top / index / prev / next / target / source

2005-08-11 diary: うそSOAP その3 → SAX2ベースによるSOAPキャプチャおよびその再生

いがぴょん画像(小) 日記形式でつづる いがぴょんコラム ウェブページです。

old-v2

うそSOAP その3 → SAX2ベースによるSOAPキャプチャおよびその再生

うそSOAPを ほんのりと抽象化しました。 , これにより SAX2ベースによるSOAP電文のキャプチャおよび再生が可能になります。

うそSOAP その3 → SAX2ベースによるSOAPキャプチャおよび再生

うそSOAPから ほんのりと抽象的な部分を抽出しました。

BlancoReverseContentHandler.java
/*
 * blancoCommons Copyright (C) 2005 Tosiki Iga
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 */

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;

/**
 * SAXイベントを入力に あべこべにそれを出力するソースコードを生成します。 <br>
 * とっても不思議なSAX2コンテントハンドラです。 <br>
 * 2005.08.11 Tosiki Iga 新規作成
 * 
 * @author Tosiki Iga
 */
public class BlancoReverseContentHandler extends BufferedWriter implements
        ContentHandler {
    /**
     * リバースコンテントハンドラのインスタンスを生成します。
     * 
     * @param writer
     *            リバース結果のソースコードの出力先
     */
    public BlancoReverseContentHandler(Writer writer) {
        super(writer);
    }

    public void setDocumentLocator(Locator arg0) {
        // ドキュメントロケータは無視します。
    }

    public void startDocument() throws SAXException {
        try {
            write("TransformerFactory tf = TransformerFactory.newInstance();");
            newLine();
            write("SAXTransformerFactory saxTf = (SAXTransformerFactory) tf;");
            newLine();
            write("TransformerHandler handler = saxTf.newTransformerHandler();");
            newLine();
            write("handler.setResult(new StreamResult(response.getOutputStream()));");
            newLine();
            write("handler.startDocument();");
            newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void endDocument() throws SAXException {
        try {
            write("handler.endDocument();");
            newLine();
            flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void startPrefixMapping(String arg0, String arg1)
            throws SAXException {
        try {
            write("handler.startPrefixMapping(\"" + arg0 + "\", \"" + arg1
                    + "\");");
            newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void endPrefixMapping(String arg0) throws SAXException {
        try {
            write("handler.endPrefixMapping(\"" + arg0 + "\");");
            newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 最初のエレメントかどうかを判断します。
     */
    private boolean isFirstAttributes = true;

    public void startElement(String uri, String localname, String qname,
            Attributes attributes) throws SAXException {
        try {
            if (isFirstAttributes) {
                isFirstAttributes = false;
                write("AttributesImpl attributes = new AttributesImpl();");
                newLine();
            } else {
                write("attributes = new AttributesImpl();");
                newLine();
            }
            for (int index = 0; index < attributes.getLength(); index++) {
                write("attributes.addAttribute(\"" + attributes.getURI(index)
                        + "\", \"" + attributes.getLocalName(index) + "\", \""
                        + attributes.getQName(index) + "\", \""
                        + attributes.getType(index) + "\", \""
                        + attributes.getValue(index) + "\");");
                newLine();
            }
            write("handler.startElement(\"" + uri + "\", \"" + localname
                    + "\", \"" + qname + "\", attributes);");
            newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void endElement(String arg0, String arg1, String arg2)
            throws SAXException {
        try {
            write("handler.endElement(\"" + arg0 + "\", \"" + arg1 + "\", \""
                    + arg2 + "\");");
            newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
        try {
            // 第二引数に0をセットしている点に注意!
            write("handler.characters(\"" + new String(arg0, arg1, arg2)
                    + "\".toCharArray(), 0, " + arg2 + ");");
            newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void ignorableWhitespace(char[] arg0, int arg1, int arg2)
            throws SAXException {
        try {
            write("handler.ignorableWhitespace(\""
                    + new String(arg0, arg1, arg2) + "\".toCharArray(), 0, "
                    + arg2 + ");");
            newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void processingInstruction(String arg0, String arg1)
            throws SAXException {
        try {
            write("handler.processingInstruction(\"" + arg0 + "\", \"" + arg1
                    + "\");");
            newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void skippedEntity(String arg0) throws SAXException {
        try {
            write("handler.skippedEntity(\"" + arg0 + "\");");
            newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static final Transformer getTransformer()
            throws TransformerFactoryConfigurationError,
            TransformerConfigurationException {
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        transformer.setOutputProperty("encoding", "UTF-8");
        transformer.setOutputProperty("standalone", "yes");
        transformer.setOutputProperty("indent", "yes");
        return transformer;
    }
}

※このファイルの継続的な維持については blancoCommonsの中において行われていくことでしょう。※さしあたり、例外をSAXExceptionに詰め替えが必要でしょう。その上で うそSOAPでは Faultを適切に扱うべきです。 この場合のキャプチャをおこなうべく まず うそSOAPサーバを起動してキャプチャします。

UsoapServlet.java
/*
 * うそSOAPサーブレット構築計画
 * Copyright (C) 2005 いがぴょん
 */

import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

/**
 * うそSOAPサーブレット ソースコード
 * 
 * @author iga
 * @version 2005.08.11
 */
public class UsoapServlet extends HttpServlet {

    /**
     * <code>ENCODING</code> HTMLで扱う文字コードを与えます。
     */
    public static final String ENCODING = "UTF-8";

    /**
     * Java Servletのエントリポイントです。
     * 
     * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest,
     *      javax.servlet.http.HttpServletResponse)
     */
    public final void service(final HttpServletRequest request,
            final HttpServletResponse response) throws ServletException,
            IOException {

        setResponseDefault(response);

        try {
            try {
                recvRequest(request);
            } catch (TransformerException e1) {
                e1.printStackTrace();
            } catch (TransformerFactoryConfigurationError e1) {
                e1.printStackTrace();
            }

            try {
                sendResponse(response);
            } catch (TransformerConfigurationException e) {
                e.printStackTrace();
            } catch (TransformerFactoryConfigurationError e) {
                e.printStackTrace();
            } catch (SAXException e) {
                e.printStackTrace();
            }
        } finally {
            // ReaderもWriterもクローズしません。flushも呼び出してはなりません。(2005.03.13に判明)
        }
    }

    /**
     * リクエストをファイルに出力します。
     * 
     * @param request
     * @throws IOException
     * @throws FileNotFoundException
     * @throws TransformerException
     * @throws TransformerFactoryConfigurationError
     * @throws TransformerConfigurationException
     */
    private void recvRequest(final HttpServletRequest request)
            throws IOException, FileNotFoundException, TransformerException,
            TransformerFactoryConfigurationError,
            TransformerConfigurationException {
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream("UsoapServletRequest.txt", true)));

        writer.write("HttpClient client = new HttpClient();");
        writer.newLine();
        writer
                .write("client.getHostConfiguration().setHost(\"localhost\", 8080, \"http\");");

        writer.newLine();
        writer
                .write("PostMethod method = new PostMethod(\"/axis/WsTest02.jws\");");
        writer.newLine();

        for (Enumeration enum = request.getHeaderNames(); enum
                .hasMoreElements();) {
            String key = (String) enum.nextElement();

            writer.write("method.addRequestHeader(\"" + key + "\", \""
                    + request.getHeader(key) + "\");");
            writer.newLine();
        }
        writer.newLine();

        SAXSource source = new SAXSource();
        source.setInputSource(new InputSource(request.getInputStream()));
        SAXResult result = new SAXResult();
        result.setHandler(new BlancoReverseContentHandler(writer));
        BlancoReverseContentHandler.getTransformer().transform(source, result);
        writer.newLine();
        writer.flush();
        writer.close();
    }

    /**
     * レスポンスを送信します。 <br>
     * ※注意: ここには うそSOAPのキャプチャ結果ソースコードをそのまま貼り付けます。
     * 
     * @param response
     * @throws TransformerFactoryConfigurationError
     * @throws TransformerConfigurationException
     * @throws IOException
     * @throws SAXException
     */
    private void sendResponse(final HttpServletResponse response)
            throws TransformerFactoryConfigurationError,
            TransformerConfigurationException, IOException, SAXException {

        // ここからはリバースSAXの出力結果。人手で書いたものではありません。
        TransformerFactory tf = TransformerFactory.newInstance();
        SAXTransformerFactory saxTf = (SAXTransformerFactory) tf;
        TransformerHandler handler = saxTf.newTransformerHandler();
        handler.setResult(new StreamResult(response.getOutputStream()));
        handler.startDocument();
        handler.startPrefixMapping("soapenv",
                "http://schemas.xmlsoap.org/soap/envelope/");
        handler.startPrefixMapping("xsd", "http://www.w3.org/2001/XMLSchema");
        handler.startPrefixMapping("xsi",
                "http://www.w3.org/2001/XMLSchema-instance");
        AttributesImpl attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "soapenv",
                "xmlns:soapenv", "CDATA",
                "http://schemas.xmlsoap.org/soap/envelope/");
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "xsd",
                "xmlns:xsd", "CDATA", "http://www.w3.org/2001/XMLSchema");
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "xsi",
                "xmlns:xsi", "CDATA",
                "http://www.w3.org/2001/XMLSchema-instance");
        handler.startElement("http://schemas.xmlsoap.org/soap/envelope/",
                "Envelope", "soapenv:Envelope", attributes);
        attributes = new AttributesImpl();
        handler.startElement("http://schemas.xmlsoap.org/soap/envelope/",
                "Body", "soapenv:Body", attributes);
        handler.startPrefixMapping("ns1", "http://MyNamespace");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "ns1",
                "xmlns:ns1", "CDATA", "http://MyNamespace");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/envelope/",
                "encodingStyle", "soapenv:encodingStyle", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        handler.startElement("http://MyNamespace", "method02Response",
                "ns1:method02Response", attributes);
        handler.startPrefixMapping("soapenc",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "soapenc",
                "xmlns:soapenc", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/encoding/",
                "arrayType", "soapenc:arrayType", "CDATA", "xsd:anyType[2]");
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "soapenc:Array");
        handler
                .startElement("", "method02Return", "method02Return",
                        attributes);
        attributes = new AttributesImpl();
        attributes.addAttribute("", "href", "href", "CDATA", "#id0");
        handler
                .startElement("", "method02Return", "method02Return",
                        attributes);
        handler.endElement("", "method02Return", "method02Return");
        attributes = new AttributesImpl();
        attributes.addAttribute("", "href", "href", "CDATA", "#id1");
        handler
                .startElement("", "method02Return", "method02Return",
                        attributes);
        handler.endElement("", "method02Return", "method02Return");
        handler.endElement("", "method02Return", "method02Return");
        handler.endPrefixMapping("soapenc");
        handler.endElement("http://MyNamespace", "method02Response",
                "ns1:method02Response");
        handler.endPrefixMapping("ns1");
        handler.startPrefixMapping("soapenc",
                "http://schemas.xmlsoap.org/soap/encoding/");
        handler.startPrefixMapping("ns2", "http://MyNamespace");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "soapenc",
                "xmlns:soapenc", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "ns2",
                "xmlns:ns2", "CDATA", "http://MyNamespace");
        attributes.addAttribute("", "id", "id", "CDATA", "id0");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/encoding/",
                "root", "soapenc:root", "CDATA", "0");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/envelope/",
                "encodingStyle", "soapenv:encodingStyle", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "ns2:WsTestOutput");
        handler.startElement("", "multiRef", "multiRef", attributes);
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "xsd:int");
        handler.startElement("", "arg3", "arg3", attributes);
        handler.characters("0".toCharArray(), 0, 1);
        handler.endElement("", "arg3", "arg3");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "xsd:string");
        handler.startElement("", "arg4", "arg4", attributes);
        handler.characters("は".toCharArray(), 0, 1);
        handler.characters("ろ".toCharArray(), 0, 1);
        handler.characters("う".toCharArray(), 0, 1);
        handler.endElement("", "arg4", "arg4");
        handler.endElement("", "multiRef", "multiRef");
        handler.endPrefixMapping("ns2");
        handler.endPrefixMapping("soapenc");
        handler.startPrefixMapping("ns3", "http://MyNamespace");
        handler.startPrefixMapping("soapenc",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "ns3",
                "xmlns:ns3", "CDATA", "http://MyNamespace");
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "soapenc",
                "xmlns:soapenc", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes.addAttribute("", "id", "id", "CDATA", "id1");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/encoding/",
                "root", "soapenc:root", "CDATA", "0");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/envelope/",
                "encodingStyle", "soapenv:encodingStyle", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "ns3:WsTestOutput");
        handler.startElement("", "multiRef", "multiRef", attributes);
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "xsd:int");
        handler.startElement("", "arg3", "arg3", attributes);
        handler.characters("0".toCharArray(), 0, 1);
        handler.endElement("", "arg3", "arg3");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "xsd:string");
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "nil", "xsi:nil", "CDATA", "true");
        handler.startElement("", "arg4", "arg4", attributes);
        handler.endElement("", "arg4", "arg4");
        handler.endElement("", "multiRef", "multiRef");
        handler.endPrefixMapping("soapenc");
        handler.endPrefixMapping("ns3");
        handler.endElement("http://schemas.xmlsoap.org/soap/envelope/", "Body",
                "soapenv:Body");
        handler.endElement("http://schemas.xmlsoap.org/soap/envelope/",
                "Envelope", "soapenv:Envelope");
        handler.endPrefixMapping("xsi");
        handler.endPrefixMapping("xsd");
        handler.endPrefixMapping("soapenv");
        handler.endDocument();
    }

    /**
     * デフォルトとなるレスポンスヘッダーの付与
     * 
     * @param response
     *            レスポンスオブジェクトを与えます。
     */
    private void setResponseDefault(final HttpServletResponse response) {
        response.setContentType("text/xml; charset=" + ENCODING);
        response.addHeader("Content-Type", "text/xml");
        response.addHeader("charset", ENCODING);
        response.addHeader("Cache-Control", "no-cache");
        response.addHeader("Pragma", "no-cache");
        response.addHeader("Expires", "0");
    }
}

※このサーブレットは 「ルート」に作業ファイルを作成してしまいます。実行の前に それが許される環境であるかどうかについて、よく考えてください。 サーバ側でキャプチャできれば、今度はクライアント側にキャプチャ結果を貼り付けて、サーバ側の挙動をキャプチャすることが出来ます。

ここからはクライアント側のコードです。

HttpCaller.java
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

public class HttpCaller {
    private static final int COUNT = 100;

    private void callMethod() {
        HttpClient client = new HttpClient();
        client.getHostConfiguration().setHost("localhost", 8080, "http");
        PostMethod method = new PostMethod("/axis/WsTest02.jws");
        method.addRequestHeader("content-type", "text/xml; charset=utf-8");

        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        try {
            buildRequest(outStream);
        } catch (TransformerConfigurationException e1) {
            e1.printStackTrace();
        } catch (TransformerFactoryConfigurationError e1) {
            e1.printStackTrace();
        } catch (SAXException e1) {
            e1.printStackTrace();
        }

        byte[] requestBytes = outStream.toByteArray();
        method
                .addRequestHeader("accept",
                        "application/soap+xml, application/dime, multipart/related, text/*");
        method.addRequestHeader("user-agent", "Usoap/1.2.1");
        method.addRequestHeader("host", "localhost:8080");
        method.addRequestHeader("cache-control", "no-cache");
        method.addRequestHeader("pragma", "no-cache");
        method.addRequestHeader("soapaction", "\"\"");
        method.addRequestHeader("content-length", String
                .valueOf(requestBytes.length));

        method.setRequestBody(new ByteArrayInputStream(requestBytes));
        try {
            client.executeMethod(method);

            try {
                SAXSource source = new SAXSource();
                source.setInputSource(new InputSource(method
                        .getResponseBodyAsStream()));
                SAXResult result = new SAXResult();
                result.setHandler(new BlancoReverseContentHandler(
                        new OutputStreamWriter(new FileOutputStream(
                                "HttpCallerResponse.txt"))));
                BlancoReverseContentHandler.getTransformer().transform(source,
                        result);
            } catch (TransformerConfigurationException e2) {
                e2.printStackTrace();
            } catch (TransformerException e2) {
                e2.printStackTrace();
            } catch (TransformerFactoryConfigurationError e2) {
                e2.printStackTrace();
            }
        } catch (HttpException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        method.releaseConnection();
    }

    /**
     * 送信電文を組み立てます。
     * 
     * @param outStream
     * @throws TransformerFactoryConfigurationError
     * @throws TransformerConfigurationException
     * @throws SAXException
     */
    private void buildRequest(ByteArrayOutputStream outStream)
            throws TransformerFactoryConfigurationError,
            TransformerConfigurationException, SAXException {

        TransformerFactory tf = TransformerFactory.newInstance();
        SAXTransformerFactory saxTf = (SAXTransformerFactory) tf;
        TransformerHandler handler = saxTf.newTransformerHandler();
        handler.setResult(new StreamResult(outStream));
        handler.startDocument();
        handler.startPrefixMapping("soapenv",
                "http://schemas.xmlsoap.org/soap/envelope/");
        handler.startPrefixMapping("xsd", "http://www.w3.org/2001/XMLSchema");
        handler.startPrefixMapping("xsi",
                "http://www.w3.org/2001/XMLSchema-instance");
        AttributesImpl attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "soapenv",
                "xmlns:soapenv", "CDATA",
                "http://schemas.xmlsoap.org/soap/envelope/");
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "xsd",
                "xmlns:xsd", "CDATA", "http://www.w3.org/2001/XMLSchema");
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "xsi",
                "xmlns:xsi", "CDATA",
                "http://www.w3.org/2001/XMLSchema-instance");
        handler.startElement("http://schemas.xmlsoap.org/soap/envelope/",
                "Envelope", "soapenv:Envelope", attributes);
        attributes = new AttributesImpl();
        handler.startElement("http://schemas.xmlsoap.org/soap/envelope/",
                "Body", "soapenv:Body", attributes);
        handler.startPrefixMapping("ns1", "http://MyNamespace");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "ns1",
                "xmlns:ns1", "CDATA", "http://MyNamespace");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/envelope/",
                "encodingStyle", "soapenv:encodingStyle", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        handler.startElement("http://MyNamespace", "method02", "ns1:method02",
                attributes);
        handler.startPrefixMapping("soapenc",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "soapenc",
                "xmlns:soapenc", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes
                .addAttribute("http://schemas.xmlsoap.org/soap/encoding/",
                        "arrayType", "soapenc:arrayType", "CDATA",
                        "ns1:WsTestInput[2]");
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "soapenc:Array");
        handler.startElement("", "input", "input", attributes);
        attributes = new AttributesImpl();
        attributes.addAttribute("", "href", "href", "CDATA", "#id0");
        handler.startElement("", "input", "input", attributes);
        handler.endElement("", "input", "input");
        attributes = new AttributesImpl();
        attributes.addAttribute("", "href", "href", "CDATA", "#id1");
        handler.startElement("", "input", "input", attributes);
        handler.endElement("", "input", "input");
        handler.endElement("", "input", "input");
        handler.endPrefixMapping("soapenc");
        handler.endElement("http://MyNamespace", "method02", "ns1:method02");
        handler.endPrefixMapping("ns1");
        handler.startPrefixMapping("soapenc",
                "http://schemas.xmlsoap.org/soap/encoding/");
        handler.startPrefixMapping("ns2", "http://MyNamespace");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "soapenc",
                "xmlns:soapenc", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "ns2",
                "xmlns:ns2", "CDATA", "http://MyNamespace");
        attributes.addAttribute("", "id", "id", "CDATA", "id1");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/encoding/",
                "root", "soapenc:root", "CDATA", "0");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/envelope/",
                "encodingStyle", "soapenv:encodingStyle", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "ns2:WsTestInput");
        handler.startElement("", "multiRef", "multiRef", attributes);
        attributes = new AttributesImpl();
        attributes.addAttribute("", "href", "href", "CDATA", "#id2");
        handler.startElement("", "arg1", "arg1", attributes);
        handler.endElement("", "arg1", "arg1");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "xsd:string");
        handler.startElement("", "arg2", "arg2", attributes);
        handler.characters("abc".toCharArray(), 0, 3);
        handler.endElement("", "arg2", "arg2");
        handler.endElement("", "multiRef", "multiRef");
        handler.endPrefixMapping("ns2");
        handler.endPrefixMapping("soapenc");
        handler.startPrefixMapping("ns3", "http://MyNamespace");
        handler.startPrefixMapping("soapenc",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "ns3",
                "xmlns:ns3", "CDATA", "http://MyNamespace");
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "soapenc",
                "xmlns:soapenc", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes.addAttribute("", "id", "id", "CDATA", "id0");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/encoding/",
                "root", "soapenc:root", "CDATA", "0");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/envelope/",
                "encodingStyle", "soapenv:encodingStyle", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "ns3:WsTestInput");
        handler.startElement("", "multiRef", "multiRef", attributes);
        attributes = new AttributesImpl();
        attributes.addAttribute("", "href", "href", "CDATA", "#id3");
        handler.startElement("", "arg1", "arg1", attributes);
        handler.endElement("", "arg1", "arg1");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "xsd:string");
        handler.startElement("", "arg2", "arg2", attributes);
        handler.characters("abc".toCharArray(), 0, 3);
        handler.endElement("", "arg2", "arg2");
        handler.endElement("", "multiRef", "multiRef");
        handler.endPrefixMapping("soapenc");
        handler.endPrefixMapping("ns3");
        handler.startPrefixMapping("soapenc",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "soapenc",
                "xmlns:soapenc", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes.addAttribute("", "id", "id", "CDATA", "id2");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/encoding/",
                "root", "soapenc:root", "CDATA", "0");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/envelope/",
                "encodingStyle", "soapenv:encodingStyle", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "xsd:int");
        handler.startElement("", "multiRef", "multiRef", attributes);
        handler.characters("3".toCharArray(), 0, 1);
        handler.endElement("", "multiRef", "multiRef");
        handler.endPrefixMapping("soapenc");
        handler.startPrefixMapping("soapenc",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes = new AttributesImpl();
        attributes.addAttribute("http://www.w3.org/2000/xmlns/", "soapenc",
                "xmlns:soapenc", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes.addAttribute("", "id", "id", "CDATA", "id3");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/encoding/",
                "root", "soapenc:root", "CDATA", "0");
        attributes.addAttribute("http://schemas.xmlsoap.org/soap/envelope/",
                "encodingStyle", "soapenv:encodingStyle", "CDATA",
                "http://schemas.xmlsoap.org/soap/encoding/");
        attributes.addAttribute("http://www.w3.org/2001/XMLSchema-instance",
                "type", "xsi:type", "CDATA", "xsd:int");
        handler.startElement("", "multiRef", "multiRef", attributes);
        handler.characters("3".toCharArray(), 0, 1);
        handler.endElement("", "multiRef", "multiRef");
        handler.endPrefixMapping("soapenc");
        handler.endElement("http://schemas.xmlsoap.org/soap/envelope/", "Body",
                "soapenv:Body");
        handler.endElement("http://schemas.xmlsoap.org/soap/envelope/",
                "Envelope", "soapenv:Envelope");
        handler.endPrefixMapping("xsi");
        handler.endPrefixMapping("xsd");
        handler.endPrefixMapping("soapenv");
        handler.endDocument();
    }

    public static void main(String[] args) {
        new HttpCaller().callMethod();
    }
}

