ライブラリのダウンロード
Java1.6 からは JAX-WS リファレンス実装が rt.jar に含まれたため、JRE だけで使用可能。
最新バージョンを使用したい場合はJAX-WSサイトからダウンロードできる。
Java 1.6.0_29 でバージョンを確認したところ、
System.out.println(com.sun.xml.internal.ws.util.RuntimeVersion.VERSION);
「JAX-WS RI 2.1.6 in JDK 6」だった。
本日時点でダウンロードできる最新は2.2.5。
スタブを使用して Web サービス実行
JAX-WSサイトからダウンロードした場合には、jaxws-ri/bin/wsimport.(bat|sh) を、
Java 標準のものを使用する場合には $JAVA_HOME/bin/wsimport(.exe) を使用する。
実行すると Java ソースファイルの生成、コンパイル、ソースファイルの削除まで行い、最終的にクラスファイルだけ生成される。
ソースファイルも残したい場合は -keep オプションを指定する。
wsimport.exe -keep http://localhost:49175/WS/ZaneliWS.asmx?WSDL
以下の 6 クラスが自動生成される。
  • com.zaneli.GetMessage
  • com.zaneli.GetMessageResponse
  • com.zaneli.ObjectFactory
  • com.zaneli.package-info
  • com.zaneli.ZaneliWS
  • com.zaneli.ZaneliWSSoap
実行は以下の通り。
import com.zaneli.ZaneliWS;
import com.zaneli.ZaneliWSSoap;

public class JaxWSExecutor1 {

 public String execute(String text, int num) {
  ZaneliWS ws = new ZaneliWS();
  ZaneliWSSoap soap = ws.getZaneliWSSoap();
  return soap.getMessage(text, num);
 }

 public static void main(String[] args) {
  System.out.println(new JaxWSExecutor1().execute("JAX-WSで実行", 111));
 }
}
「text=JAX-WSで実行, num=111」が出力されることを確認。
スタブを使用せず Web サービス実行
リクエスト・レスポンスのやり取りにSOAP ボディ以下のみを使用する(Service.Mode.PAYLOAD)か、
SOAP エンベロープ全体を使用する(Service.Mode.MESSAGE)かを指定する。
ペイロードのみをやり取りする
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class JaxWSExecutor2 {

 private static final String WSDL_URI = "http://localhost:49175/WS/ZaneliWS.asmx?WSDL";
 private static final String NAMESPACE = "http://www.zaneli.com/";
 private static final QName SERVICE_NAME = new QName(NAMESPACE, "ZaneliWS");
 private static final QName PORT_NAME = new QName(NAMESPACE, "ZaneliWSSoap");
 private static final String OPERATION_NAME = "GetMessage";
 private static final String RESPONSE_BODY_NAME = OPERATION_NAME + "Result";

 public String execute(String text, int num) throws ParserConfigurationException, SAXException, IOException, XMLStreamException, FactoryConfigurationError, TransformerException {
  URL wsdlURL = new URL(WSDL_URI);
  Service service = Service.create(wsdlURL, SERVICE_NAME);
  Dispatch<Source> disp = service.createDispatch(PORT_NAME, Source.class, Service.Mode.PAYLOAD);
  disp.getRequestContext().put(Dispatch.SOAPACTION_URI_PROPERTY, NAMESPACE + OPERATION_NAME);
  Source request = createRequestSource(text, num);
  Source response = disp.invoke(request);
  
  Transformer transformer = TransformerFactory.newInstance().newTransformer(); 
  ResponseHandler handler = new ResponseHandler();
  Result result = new SAXResult(handler);
  transformer.transform(response, result);
  return handler.getResponse();
 }

 private SAXSource createRequestSource(String text, int num) throws IOException {
  InputStream in = null;
  try {
   String reqBody =
     "<GetMessage xmlns=\"http://www.zaneli.com/\">" +
     "<text>" + text + "</text>" +
     "<num>" + num + "</num>" +
     "</GetMessage>";
   in = new ByteArrayInputStream(reqBody.getBytes("UTF-8")); 
   return new SAXSource(new InputSource(in));
  } finally {
   if (in != null) in.close();
  }
 }

 private static class ResponseHandler extends DefaultHandler {
  private boolean isGetMessageResultStarted;
  private String response;
  @Override
  public void startElement(
    String uri, String localName, String qName, Attributes attributes) throws SAXException {
   isGetMessageResultStarted = NAMESPACE.equals(uri) && RESPONSE_BODY_NAME.equals(localName);
  }
  @Override
  public void characters(char[] ch, int start, int length) throws SAXException {
   if (isGetMessageResultStarted) {
    response = new String(ch, start, length);
   }
  }
  public String getResponse() {
   return response;
  }
 }

 public static void main(String[] args) throws Exception {
  System.out.println(new JaxWSExecutor2().execute("JAX-WSで動的実行", 222));
 }
}
「text=JAX-WSで動的実行, num=222」が出力されることを確認。
メッセージ全体をやり取りする
import java.io.IOException;
import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.TransformerException;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;

