730 likes | 833 Views
Handling Web Services with Apache AXIS. Web-Service Review. By Examples. POST /wsprimegenerator.exe/soap/IPrimeGenerator HTTP/1.0 Content-Type: text/xml; charset=utf-8 Host: www.jusufdarmawan.com SOAPAction: "urn:UnitIPrimeGenerator-IPrimeGenerator#primegenerator" Content-Length: 527
E N D
Web-Service Review By Examples ...
POST /wsprimegenerator.exe/soap/IPrimeGenerator HTTP/1.0 Content-Type: text/xml; charset=utf-8 Host: www.jusufdarmawan.com SOAPAction:"urn:UnitIPrimeGenerator-IPrimeGenerator#primegenerator" Content-Length: 527 <?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:primegenerator soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:UnitIPrimeGenerator-IPrimeGenerator"> <valstart xsi:type="xsd:string">12</valstart> <valend xsi:type="xsd:string">120</valend> </ns1:primegenerator> </soapenv:Body> </soapenv:Envelope> A request to www.jusufdarmawan.com
HTTP/1.0 200 OK Date: Mon, 09 May 2005 20:58:35 GMT Content-Length: 619 Content-Type: text/xml Server: Microsoft-IIS/5.0 X-Powered-By: ASP.NET <?xml version="1.0" encoding='UTF-8'?> <SOAP-ENV:Envelope xmlns:SOAP- ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <NS1:primegeneratorResponse xmlns:NS1="urn:UnitIPrimeGenerator-IPrimeGenerator" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <return xsi:type="xsd:string">13,17,19,23,29,31, 37, 41,43, 47, 53,59,61,67,71,73,79,83,89,97,101,103,107,109,113</return> </NS1:primegeneratorResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope> The Response
POST /soap HTTP/1.0 SOAPAction: "" Content-Length: 520 <?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:getRate soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="urn:xmethods-CurrencyExchange"> <country1 xsi:type="xsd:string">Euro</country1> <country2 xsi:type="xsd:string">Israel</country2> </ns1:getRate> </soapenv:Body> </soapenv:Envelope> A request to services.xmethods.net
HTTP/1.0 200 OK Date: Sat, 07 May 2005 23:26:21 GMT Content-Length: 492 Content-Type: text/xml <?xml version='1.0' encoding='UTF-8'?> <soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/' soap:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'> <soap:Body> <n:getRateResponse xmlns:n='urn:xmethods-CurrencyExchange'> <Result xsi:type='xsd:float'>5.5825</Result> </n:getRateResponse> </soap:Body> </soap:Envelope> The Response
A WSDL Example <?xml version="1.0"?> <definitionsname="CurrencyExchangeService" targetNamespace="http://www.xmethods.net/sd/CurrencyExchangeService.wsdl" xmlns:tns="http://www.xmethods.net/sd/CurrencyExchangeService.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="getRateRequest"> <part name="country1" type="xsd:string"/> <part name="country2" type="xsd:string"/> </message> <message name="getRateResponse"> <part name="Result" type="xsd:float"/> </message> <portType name="CurrencyExchangePortType"> <operation name="getRate"> <input message="tns:getRateRequest" name="getRate"/> <output message="tns:getRateResponse" name="getRateResponse"/> </operation></portType>
<bindingname="CurrencyExchangeBinding"type="tns:CurrencyExchangePortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="getRate"> <soap:operation soapAction=""/> <input name="getRate"> <soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output name="getRateResponse"> <soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> </binding> <service name="CurrencyExchangeService"> <documentation>Returns the exchange rate between the two currencies</documentation> <port name="CurrencyExchangePort" binding="tns:CurrencyExchangeBinding"> <soap:address location="http://services.xmethods.net:80/soap"/> </port> </service> </definitions>
WSDL Elements Service Port * Binding Input Output Operation Port Type *
What is AXIS • Axis is essentially a SOAP engine – a framework for constructing SOAP processors • client side • server side • Axis implements the interfaces of JAX-RPC (XML-based remote procedure calls in Java) • AXIS =Apache EXtensible Interaction System
Apache AXIS: Included Tools • A simple stand-alone server • A Web application that resides in Servlet engines, such as Tomcat • Standalone tools for Web-service invocation • Java/C components • Extensive support for the Web Service Description Language(WSDL) • E.g., tools for generating Java classes (stubs) from WSDL and vice versa • … and more
Remote Method Invocation is not New • java.rmi has been in Java since Java’s early versions • In Java RMI, objects can invoke methods of objects that reside on a remote computer • (RMI = Remote Method Invocation) • So, what has been changed? • Using HTTP for communication • Using agreed protocols, Java can invoke methods that were not written in Java (e.g., .NET methods) and vice versa • A complex registry procedure has been required in RMI
What We Would Like to Create • Client applications: applications that can call a remote Web service • Services: methods that can be called by remote applications • Service descriptions: WSDL files that describe our methods
Calling Web Services • By now, we already know how to invoke a remote Web service in Java: • Open a socket to the remote server • Through the socket, send a SOAP request wrapped by a HTTP request • Parse the response (e.g., using SAX/DOM) • However, this approach is cumbersome, and most of it can be automated • This is the whole point of using standards…
Invoking Services with Apache • Axis includes comfortable tools for managing calls to Web services • The programmer configures the request for the Web service using a friendly API • with, or without considering the WSDL • According to the configuration, a method invocation is transformed into a SOAP request that is sent to the remote server
Invoking Services with Axis • To invoke an operation of a Web service, do the following: • Construct a Service instance • Using the Service instance, generate a Call instance • Configure the Call instance • Invoke the call
Example: Currency Exchange import org.apache.axis.client.*; import javax.xml.namespace.QName; import javax.xml.rpc.ParameterMode; import javax.xml.rpc.encoding.XMLType; publicclass CurrencyExchange { publicstaticvoid main(String[] args) throwsException { System.setProperty("http.proxyHost","wwwproxy.huji.ac.il"); System.setProperty("http.proxyPort","8080"); String endpointUrl = "http://services.xmethods.net:80/soap"; String nsuri = "urn:xmethods-CurrencyExchange"; Service service = new Service(); Call call = (Call) service.createCall();
Example: Currency Exchange (cont) call.setTargetEndpointAddress(endpointUrl); call.setOperationName(new QName(nsuri,"getRate")); call.addParameter("country1", XMLType.SOAP_STRING, ParameterMode.IN); call.addParameter("country2", XMLType.SOAP_STRING, ParameterMode.IN); call.setReturnType(XMLType.SOAP_FLOAT); Object ret = call.invoke(newObject[] {"Euro","Israel"}); System.out.println(ret); } }
Using the WSDL • Axis can read a given WSDL and configure the service as much as possible from that WSDL • Instead of using the default constructor, construct the service using the following constructor: Service(String wsdlLocation, QName serviceName) • When there is only one port, we can obtain it automatically • In this approach, you usually need to know the following about the service: • the WSDL URL, the service name, the namespace uri, the operation name and the expected arguments
public class CurrencyExchange2 { publicstaticvoid main(String[] args)throwsException{ System.setProperty("http.proxyHost",“wwwproxy.huji.ac.il"); System.setProperty("http.proxyPort","8080"); String wsdl ="http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl"; QName sName =new QName("http://www.xmethods.net/sd/CurrencyExchangeService.wsdl", "CurrencyExchangeService"); String oName ="getRate"; Service service =new Service(wsdl, sName); QName port =(QName)service.getPorts().next(); Call call =(Call)service.createCall(port, oName); System.out.println(call.invoke(newObject[]{"UK","Israel"})); }}
publicclass PrimeNumbers { publicstaticvoid main(String[] args)throwsException{ System.setProperty("http.proxyHost",“wwwproxy.huji.ac.il"); System.setProperty("http.proxyPort","8080"); String wsdl ="http://www50.brinkster.com/vbfacileinpt/np.asmx?wsdl"; QName sName =new QName("http://www50.brinkster.com/vbfacileinpt/np","pnum"); String oName ="GetPrimeNumbers"; Service service =new Service(wsdl, sName); QName port = (QName)service.getPorts().next(); Call call = (Call)service.createCall(port, oName); System.out.println(call.invoke(new Object[] {100})); }}
The WSDL2Java Application • Axis provides a mechanism for communicating with a Web service using stubs • That is, generation of regular Java classes that have an interface similar to that of the Web service and implementation that wraps Web service management • Invoke class WSDL2Java in order to create the required Java classes
Generated Classes • WSDL2Java generates the following: • A service interface and a service implementation (locator) for each service • A stub class for each binding • An interface for each port type • This interface contains methods that correspond to the operations of the port type • A class for each complex type
Using The Generated Classes import com.brinkster.www50.vbfacileinpt.np.*; publicclass PrimeNumbers2 { publicstaticvoid main(String[] args)throwsException { System.setProperty("http.proxyHost","wwwproxy.huji.ac.il"); System.setProperty("http.proxyPort","8080"); PnumSoap ps =new PnumLocator().getpnumSoap(); System.out.println(ps.getPrimeNumbers("20")); } }
AXIS Installation • Axis works inside a Servlet container (e.g., Tomcat) • You should add to your Tomcat libs some jar files: axis.jar, saaj.jar, wsdl4j.jar, … • You need to include several jar files in your CLASSPATH • This has already been done for you! • The needed CLASSPATH definitions where added to dbi.cshrc • The needed jar files are in $CATALINA_HOME/lib/
$CATALINA_HOME $CATALINA_BASE lib webapps … axis.jar saaj.jar myapplication axis The directory that you need to copy Classes were added for you AXIS Installation (cont) • You need to copy the Axis application to your Tomcat's application directory: cp -r ~dbi/tomcat/axis/ $CATALINA_BASE/webapps
Creating a Web Service Next, we will see how we can create and publish a Web service using the Axis plugin in Tomcat
1. Generate the Implementing Class package myws; publicclass Power { publicint power(int a, int n) { return (int)Math.pow(a,n); } } $CATALINA_BASE/webapps/axis/WEB-INF/ classes/myws/Power.class
2. Deploy the Service using Web Service Deployment Descriptor <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="mypower" provider="java:RPC"> <parameter name="className" value="myws.Power"/> <parameter name="scope" value="application"/> <parameter name="allowedMethods" value="*"/> </service> </deployment> services.wsdd java org.apache.axis.client.AdminClient -hlocalhost -p8080 services.wsdd
That's it! You Can Call the Service. import org.apache.axis.client.*; publicclass PowerClient { publicstaticvoid main(String[] argv)throwsException { String endpoint = "http://mangal:8080/axis/services/mypower"; Call call = (Call) new Service().createCall(); call.setTargetEndpointAddress(endpoint); call.setOperationName("power"); Object value = call.invoke(newObject[] {newInteger(2), newInteger(5)}); System.out.println(2+"^"+5 +"=" + value); } }
How Does it Work? • The AXIS plugin is simply a Web application that resides in Tomcat (under webapps/) • The Servlet AxisServlet of this application is responsible for invoking services • All URLs of the form /services/* are mapped to the AxisServlet • Where is that written?
How Does it Work? (cont) • The wsdd file defines mappings between a Web service elements to a Java class elements • I.e., names, methods, etc. • The class AdminClient sends a request to the application to register the service based on the wsdd content • When a SOAP request arrives, the AxisServlet object parses the request and invokes the corresponding method of the class associated with the service URL
The Deployment Descriptor <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="mypower" provider="java:RPC"> <parameter name="className" value="myws.Power"/> <parameter name="scope" value="application"/> <parameter name="allowedMethods" value="*"/> </service> </deployment> services.wsdd
The Scope of the Object • Request (the default): a new object is created for each request, the service instance is available for the duration of the request (regardless of forwarding) • Session: a new object is created for each new session and the service instance is available for the entire session • Application: a singleton shared service instance is used to serve all invocations
Undeploying a Service <undeployment xmlns="http://xml.apache.org/axis/wsdd/"> <service name="mypower"/> </undeployment> undeploy.wsdd java org.apache.axis.client.AdminClient -hlocalhost -p8080 undeploy.wsdd
Implementing Classes • The class that implements the Web service must be accessible to the Axis Servlet • Hence, this class should reside in a package in $CATALINA_BASE/webapps/axis/WEB-INF/classes/ • Of course, all helper classes should be accessible to the Axis application too
The Service WSDL • Axis automatically provides a WSDL for each deployed service • To get the WSDL, use the service URL with the empty argument wsdl http://localhost:8080/axis/services/mypower?wsdl
Power-Service WSDL <?xmlversion="1.0" encoding="UTF-8"?> <wsdl:definitionstargetNamespace="http://inferno-02/axis/services/mypower" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://localhost/axis/services/mypower" xmlns:intf="http://localhost/axis/services/mypower" 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:message name="powerResponse"> <wsdl:part name="powerReturn" type="xsd:int"/> </wsdl:message> <wsdl:message name="powerRequest"> <wsdl:part name="a" type="xsd:int"/> <wsdl:part name="n" type="xsd:int"/> </wsdl:message>
<wsdl:portType name="Power"> <wsdl:operation name="power" parameterOrder="a n"> <wsdl:input message="impl:powerRequest" name="powerRequest"/> <wsdl:output message="impl:powerResponse" name="powerResponse"/> </wsdl:operation> </wsdl:portType>
<wsdl:binding name="mypowerSoapBinding"type="impl:Power"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="power"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="powerRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://myws" use="encoded"/> </wsdl:input> <wsdl:output name="powerResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/axis/services/mypower" use="encoded"/> </wsdl:output> </wsdl:operation> </wsdl:binding>
<wsdl:service name="PowerService"> <wsdl:port binding="impl:mypowerSoapBinding" name="mypower"> <wsdlsoap:address location="http://inferno-02:8080/axis/services/mypower"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
jws Files • There is a fast and easy way of crating a service: • Create a Java class myClass.java • Rename your class to end with jws: myClass.jws • Put the jws file directly under the directory $CATALINA_BASE/webapps/axis/ (the application’s root) • That is all. Now you can call the service!
Example: a Calculator Service publicclass SimpleCalculator { publicint add(int i1, int i2) { return i1 + i2; } publicint subtract(int i1, int i2) { return i1 - i2; } } $CATALINA_BASE/webapps/axis/SimpleCalculator.jws Service URL: http://server:port/axis/SimpleCalculator.jws
Example: a Calculator Service publicclass CalculatorClient { publicstaticvoid main(String[] argv)throwsException { String endpoint = "http://localhost:8080/axis/SimpleCalculator.jws"; Call call = (Call) new Service().createCall(); call.setTargetEndpointAddress(endpoint); call.setOperationName("add"); Object value = call.invoke(newObject[] {new Integer(4), newInteger(6)}); System.out.println(value); } }
How does it Work? • On the first time the jws file is being called, it is compiled into a class • WEB-INF/jwsClasses/SimpleCalculator.class • Axis then considers the URL of the jws as one of a regular web service • Default configurations are assumed • Sounds like any other technology we know?
When not to Use jws Files • When you do not have the Java source code • When you don’t want to expose your code • When you want to use custom type mappings • When you want to use other configuration options