href/multiRef解析コード例

multiRef対応の解析コードの例を示します。 SAX2はコールバックなので、いろいろ応用が利いて便利ですね。

SAX2インラインクラスベースによるhrefおよびmultiRefの解析コード
        SAXSource source = new SAXSource();
        source.setInputSource(new InputSource(request.getInputStream()));
        SAXResult result = new SAXResult();
        result.setHandler(new ContentHandler() {
            /**
             * カレントのタグ
             */
            private String currentTag = "";

            /**
             * テキストの記憶領域。「タグ : テキスト」の組み合わせで記憶していきます。
             */
            private Hashtable hashTagText = new Hashtable();

            /**
             * href/multiRefの記憶領域。「id: タグ」の組み合わせで記憶していきます。
             */
            private Hashtable hashHref = new Hashtable();

            /**
             * カレントの multiRefを記憶します。
             */
            private Stack currentMultiRef = new Stack();

            public void setDocumentLocator(Locator arg0) {
            }

            public void startDocument() throws SAXException {
                System.out.println("開始します.");
            }

            public void endDocument() throws SAXException {
                // TODO:ここで何かしらの終了処理を行います。
            }

            public void startPrefixMapping(String arg0, String arg1)
                    throws SAXException {
            }

            public void endPrefixMapping(String arg0) throws SAXException {
            }

            public void startElement(String arg0, String arg1, String arg2,
                    Attributes attributes) throws SAXException {

                // カレントのタグを記憶します。
                currentTag = arg2;

                if (hashTagText.get(currentTag) == null) {
                    // もしタグがない場合には新規作成します。
                    hashTagText.put(currentTag, new CharArrayWriter());
                }

                if (currentTag.equals("multiRef")) {
                    for (int index = 0; index < attributes.getLength(); index++) {
                        if (attributes.getLocalName(index).equals("id")) {
                            currentMultiRef.push(attributes.getValue(index));
                        }
                    }
                }

                for (int index = 0; index < attributes.getLength(); index++) {
                    if (attributes.getLocalName(index).equals("href")) {
                        hashHref.put(attributes.getValue(index).substring(1),
                                currentTag);
                    }
                }

            }

            public void endElement(String arg0, String arg1, String arg2)
                    throws SAXException {
                CharArrayWriter writer = null;
                String strText = null;
                if (currentTag != null && hashTagText.get(currentTag) != null) {
                    writer = (CharArrayWriter) hashTagText.get(currentTag);

                    writer.flush();
                    strText = writer.toString();
                    System.out.println(currentTag + "[" + strText + "]");
                    writer.reset();
                }

                if (currentTag.equals("multiRef")) {
                    String strCurrentMultiRef = (String) currentMultiRef.pop();
                    System.out.println("multiRef読み替え:"
                            + hashHref.get(strCurrentMultiRef) + "[" + strText
                            + "]");
                }

                // TODO:ここでタグにより分岐処理を行います。

            }

            public void characters(char[] arg0, int arg1, int arg2)
                    throws SAXException {
                if (hashTagText.get(currentTag) == null) {
                    // もしタグがない場合には新規作成します。
                    hashTagText.put(currentTag, new CharArrayWriter());
                }

                ((CharArrayWriter) hashTagText.get(currentTag)).write(arg0,
                        arg1, arg2);
            }

            public void ignorableWhitespace(char[] arg0, int arg1, int arg2)
                    throws SAXException {
            }

            public void processingInstruction(String arg0, String arg1)
                    throws SAXException {
            }

            public void skippedEntity(String arg0) throws SAXException {
            }
        });

        BlancoReverseContentHandler.getTransformer().transform(source, result);

※ほんとうはタグについてもスタック対応すべきなのでしょう。※SOAP 1.2では hrefは名称が enc:refに変更されています。SOAP 1.2では IDREFなどの用語も登場します。 低速な箇所の高速化のために、上記技法が有益であることはわかったのですが、対応実施までは至らず。残念。

関連する日記


この日記について