Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Page 1 of 13 569 Web Service Tutorial 1 Introduction This tutorial introduces running web services on Tomcat using Axis. The axis web site (http://ws.apache.org/axis/) is a good place to start with. You need to read the installation and users guides there. You are also assumed to know the basics of web service, such as WSDL, JAX-RPC. 2 Preparing the Environment All the examples are run on Tomcat5.5.9 and Axis1.2.1. You also need to install JDK1.5. After tomcat is installed, you should be able to see the following screen when you go to http://localhost:8080 in a browser. To install axis, simply copy axisDirectory/webapps/axis to tomcatDirectory/webapps/. If everything is correct, you will see the following screen when you go to the place http://localhost:8080/axis. Page 2 of 13 To better observe what is happening over the wire, you should run tcpmon by running the following java program: E:\tomcat\webapps\axis>java -cp %AXISCLASSPATH% org.apache.axis.utils.tcpmon You will see the following TCPMonitor screen if the program can run correctly. Here %AXISCLASSPATH% includes all the jar files under axisDirectory/lib. E:\Documents and Settings\lombardy>echo %AXISCLASSPATH% e:\axis\lib\wsdl4j.jar;e:\axis\lib\axis.jar;e:\axis\lib\commons-discovery.jar;e: \axis\lib\commons-logging.jar;e:\axis\lib\jaxrpc.jar;e:\axis\lib\saaj.jar;e:\axi s\lib\log4j-1.2.8.jar;e:\axis\lib\xml-apis.jar;e:\axis\lib\xercesImpl.jar You need to make sure that the jar file names are the same as the names in your axis directory. Different versions of Axis may include different jar file names. Page 3 of 13 3 A Simple Round of Web Service Creation and Invocation 3.1 Create a service Here are the steps to create a web service. This approach (we call it jws approach) can only create simple web services as we will explain in section 4. a. Write a Java class (Echo.java) b. Change file name Echo.java to Echo.jws c. Move the file under the directory webapps/axis Now the web service is created. If you look at the url: http://localhost:8080/axis/Echo.jws you will see a page telling you that the service exists, and if you look at http://localhost:8080/axis/Echo.jws?wsdl, you will see the wsdl file that is automatically generated by axis. I list the Echo.wsdl file below to show the correspondence between the Java class and the wsdl definition. public class Echo { public String echo(String param) { return param; Page 4 of 13 } } Echo.java <?xml version="1.0" encoding="UTF-8" ?> - <wsdl:definitions targetNamespace="http://137.207.234.183/axis/Echo.jws" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://137.207.234.183/axis/Echo.jws" xmlns:intf="http://137.207.234.183/axis/Echo.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 created by Apache Axis version: 1.2.1 Built on Jun 14, 2005 (09:15:57 EDT) --> - <wsdl:message name="echoRequest"> <wsdl:part name="param" type="xsd:string" /> </wsdl:message> - <wsdl:message name="echoResponse"> <wsdl:part name="echoReturn" type="xsd:string" /> </wsdl:message> - <wsdl:portType name="Echo"> - <wsdl:operation name="echo" parameterOrder="param"> <wsdl:input message="impl:echoRequest" name="echoRequest" /> <wsdl:output message="impl:echoResponse" name="echoResponse" /> </wsdl:operation> </wsdl:portType> - <wsdl:binding name="EchoSoapBinding" type="impl:Echo"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> - <wsdl:operation name="echo"> <wsdlsoap:operation soapAction="" /> - <wsdl:input name="echoRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded" /> </wsdl:input> - <wsdl:output name="echoResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://137.207.234.183/axis/Echo.jws" use="encoded" /> </wsdl:output> </wsdl:operation> </wsdl:binding> - <wsdl:service name="EchoService"> - <wsdl:port binding="impl:EchoSoapBinding" name="Echo"> <wsdlsoap:address location="http://137.207.234.183/axis/Echo.jws" /> </wsdl:port> </wsdl:service> </wsdl:definitions> WSDL file generated from Echo.jws 3.2 Call the service The steps to call a web service are as below: d. Write a web service client EchoJWSClient.java e. Compile and run EchoJWSClient.class Again, this is the simple way to invoke a web service. We will see there are more complicated ways to do web service invocation, especially when we need to have complex types. Page 5 of 13 import org.apache.axis.client.Call; import org.apache.axis.client.Service; import javax.xml.namespace.QName; public class EchoJWSClient{ public static void main(String [] args) throws Exception{ String endpoint = "http://localhost:8081/axis/Echo.jws"; Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName(new QName("http://soapinterop.org/", "echo") ); String ret = (String) call.invoke( new Object[] { "Hello!" } ); System.out.println("Sent 'Hello!', got '" + ret + "'"); } } EchoJWSClient.java When you run the program, you will see the following SOAP request and response. POST /axis/Echo.jws HTTP/1.0 Content-Type: text/xml; charset=utf-8 Accept: application/soap+xml, application/dime, multipart/related, text/* User-Agent: Axis/1.2.1 Host: 137.207.234.183:8082 Cache-Control: no-cache Pragma: no-cache SOAPAction: "" Content-Length: 495 <?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:echo Soapenv:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/” xmlns:ns1="http://soapinterop.org/"> <ns1:arg0 xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"> Hello! </ns1:arg0> </ns1:echo> </soapenv:Body> </soapenv:Envelope> Request SOAP message HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Set-Cookie: JSESSIONID=37EC6D4DB41FB63B5927D8FC8336BE8B; Path=/axis Content-Type: text/xml;charset=utf-8 Date: Wed, 12 Oct 2005 13:12:01 GMT Connection: close <?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"> Page 6 of 13 <soapenv:Body> <ns1:echoResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://soapinterop.org/"> <echoReturn xsi:type="xsd:string"> Hello! </echoReturn> </ns1:echoResponse> </soapenv:Body> </soapenv:Envelope> Response SOAP message 3.3 Change parameter names and types In the above example, you can see that Axis automatically names the XML-encoded arguments in the SOAP message as "arg0", "arg1", etc. Sometimes you need to change the name and the types. Now let’s look at the Calculator example. You can also find that example in axis installation under samples/userguide. The Calculator class is simple and straight forward: public class Cal { public int add(int i1, int i2){ return i1 + i2; } public int subtract(int i1, int i2){ return i1 - i2; } } Write that class in file Cal.jws and put the file under webapps\axis, we will see its corresponding wsdl file: <?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://localhost:8080/axis/Cal.jws" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://localhost:8080/axis/Cal.jws" xmlns:intf="http://localhost:8080/axis/Cal.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 created by Apache Axis version: 1.2.1 Built on Jun 14, 2005 (09:15:57 EDT)--> <wsdl:message name="addRequest"> <wsdl:part name="i1" type="xsd:int"/> <wsdl:part name="i2" type="xsd:int"/> </wsdl:message> <wsdl:message name="subtractRequest"> <wsdl:part name="i1" type="xsd:int"/> <wsdl:part name="i2" type="xsd:int"/> </wsdl:message> <wsdl:message name="addResponse"> <wsdl:part name="addReturn" type="xsd:int"/> </wsdl:message> <wsdl:message name="subtractResponse"> <wsdl:part name="subtractReturn" type="xsd:int"/> </wsdl:message> <wsdl:portType name="Cal"> <wsdl:operation name="add" parameterOrder="i1 i2"> Page 7 of 13 <wsdl:input message="impl:addRequest" name="addRequest"/> <wsdl:output message="impl:addResponse" name="addResponse"/> </wsdl:operation> <wsdl:operation name="subtract" parameterOrder="i1 i2"> <wsdl:input message="impl:subtractRequest" name="subtractRequest"/> <wsdl:output message="impl:subtractResponse" name="subtractResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="CalSoapBinding" type="impl:Cal"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="add"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="addRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded"/> </wsdl:input> <wsdl:output name="addResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/Cal.jws" use="encoded"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="subtract"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="subtractRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" use="encoded"/> </wsdl:input> <wsdl:output name="subtractResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/Cal.jws" use="encoded"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="CalService"> <wsdl:port binding="impl:CalSoapBinding" name="Cal"> <wsdlsoap:address location="http://localhost:8080/axis/Cal.jws"/> </wsdl:port> </wsdl:service> </wsdl:definitions> The Cal client program is as follows. Please note that we need to set parameter types to int, since it is required by the WSDL file. Also note that the port number is 8081 instead of 8080. We are running tcpmon, which is listening at 8081 and forward the message to 8080. import org.apache.axis.client.Call; import org.apache.axis.client.Service; import javax.xml.namespace.QName; public class CalJWSClient{ public static void main(String [] args) throws Exception{ String endpoint="http://localhost:8081/axis/Cal.jws"; Service service = new Service(); Call call= (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName(new QName("http://soapinterop.org/", "add") ); call.addParameter("oprand1", org.apache.axis.Constants.XSD_INT, javax.xml.rpc.ParameterMode.IN); Page 8 of 13 call.addParameter("oprand2", org.apache.axis.Constants.XSD_INT, javax.xml.rpc.ParameterMode.IN); call.setReturnType(org.apache.axis.Constants.XSD_INT); Integer ret=(Integer)call.invoke(new Object[] { new Integer("1"), new Integer("2") } ); System.out.println("CalcJWS 1+2=" + ret); } } The corresponding SOAP messages exchanged are: Host: 127.0.0.1:8081 Cache-Control: no-cache Pragma: no-cache SOAPAction: "" Content-Length: 808 <?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:add soapenv:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/” xmlns:ns1="http://soapinterop.org/"> <oprand1 href="#id0"/> <oprand2 href="#id1"/> </ns1:add> <multiRef id="id1" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">2 </multiRef> <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/">1</multiRef> </soapenv:Body> </soapenv:Envelope> HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Set-Cookie: JSESSIONID=3DE7DE28FDBFB30949A15F6CC605813D; Path=/axis Content-Type: text/xml;charset=utf-8 Date: Sun, 16 Oct 2005 15:18:55 GMT Connection: close <?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:addResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://soapinterop.org/"> <addReturn xsi:type="xsd:int">3</addReturn> </ns1:addResponse> </soapenv:Body> </soapenv:Envelope> 4 A More Complete View Page 9 of 13 The above simple method is not enough for web service deployment and invocation in real situation. The complete workflow of web service generation and reuse can be illustrated by the following diagram: One path is that when we have a web service, i.e., a wsdl file, we can use tools (in axis we can use WSDL2Java) to generate some java classes so that we can invoke the service as though it is a local object. In particular WSDL2Java will generate the classes that correspond to the types defined in WSDL file. Another path is that when we have a bunch of java classes and we want to turn those classes into web services. In this case we can use axis tool Java2WSDL, to generate the corresponding WSDL file. In addition, we can define the deployment descriptor (.wsdd file), and run AdminClient tool to deploy the web service. 5 Invoke web service using WSDL2Java WSDL2Java tool generates the necessary classes for you to invoke a web service, so that you can call the service just like calling a locale object. java org.apache.axis.wsdl.WSDL2Java Echo.wsdl It will generate the following four files: Echo.java EchoService.java EchoServiceLocator.java EchoSoapBindingStub.java Now the code to invoke the operation is as follows: import DefaultNamespace.*; public class EchoClientWithStub { public static void main(String[] args)throws Exception { Echo es=new EchoServiceLocator().getEcho(); Page 10 of 13 System.out.println("echoClientImplementedWithStub "+ es.echo("stub client")); } } You can also try to invoke web service using wrapper classes on the following examples. I have tested those links and above approach can work on these cases. http://ws.cdyne.com/emailverify/Emailvernotestemail.asmx?wsdl http://www.abundanttech.com/webservices/bnprice/bnprice.wsdl …… 6 Deploy web service 6.1 Deploy Echo using wsdd To deploy a web service, put the .class file into the webapps/axis/WEB-INF/classes directory on your server. Then use a .wsdd file and deploy the web service using the AdminClient as follows: java org.apache.axis.client.AdminClient EchoDeploy.wsdd Where EchoDeploy.wsdd is listed below: <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="EchoWervice" provider="java:RPC"> <parameter name="className" value="Echo"/> <parameter name="allowedMethods" value="*"/> </service> </deployment> You can check whether the service is deployed by listing the exsiting services from the link in http://137.207.234.183/axis/. You can also invoke the service with the same Echo client as listed before. The place you need to change is the endpoint string. That should be the same one as listed in the wsdl file (http://137.207.234.183/axis/services/EchoService?wsdl). 6.2 Deploy Echo as a document style service The deployment descriptor is as below. Note that we changed to document style. <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="EchoDocService" style="document"> <parameter name="className" value="Echo"/> <parameter name="allowedMethods" value="*"/> </service> </deployment> The request sent over the wire would look like follows. Note that there is no operator specification. <soapenv:Body> <arg0 xsi:type="xsd:string" xmlns="http://soapinterop.org/">Hello!</arg0> </soapenv:Body> Page 11 of 13 6.3 Deploy Cal using wsdd First compile the following class and move the class file to WEB-INF/classes directory: public class Cal { public int add(int i1, int i2){ return i1 + i2; } public int subtract(int i1, int i2){ return i1 - i2; } } 6.3.1 Use Axis default:RPC style to deploy Use the following wsdd code to deploy the service. <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="CalService" provider="java:RPC"> <parameter name="className" value="Cal"/> <parameter name="allowedMethods" value="*"/> </service> </deployment> The code to call the service is as below: import org.apache.axis.client.Call; import org.apache.axis.client.Service; import javax.xml.namespace.QName; public class CalWSDDClient{ public static void main(String [] args) throws Exception{ String endpoint="http://localhost:8081/axis/services/CalService"; Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName(new QName("http://soapinterop.org/", "add") ); call.addParameter("oprand1", org.apache.axis.Constants.XSD_INT, javax.xml.rpc.ParameterMode.IN); call.addParameter("oprand2", org.apache.axis.Constants.XSD_INT, javax.xml.rpc.ParameterMode.IN); call.setReturnType(org.apache.axis.Constants.XSD_INT); Integer ret = (Integer) call.invoke( new Object[] { new Integer("3"), new Integer("2") } ); System.out.println("CalWSDD 3+2=" + ret); } } 6.3.2 Use the Document style to deploy the service <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="CalService" style="document" > <parameter name="className" value="Cal"/> <parameter name="allowedMethods" value="*"/> </service> </deployment> Page 12 of 13 - - - - - - - - - - - <?xml version="1.0" encoding="UTF-8" ?> - <wsdl:definitions targetNamespace="http://localhost:8080/axis/services/CalService" …… <wsdl:types> <schema elementFormDefault="qualified" targetNamespace="http://DefaultNamespace" xmlns="http://www.w3.org/2001/XMLSchema"> <element name="i1" type="xsd:int" /> <element name="i2" type="xsd:int" /> <element name="i3" type="xsd:int" /> <element name="i4" type="xsd:int" /> </schema> <schema elementFormDefault="qualified" targetNamespace="http://localhost:8080/axis/services/CalService" xmlns="http://www.w3.org/2001/XMLSchema"> <element name="addReturn" type="xsd:int" /> <element name="subtractReturn" type="xsd:int" /> </schema> </wsdl:types> <wsdl:message name="addRequest"> <wsdl:part element="tns1:i1" name="i1" /> <wsdl:part element="tns1:i2" name="i2" /> </wsdl:message> <wsdl:message name="subtractResponse"> <wsdl:part element="impl:subtractReturn" name="subtractReturn" /> </wsdl:message> <wsdl:message name="addResponse"> <wsdl:part element="impl:addReturn" name="addReturn" /> </wsdl:message> <wsdl:message name="subtractRequest"> <wsdl:part element="tns1:i3" name="i1" /> <wsdl:part element="tns1:i4" name="i2" /> </wsdl:message> <wsdl:portType name="Cal"> <wsdl:operation name="add" parameterOrder="i1 i2"> <wsdl:input message="impl:addRequest" name="addRequest" /> <wsdl:output message="impl:addResponse" name="addResponse" /> </wsdl:operation> <wsdl:operation name="subtract" parameterOrder="i1 i2"> <wsdl:input message="impl:subtractRequest" name="subtractRequest" /> <wsdl:output message="impl:subtractResponse" name="subtractResponse" /> </wsdl:operation> </wsdl:portType> <wsdl:binding name="CalServiceSoapBinding" type="impl:Cal"> <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="add"> <wsdlsoap:operation soapAction="" /> <wsdl:input name="addRequest"> <wsdlsoap:body use="literal" /> </wsdl:input> <wsdl:output name="addResponse"> <wsdlsoap:body use="literal" /> </wsdl:output> </wsdl:operation> <wsdl:operation name="subtract"> <wsdlsoap:operation soapAction="" /> <wsdl:input name="subtractRequest"> <wsdlsoap:body use="literal" /> </wsdl:input> Page 13 of 13 - <wsdl:output name="subtractResponse"> <wsdlsoap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> - <wsdl:service name="CalService"> - <wsdl:port binding="impl:CalServiceSoapBinding" name="CalService"> <wsdlsoap:address location="http://localhost:8080/axis/services/CalService" /> </wsdl:port> </wsdl:service> </wsdl:definitions> 7 Generate WSDL using Java2WSDL java org.apache.axis.wsdl.Java2WSDL -l http://137.207.234.183:8080/axis/Echo Echo The generated WSDL is in http://137.207.234.183/axis/Echo.wsdl. Give the following Java classes we can generate wsdl file for AddrService by running Java2WSDL: public class Address { private String street; private String city; …… } public class AddrService { public AddrService(){} public Address findAddressByZip(String zip){ if (zip.equals("n9b3p4")) return new Address("sunset", "windsor"); return new Address("unknowStreet", "unknown City"); } public String findZipByAddress(Address addr){ if (addr.getCity().equals("windsor")) return "n9b3p4"; return "unknow address"; } } Here is part of the type declarations in the corresponding WSDL file: <complexType name="Address"> <sequence> <element name="city" nillable="true" type="xsd:string"/> <element name="street" nillable="true" type="xsd:string"/> </sequence> </complexType> 8 References [1]. http://ws.apache.org/axis/ [2]. Axis documents, http://ws.apache.org/axis/java/index.html. [3]. Axis User’s Guide, http://ws.apache.org/axis/java/user-guide.html. [4]. http://xmethods.com/