ライブラリのダウンロード
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」が出力されることを確認。