top / index / prev / next / target / source

2005-08-02 diary: うそSOAPサーバ・サーブレット実現性の模索

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

old-v2

うそSOAPサーバ・サーブレット実現性の模索

うそSOAPサーバ版が技術的に実現可能かどうか簡単に検証しました。

うそSOAPサーバ・サーブレット実現性の模索

Apache Axis 1.2.1 ベースで うそSOAPの可能性を探ってみました。Tomcat 4.1も利用しています。

とりあえず jwsベースで Webサービスを作成して Axisに食わしてみます。 WsTest01.jws

public class WsTest01 {
    public String method01(String arg1, int arg2) {
        return "戻り値:[" + arg1 + ", " + arg2 + "]";
    }
}

WsTest01.jwsをベースに Axisが生成する WSDLは 下記になります。 http://localhost:8080/axis/WsTest01.jws?wsdl

<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions targetNamespace="http://localhost:8080/axis/WsTest01.jws" 
 xmlns:apachesoap="http://xml.apache.org/xml-soap" 
 xmlns:impl="http://localhost:8080/axis/WsTest01.jws" 
 xmlns:intf="http://localhost:8080/axis/WsTest01.jws"
 xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"><!--WSDLはApache Axis version: 1.2.1
Built on Jun 14, 2005 (09:15:57 EDT)によって生成されました / [en]-(WSDL created by Apache Axis version: 1.2.1
Built on Jun 14, 2005 (09:15:57 EDT))-->
   <wsdl:message name="method01Request">
      <wsdl:part name="arg1" type="xsd:string"/>
      <wsdl:part name="arg2" type="xsd:int"/>
   </wsdl:message>
   <wsdl:message name="method01Response">
      <wsdl:part name="method01Return" type="xsd:string"/>
   </wsdl:message>
   <wsdl:portType name="WsTest01">
      <wsdl:operation name="method01" parameterOrder="arg1 arg2">
         <wsdl:input message="impl:method01Request" name="method01Request"/>
         <wsdl:output message="impl:method01Response" name="method01Response"/>
      </wsdl:operation>
   </wsdl:portType>
   <wsdl:binding name="WsTest01SoapBinding" type="impl:WsTest01">
      <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name="method01">
         <wsdlsoap:operation soapAction=""/>
         <wsdl:input name="method01Request">
            <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                namespace="http://DefaultNamespace" use="encoded"/>
         </wsdl:input>
         <wsdl:output name="method01Response">
            <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                namespace="http://localhost:8080/axis/WsTest01.jws" use="encoded"/>
         </wsdl:output>
      </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name="WsTest01Service">
      <wsdl:port binding="impl:WsTest01SoapBinding" name="WsTest01">
         <wsdlsoap:address location="http://localhost:8080/axis/WsTest01.jws"/>
      </wsdl:port>
   </wsdl:service></wsdl:definitions>

※不要な改行を除去するなど、多少デフォルメしています。※WsTest01.jws.wsdl としてファイルを保存します。 WSDL2Javaを実行して Javaソースコードを生成します。 コマンドライン java -classpath axis.jar;commons-logging-1.0.4.jar;commons-discovery-0.2.jar;jaxrpc.jar;saaj.jar;wsdl4j-1.5.1.jar org.apache.axis.wsdl.WSDL2Java -t -s WsTest01.jws.wsdl

呼び出し側の SOAPを利用するクライアントは下記のようになります。 TestCaller.java

import java.rmi.RemoteException;

import javax.xml.rpc.ServiceException;

import localhost.axis.WsTest01_jws.WsTest01;
import localhost.axis.WsTest01_jws.WsTest01ServiceLocator;

public class TestCaller {

    public static void main(String[] args) {
        try {
            WsTest01 test = new WsTest01ServiceLocator().getWsTest01();
            String result = test.method01("こんにちは", 123);
            System.out.println(result);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (ServiceException e) {
            e.printStackTrace();
        }
    }
}

ここで、SOAPを うそSOAP (USOAP)サーバ・サーブレットに取り替えます。 UsoapServlet.java

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

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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

    /**
     * <code>ENCODING</code> 文字コードを与えます。
     */
    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 {

        BufferedReader reader = null;
        PrintWriter writer = null;
        setResponseDefault(response);

        try {
            reader = request.getReader();
            writer = response.getWriter();

            for (Enumeration enum = request.getHeaderNames(); enum
                    .hasMoreElements();) {
                String key = (String) enum.nextElement();
                System.out.println("H:" + key + "=" + request.getHeader(key)
                        + "");
            }

            for (;;) {
                String line = reader.readLine();
                if (line == null) {
                    break;
                }
                System.out.println("REQ:" + line);
            }
            String result = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
                    + "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\""
                    + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""
                    + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
                    + "  <soapenv:Body>"
                    + "    <ns1:method01Response"
                    + "     soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\""
                    + "     xmlns:ns1=\"http://DefaultNamespace\">"
                    + "      <method01Return xsi:type=\"xsd:string\">"
                    + "&#x623B;&#x308A;&#x5024;:[&#x3053;&#x3093;&#x306B;&#x3061;&#x306F;, 123]"
                    + "</method01Return>"
                    + "    </ns1:method01Response>" + "  </soapenv:Body>"
                    + "</soapenv:Envelope>";
            writer.write(result);
        } finally {
            // ReaderもWriterもクローズしません。flushも呼び出してはなりません。(2005.03.13に判明)
        }
    }

    /**
     * デフォルトとなるレスポンスヘッダーの付与
     * 
     * @param response
     *            レスポンスオブジェクトを与えます。
     */
    private void setResponseDefault(final HttpServletResponse response) {
        response.setContentType("text/html; 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");
    }
}

