800 likes | 996 Views
Deploying Web Services with AXIS. Representation and Management of Data on the Web. Web Services. Web services are methods that a remote application can call The methods are invoked through usual Web protocols (e.g., HTTP) Calling a method: Discovery (UDDI) Description (WSDL)
E N D
Deploying Web Services with AXIS Representation and Management of Data on the Web
Web Services • Web services are methods that a remote application can call • The methods are invoked through usual Web protocols (e.g., HTTP) • Calling a method: • Discovery (UDDI) • Description (WSDL) • Invocation (SOAP)
What is AXIS • Axis is essentially a SOAP engine – a framework for constructing SOAP processors such as clients, servers, gateways • AXIS implements the interfaces of JAX-RPC (remote procedure calls in Java, using XML) • AXIS = Apache EXtensible Interaction System
Remote Method Invocation is not a New Idea • 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 Invokation) • So, what has been changed: • Using HTTP and port 80 we can bypass the firewall • 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
AXIS Includes • Axis isn't just a SOAP engine – it also includes: • a simple stand-alone server • a server which plugs into servlet engines such as Tomcat • extensive support for the Web Service Description Language (WSDL) • emitter tooling that generates Java classes from WSDL • a tool for monitoring TCP/IP packets
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 were added to $CATALINA_BASE/shared/lib/
The directory that you need to copy Classes were added for you Working With AXIS • AXIS uses Servlets that Tomcat apply • You should copy the axis directory from dbi to your webapps directory: cp –r ~dbi/tomcat/axis $CATALINA_BASE/webapps/ $CATALINA_BASE webapps shared friendsnet axis lib classes
http://computer-that-run-tomcat:port/axis Validate installation View deployed services
What We Would Like to Create • Client applications: applications that can call a remote service • Services: methods that can be called by remote applications • Service descriptions: WSDL files that describe our methods
Will We Do a Lot of XML Parsing? • You will not directly read or write SOAP messages • Instead, use Java methods that create request and analyze result • Use the AxisServlet that actually includes a SOAP processor • Code the Client Application and the Service Application
Request a WSDL file Receive a WSDL Parse Returned WSDL A Client in a Web Service Web Server
SOAP Request Send SOAP Request Create Receive SOAP Response Parse SOAP Response A Client in a Web Service Web Server
Creating a Client • Create a Service object • Create a Call object • Set the endpoint URL, i.e., the destination for the SOAP message • Define the operation (method) name of the Web Service • Invoke the desired service, passing in an array of parameters
A Simple Client Example import org.apache.axis.client.Call; import org.apache.axis.client.Service; import javax.xml.namespace.QName; public class TestClient { public static void main(String [] args) { try { String endpoint = "http://nagoya.apache.org:5049/axis/services/echo"; Service service = new Service(); Call call = (Call) service.createCall();
A Simple Client Example call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName(new QName("http://soapinterop.org/", "echoString")); String ret = (String) call.invoke( new Object[] { "Hello!" } ); System.out.println("Sent 'Hello!', got '" + ret + "'"); } catch (Exception e) { System.err.println(e.toString()); } } }
POST http://nagoya.apache.org:5049/axis/services/echo HTTP/1.0 Content-Type: text/xml; charset=utf-8 Accept: application/soap+xml, application/dime, multipart/related, text/* User-Agent: Axis/1.1 Host: nagoya.apache.org:5049 Cache-Control: no-cache Pragma: no-cache SOAPAction: "" Content-Length: 461 <?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:echoString soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://soapinterop.org/"> <ns1:arg0 xsi:type="xsd:string">Hello!</ns1:arg0> </ns1:echoString> </soapenv:Body> The HTTP Request
Example: A Client that Uses WSDL • We create an application that calls a remote Web service • In our example the remote Web service produces prime numbers in a given range • The service is in URL http://www.jusufdarmawan.com/wsprimegenerator.exe/wsdl/IPrimeGenerator
The WSDL of the Service <?xml version="1.0" ?> <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema" name="IPrimeGeneratorservice" targetNamespace="http://www.borland.com/soapServices/" xmlns:tns="http://www.borland.com/soapServices/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"> <message name="primegeneratorRequest"> <partname="valstart" type="xs:string" /> <partname="valend" type="xs:string" /> </message> <message name="primegeneratorResponse"> <partname="return" type="xs:string" /> </message>
<portType name="IPrimeGenerator"> <operation name="primegenerator"> <inputmessage="tns:primegeneratorRequest" /> <outputmessage="tns:primegeneratorResponse" /> </operation> </portType> String primegenerator(String valstart, String valend) Defining the function
<binding name="IPrimeGeneratorbinding" type="tns:IPrimeGenerator"> <soap:bindingstyle="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> <operation name="primegenerator"> <soap:operationsoapAction="urn:UnitIPrimeGenerator-IPrimeGenerator#primegenerator" /> <input> <soap:bodyuse="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:UnitIPrimeGenerator-IPrimeGenerator" /> </input> <output> <soap:bodyuse="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:UnitIPrimeGenerator-IPrimeGenerator" /> </output> </operation> </binding> Binding the method as an RPC
<service name="IPrimeGeneratorservice"> <port name="IPrimeGeneratorPort" binding="tns:IPrimeGeneratorbinding"> <soap:address location="http://www.jusufdarmawan.com/wsprimegenerator. exe/soap/IPrimeGenerator" /> </port> </service> </definitions> The Service URL
The Client Source Code import org.apache.axis.client.Call; import org.apache.axis.client.Service; import javax.xml.namespace.QName; import java.net.URL; public class PrimeGenerator { public static void main(String[] argv) { try { /* Set the porxy parameters */ System.setProperty("http.proxyHost", "wwwproxy.huji.ac.il"); System.setProperty("http.proxyPort", "8080");
/* Set the service parameters */ String defaultNS = null; String endpoint = null; URL wsdl = new URL("http://www.jusufdarmawan.com/ wsprimegenerator.exe/wsdl/IPrimeGenerator"); QName serviceName = new QName("http://www.borland.com/soapServices/", "IPrimeGeneratorservice"); String method = "primegenerator"; String port = "IPrimeGeneratorPort"; /* Set the service arguments */ String start = "200"; String end = "300";
/* Invoke the service */ Service service = new Service(wsdl, serviceName); Call call = (Call) service.createCall(new QName(port), new QName(method)); String value = (String)call.invoke(new Object[] { start, end } ); System.out.println("Primes between " + start +" and " + end + ": " + value); } catch (Exception exp) { exp.printStackTrace(System.err); } } }
The HTTP Request POST /wsprimegenerator.exe/soap/IPrimeGenerator HTTP/1.0 content-type:text/xml; charset=utf-8 accept:application/soap+xml, application/dime, multipart/related, text/* user-agent:Axis/1.1 host:www.jusufdarmawan.com cache-control:no-cache pragma:no-cache soapaction:"urn:UnitIPrimeGenerator-IPrimeGenerator#primegenerator" content-length:540 -- empty line --
<?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">200</valstart> <valend xsi:type="xsd:string">300</valend> </ns1:primegenerator> </soapenv:Body> </soapenv:Envelope>
The HTTP Response HTTP/1.0 200 OK Date: Tue, 08 Jun 2004 20:10:16 GMT Content-Length: 603 Content-Type: text/xml Server: Microsoft-IIS/5.0 X-Powered-By: ASP.NET Content: Via: 1.1 proxy7 (NetCache NetApp/5.5R4)
<?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"> 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293</return> </NS1:primegeneratorResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Service • Service() • the constructor assumes that the caller will set the appropriate fields by hand rather than getting them from the WSDL • Service(java.io.InputStream wsdlInputStream, QName serviceName) • Constructs a new Service object for the service in the WSDL document in the wsdlInputStream and serviceName parameters
Creating a Call • Call createCall() • Creates a new Call object with no prefilled data • Call createCall(QName portName, QName operationName) • Creates a new Call object - will prefill as much info from the WSDL as it can
Call • Used to actually invoke the Web service • You can invoke the operation associated with the call using invoke(…) • invoke(Object[] params) • Invokes the operation associated with the call usingthe passed in parameters as the arguments to the method
Setting Types • You can set parameters using the method addParamether(…) • You can set the returned type using setReturnedType(…) call.addParameter("testParam", org.apache.axis.Constants.XSD_STRING, javax.xml.rpc.ParameterMode.IN); call.setReturnType(org.apache.axis.Constants.XSD_STRING);
Creating a Service • 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 under the directory $CATALINA_BASE/webapps/axis/ • That is all. Now you can call the service!
We create a Java Class Example: a Calculator Service public class SimpleCalculator { public int add(int i1, int i2) { return i1 + i2; } public int subtract(int i1, int i2) { return i1 - i2; } } We rename the file SimpleCalculator.jws We put the file under webapps/axis
http://computer-that-runs-tomcat:port/axis/SimpleCalculator.jwshttp://computer-that-runs-tomcat:port/axis/SimpleCalculator.jws
The Client For the Calculator import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.apache.axis.encoding.XMLType; import org.apache.axis.utils.Options; import javax.xml.rpc.ParameterMode; public class SimpleCalcClient { public static void main(String [] args) throws Exception { String endpoint = "http://mangal.cs.huji.ac.il:8999/axis/SimpleCalculator.jws"; if (args == null || args.length != 3) { System.err.println("Usage: SimpleCalcClient <add|subtract> arg1 arg2"); return; } String method = args[0]; if (!(method.equals("add") || method.equals("subtract"))) { System.err.println("Usage: CalcClient <add|subtract> arg1 arg2"); return; }
Integer i1 = new Integer(args[1]); Integer i2 = new Integer(args[2]); Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName( method ); call.addParameter( "op1", XMLType.XSD_INT, ParameterMode.IN ); call.addParameter( "op2", XMLType.XSD_INT, ParameterMode.IN ); call.setReturnType( XMLType.XSD_INT ); Integer ret = (Integer) call.invoke( new Object [] { i1, i2 }); System.out.println("Got result : " + ret); } }
1 SimpleCalculator.jws HTTP Request 2 http://host:8090/axis/SimpleCalculator.jws Tomcat $CATALINA_BASE webapps shared friendsnet axis lib classes WEB-INF classes jwsClasses AxisServlet.class
1 SimpleCalculator.jws 4 SimpleCalculator.class The HTTP Request is “translated” to a request for 3 http://host:8090/axis/servlet/AxisServlet The original URL is still known! Tomcat $CATALINA_BASE webapps shared friendsnet axis lib classes WEB-INF classes jwsClasses AxisServlet.class
1 SimpleCalculator.jws 4 SimpleCalculator.class Tomcat $CATALINA_BASE webapps shared friendsnet axis lib classes WEB-INF classes jwsClasses AxisServlet.class • The class SimpleCalculator is compiled and dynamically loaded • The SOAP request is parsed and analyzed • A response is created by the SimpleCalculator • The result is wrapped as a SOAP response an returned to the caller 5 HTTP Response
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
AxisServlet • Dealing with service calls is done by AxisServlet • The following files are mapped to AxisServlet (in web.xml of the axis application directory): • servlet/AxisServlet • *.jws • services/*
Deploying Services • When a service is called, the AxisServlet must know where to look for the application • Telling where the application can be found is called "deploying" • Deploying is a two-step process: • Create a deployment descriptor file • Call the java command that deploys the web application: java org.apache.axis.client.AdminClient -p portdeploy-file.wsdd
Creating a Service • Create a Java class • Compile the class • Put the class under axis/WEB-INF/classes/the-package-name/ • Create a deployment descriptor file mydeploy.wsdd • Call the AdminClient Service with the deployment file as a parameter (in the computer where Tomcat runs AXIS) • You are done and can call the service!
Example: A Power Function • We create a service that computes the power of two numbers • We show how to deploy the service • We demonstrate the service with a client that calls the service
We compile the class and put the file in the right directory $CATALINA_BASE/webapps/axis/WEB-INF/classes/dbi/PowerService.class The Service Code package dbi; public class PowerService { public int power(int a, int n) { return (int)Math.pow(a,n); } }
Deployment File <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="dbiPowerService" provider="java:RPC"> <parameter name="className" value="dbi.PowerService"/> <parameter name="scope" value="application"/> <parameter name="allowedMethods" value="*"/> </service> </deployment> We call the file dbideploy.wsdd java org.apache.axis.client.AdminClient -p8090 dbideploy.wsdd After deployment you can call the service
A Client that Calls the Power Service import org.apache.axis.client.Call; import org.apache.axis.client.Service; import javax.xml.namespace.QName; public class PowerClient { private static final String host = "mangal.cs.huji.ac.il"; private static final int port = 8090; public static void main(String[] argv) { try { int x=2, n=5; String endpoint = "http://" + host + ":" + port + "/axis/services/dbiPowerService";
call call = (Call) new Service().createCall(); call.setTargetEndpointAddress(new java.net.URL(endpoint)); call.setOperationName("power"); Integer value = (Integer)call.invoke(new Object[] { new Integer(x), new Integer(n) }); System.out.println(x+"^"+n +"=" + value); } catch (Exception exp) { exp.printStackTrace(System.err); } } } Is it important from which directory I call the client? Is it important from which computer I call the client?