import org.xml.sax.SAXException;

public class JaxWSExecutor3 {

 private static final String WSDL_URI = "http://localhost:49175/WS/ZaneliWS.asmx?WSDL";
 private static final String NAMESPACE = "http://www.zaneli.com/";
 private static final QName SERVICE_NAME = new QName(NAMESPACE, "ZaneliWS");
 private static final QName PORT_NAME = new QName(NAMESPACE, "ZaneliWSSoap");
 private static final String OPERATION_NAME = "GetMessage";

 public String execute(String text, int num) throws ParserConfigurationException, SAXException, IOException, XMLStreamException, FactoryConfigurationError, TransformerException, SOAPException {
  URL wsdlURL = new URL(WSDL_URI);
  Service service = Service.create(wsdlURL, SERVICE_NAME);
  Dispatch<SOAPMessage> disp = service.createDispatch(PORT_NAME, SOAPMessage.class, Service.Mode.MESSAGE);
  disp.getRequestContext().put(Dispatch.SOAPACTION_URI_PROPERTY, NAMESPACE + OPERATION_NAME);
  SOAPMessage request = createRequestSource(text, num);
  SOAPMessage response = disp.invoke(request);
  return response.getSOAPBody().getTextContent();
 }

 private SOAPMessage createRequestSource(String text, int num) throws IOException, SOAPException {
  SOAPMessage request = MessageFactory.newInstance().createMessage();
  SOAPBody body = request.getSOAPBody();
  SOAPBodyElement bodyElement = body.addBodyElement(new QName(NAMESPACE, OPERATION_NAME));
  SOAPElement textElem = bodyElement.addChildElement(new QName("text"));
  textElem.setTextContent(text);
  SOAPElement numElem = bodyElement.addChildElement(new QName("num"));
  numElem.setTextContent(Integer.toString(num));
  return request;
 }

 public static void main(String[] args) throws Exception {
  System.out.println(new JaxWSExecutor3().execute("JAX-WSで動的実行", 333));
 }
}
「text=JAX-WSで動的実行, num=333」が出力されることを確認。
CXF を使用する
Apache CXF を使用すると引数のみを指定して実行することもできる。
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;

public class CXFExecutor {

 private static final String WSDL_URI = "http://localhost:49175/WS/ZaneliWS.asmx?WSDL";
 private static final String OPERATION_NAME = "GetMessage";

 public String execute(String text, int num) throws Exception {
  JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
  Client client = dcf.createClient(WSDL_URI);
  Object[] result = client.invoke(OPERATION_NAME, text, num);
  if (result.length > 0 && result[0] instanceof String) {
   return (String) result[0];
  }
  throw new IllegalStateException("レスポンスが無いんです!(><;");
 }

 public static void main(String[] args) throws Exception {
  System.out.println(new CXFExecutor().execute("CXFで動的実行", 444));
 }
}
「text=CXFで動的実行, num=444」が出力されることを確認。

Copyright© 2011-2021 Shunsuke Otani All Right Reserved .