電文をシュミレートするために、うそSOAPクライアントの活用は有益です。 HttpCaller.java

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

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;

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

    private static void callMethod(boolean isSysout) {
        HttpClient client = new HttpClient();
        client.getHostConfiguration().setHost("localhost", 8080, "http");

        //PostMethod method = new PostMethod("/examples/KantanHelloServlet");
        PostMethod method = new PostMethod("/axis/WsTest01.jws");

        String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                + "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\""
                + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""
                + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
                + "  <soapenv:Body>"
                + "    <ns1:method01 soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\""
                + " xmlns:ns1=\"http://DefaultNamespace\">"
                + "      <arg1 xsi:type=\"xsd:string\">&#x3053;&#x3093;&#x306B;&#x3061;&#x306F;</arg1>"
                + "      <arg2 href=\"#id0\"/>"
                + "    </ns1:method01>"
                + "    <multiRef id=\"id0\" soapenc:root=\"0\""
                + " soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\""
                + " xsi:type=\"xsd:int\""
                + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">123</multiRef>"
                + "  </soapenv:Body>" + "</soapenv:Envelope>";
        byte[] requestBytes = null;
        try {
            requestBytes = request.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e1) {
            // TODO 自動生成された catch ブロック
            e1.printStackTrace();
        }
        method.addRequestHeader("content-type", "text/xml; charset=utf-8");
        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);
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    method.getResponseBodyAsStream()));
            for (;;) {
                String readLine = reader.readLine();
                if (readLine == null) {
                    break;
                }
                System.out.println(readLine);
            }
            reader.close();
        } catch (HttpException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        method.releaseConnection();
    }

    public static void main(String[] args) {
        callMethod(true);
    }
}

※Jakarta Commons HttpClient 2.0.2で動作確認を取りました。 とりあえず文字列エンコードがもっとも くせがありそうです。

関連する日記

エンコーディングなどを調査

文字列エンコードが納得いかないので、WSDLを少し変更してみつつあります。

登り電文の例 登り電文の例

H:content-type=text/xml; charset=utf-8
H:accept=application/soap+xml, application/dime, multipart/related, text/*
H:user-agent=Axis/1.2.1
H:host=localhost:8080
H:cache-control=no-cache
H:pragma=no-cache
H:soapaction=""
H:content-length=401<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope
 xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <method01 xmlns="http://DefaultNamespace">
      <arg1 xmlns="">&#x3053;&#x3093;&#x306B;&#x3061;&#x306F;</arg1>
      <arg2 xmlns="">123</arg2>
    </method01>
  </soapenv:Body></soapenv:Envelope>

うそSOAPサーバ・サーブレットも改良します。 UsoapServlet.java v2

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

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * うそSOAPサーブレット ソースコード
 * 
 * @author iga
 * @version 2005.08.02
 */
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 {

        BufferedReader reader = null;
        PrintWriter writer = null;
        setResponseDefault(response);

        try {
            reader = request.getReader();
            writer = response.getWriter();

            for (Enumeration enum = request.getHeaderNames(); enum
                    .hasMoreElements();) {
                String key = (String) enum.nextElement();
                System.out.println("H:" + key + "=" + request.getHeader(key)
                        + "");
            }

            for (;;) {
                String line = reader.readLine();
                if (line == null) {
                    break;
                }
                System.out.println("REQ:" + line);
            }
            String result = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
                    + "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\""
                    + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""
                    + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
                    + "  <soapenv:Body>"
                    + "    <ns1:method01Response"
                    + "     xmlns:ns1=\"http://DefaultNamespace\">"
                    + "      <method01Return xsi:type=\"xsd:string\">こんにちはSOAP</method01Return>"
                    + "    </ns1:method01Response>" + "  </soapenv:Body>"
                    + "</soapenv:Envelope>";
            writer.write(result);
        } finally {
            // ReaderもWriterもクローズしません。flushも呼び出してはなりません。(2005.03.13に判明)
        }
    }

    /**
     * デフォルトとなるレスポンスヘッダーの付与
     * 
     * @param response
     *            レスポンスオブジェクトを与えます。
     */
    private void setResponseDefault(final HttpServletResponse response) {
        response.setContentType("text/html; 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");
    }
}

これに呼応する形で、うそSOAPクライアントも変更します。 HttpCaller.java 改造版

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

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;

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

    private static void callMethod(boolean isSysout) {
        HttpClient client = new HttpClient();
        client.getHostConfiguration().setHost("localhost", 8080, "http");

        //PostMethod method = new PostMethod("/examples/KantanHelloServlet");
        PostMethod method = new PostMethod("/axis/WsTest01.jws");

        String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                + "<soapenv:Envelope"
                + " xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\""
                + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""
                + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
                + "  <soapenv:Body>"
                + "    <method01 xmlns=\"http://DefaultNamespace\">"
                + "      <arg1 xmlns=\"\">こんにちは</arg1>"
                + "      <arg2 xmlns=\"\">123</arg2>" + "    </method01>"
                + "  </soapenv:Body>" + "</soapenv:Envelope>";
        byte[] requestBytes = null;
        try {
            requestBytes = request.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e1) {
            // TODO 自動生成された catch ブロック
            e1.printStackTrace();
        }
        method.addRequestHeader("content-type", "text/xml; charset=utf-8");
        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);
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    method.getResponseBodyAsStream()));
            for (;;) {
                String readLine = reader.readLine();
                if (readLine == null) {
                    break;
                }
                System.out.println(readLine);
            }
            reader.close();
        } catch (HttpException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        method.releaseConnection();
    }

    public static void main(String[] args) {
        callMethod(true);
    }
}

とりあえず、文字列エンコーディングは 利用しないように変更することができました。

関連する日記

世間のニュースから


この日記について