660 likes | 806 Views
Distributed Object Programming with XML and Java. CC432 / Short Course 509 Applied XML Lecturer: Simon Lucas University of Essex Spring 2002. Outline. Web Services Distributed Object Programming Java RMI XML-RPC SOAP-RPC. Web Services. Client Application. Service Implementation.
E N D
Distributed Object Programmingwith XML and Java CC432 / Short Course 509 Applied XML Lecturer: Simon Lucas University of Essex Spring 2002
Outline • Web Services • Distributed Object Programming • Java RMI • XML-RPC • SOAP-RPC
Web Services Client Application Service Implementation Language Specific Messages Language Neutral Messages Web Service
Web Service Components Service Implementation Web Application Server (e.g. Tomcat) Service Proxy Client Service Listener
Web Service Stack Discovery (UDDI) Description (WSDL) Packaging (SOAP) Transport (HTTP) Network (TCP/IP)
Web Services and DOP • If both clients and services are implemented in OO languages • Then we can view a web service system as a form of distributed object programming (DOP) • Therefore: instructive to consider other (less general) ways of doing this
Why is DOP Difficult? • Aim: invoke a method call on a remote object • Easy if: parameters and return values are all primitive types • What if they are Objects? • Of standard classes • Of user-defined classes
Java RMI • We’ll begin by looking at Java RMI • This allows easy distributed object programming • BUT: restricted to the Java language • Almost transparent: • declare things to be remote or serializable • then just call methods on remote objects just as you would on local objects
Remote Objects • Suppose we have a Rectangle class: • class Rectangle { double w; double h; } • Suppose we have the following method in class Geometry to be exposed service: • public double area(Rectangle r) { return r.w * r.h; }
Rectangle Reference • There are two distinct ways in which the remote service can access the w and h values • Either the client sends it a serialized version of the Rectangle • OR – the client sends it a remote reference to the Rectangle • In other words, pass by value, or pass by reference
Parameter Marshalling / Unmarshalling • Marshalling is the process of the caller packaging up the parameters prior to the remote method call • Unmarshalling is when the server unpacks them at the other end • Before then passing them on to the remote object (i.e. the object at the server)
Hello World in RMI • For comparison with SOAP later, let’s look at a hello world service, and how to implement and deploy it using RMI • We need to: • Define the service interface • Provide a Remote-enabled implementation • Register an implementation object • Access it with a client • The client gets a remote reference to the object implementation • Then makes calls on it, just like a local object
Hello Interface package examples.rmi; import java.rmi.*; public interface HelloInterface extends Remote { public String getResponse(String request) throws RemoteException; }
Hello Implementation package examples.rmi; import java.rmi.*; import java.rmi.server.UnicastRemoteObject; public class HelloServer extends UnicastRemoteObject implements HelloInterface { public String getResponse(String request) throws RemoteException { return "Hello from " + name; } }
Registering the Service package examples.rmi; import java.rmi.Naming; public class RegisterHelloServer { public static void main(String[] args) throws Exception { HelloServer hob = new HelloServer(); Naming.rebind("HelloServer2", hob); System.out.println( "HelloServer bound in registry"); } }
Hello Client package examples.rmi; import java.rmi.Naming; public class HelloClient { public static void main (String[] args) throws Exception { HelloInterface obj = (HelloInterface) Naming.lookup( "//ace.essex.ac.uk/HelloServer2"); System.out.println(obj.getResponse( "From Me" )); } }
Serialized v. Remote Ref • Discussion Question: • Suppose you must decide whether to send a serialized copy of an object, or a remote reference to the object • What do you think are the criteria for deciding which option is best?
XML-RPC A simple protocol for making language neutral remote procedure calls
XML-RPC • Easy way to make RPCs over the web • Typically done over HTTP • XML-based so language neutral • Offers a fixed set of datatypes • Primitives (int, boolean etc, all the usual) • Strings • Arrays of primitives or Strings (uniform) • Structs of primitives or Strings (mixed)
XML-RPC Parameters • Method parameters are passed by value • So: what happens if the parameters are objects? • XML-RPC only supports a fixed set of data types • So: you must make your code fit in with these • Could be very HARD WORK for comp[lex objects • But very easy to use for simple examples
Apache XML-RPC Client XmlRpcClient xmlrpc = new XmlRpcClient ("http://localhost:8080/RPC2"); Vector params = new Vector (); params.addElement ("some parameter"); // this method returns a string String result = (String) xmlrpc.execute ("method.name", params);
Client Request Header POST / HTTP/1.0 User-Agent: Apache XML-RPC 1.0 Host: localhost:5050 Content-Type: text/xml Content-Length: 192
Client Request Body <?xml version="1.0" encoding="ISO-8859-1"?> <methodCall> <methodName>echo</methodName> <params> <param> <value>test</value> </param> <param> <value> <int>123</int> </value> </param> </params> </methodCall>
Server Response Header HTTP/1.0 200 OK Server: Helma XML-RPC 1.0 Connection: close Content-Type: text/xml Content-Length: 199
Server Response Body <?xml version="1.0" encoding="ISO-8859-1"?> <methodResponse> <params> <param> <value> <array> <data> <value>test</value> <value><int>123</int></value> </data> </array> </value> </param> </params> </methodResponse>
SOAP Simple Object Access Protocol
SOAP Basics • Parameters passed by value • Can be of any type • Selectable Object Encoding • Can use a SOAP standard encoding • Or ANY user defined one • In which case client and service MUST agree! • Often layered over HTTP POST requests • BUT is actually protocol neutral – can work over email as well, or any other transport
SOAP-RPC Request • Parameters passed by value • SOAP-RPC Request envelope • Defines the Object URN • The method name • The method parameters
SOAP-RPC Response • Returns a response value or a fault • Again – object encoding is user-defined • See example below
Deploying SOAP Services • Apache-SOAP offers two methods • Fill in a form using a web-browser • POST an XML DeploymentDescriptor to the SOAP RPC Router • The latter method is generally preferred • can be executed from a program • hence less effort
SOAP-RPCs from Java • The following example uses Apache SOAP 2.0 • Make a remote method call – hello world example • This example was adapted from the SOAP articles by Tarak Modi: • http://www.javaworld.com/javaworld/jw-03-2001/jw-0330-soap.html
Making a SOAP-RPC A standard SOAP-RPC involves: • Create a call Object • Set up the URI encoding style • Set the URN of the object (TargetObject URN) • Set the method name • Set up a Vector of parameters (each one of type Parameter) • Set the call parameters to be this vector of parameters
Making a SOAP-RPC contd • Set up a URL for the call • Make the method invocation: • Response r = call.invoke() • From the response, we detect whether the call was successful, or if some error has occurred • If successful, we extract the Parameter from the call, and retrieve the object from the parameter
Hello SOAP World • Define this interface for Hello Service • Not necessary – but useful to decouple the service description from the implementation • Essential for Dynamic Proxy – see later package hello; public interface Hello { public String sayHelloTo(String name) }
Implementing the Service • In this case, the service is very simple: package hello; public class HelloImpl { // just to notify when tomcat loads the class static { System.out.println("Loaded HelloImpl.class"); } public String sayHelloTo(String name) { System.out.println("sayHelloTo(String name)"); return "Hello " + name + ", How are you doing?"; } }
DeploymentDescriptor.xml <isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment" id="urn:Hello"> <isd:provider type="java" scope="Application" methods="sayHelloTo"> <isd:java class="hello.HelloImpl" static="false"/> </isd:provider> </isd:service>
Notes on Deployment • id=“urn:Hello” – this will be the urn identified in the SOAP-Request by the client • and mapped to a service object • scope=“Application” – an instance is created once for the entire application
Notes on Deployment II • class=“hello.HelloImpl” – the (Java) class to be loaded for this URN • Must be available on the Servlet-Engine’s classpath • static=“false” – an instance method rather than a class method
Deploying the Descriptor • Done by POSTing a SOAP message to the SOAP Service Manager: \soap>java org.apache.soap.server.ServiceManagerClient http://localhost:8080/soap/servlet/rpcrouter deploy hello\DeploymentDescriptor.xml (line breaks for presentation only)
The Hello Client • Note that the most basic version is quite long-winded • Compare this to the Dynamic Proxy version that comes later!
Hello I - imports package hello; import java.net.URL; import java.util.Vector; import org.apache.soap.SOAPException; import org.apache.soap.Constants; import org.apache.soap.Fault; import org.apache.soap.rpc.Call; import org.apache.soap.rpc.Parameter; import org.apache.soap.rpc.Response;
Hello II - init public class Client { public static void main(String[] args) throws Exception { String name = args[0]; try { URL url = new URL("http://localhost:8080/ soap/servlet/rpcrouter"); // Build the call - but time it also long start = System.currentTimeMillis();
Hello III – Call setup Call call = new Call(); call.setTargetObjectURI("urn:Hello"); call.setMethodName("sayHelloTo"); call.setEncodingStyleURI( Constants.NS_URI_SOAP_ENC); Vector params = new Vector(); params.addElement( new Parameter( "name", String.class, name, null)); call.setParams(params);
Hello IV – Method Invocation Response resp = null; try { resp = call.invoke(url, ""); resp = call.invoke(url, ""); } catch( SOAPException e ) { System.err.println( "Caught SOAPException (" + e.getFaultCode() + "): " + e.getMessage()); System.exit(-1); }
Hello V – Response Handling if( !resp.generatedFault() ) { Parameter ret = resp.getReturnValue(); Object value = ret.getValue(); System.out.println(value); } else { Fault fault = resp.getFault(); System.err.println( fault ); } long end = System.currentTimeMillis(); System.out.println( "Elapsed ms: " + (end - start) );
Running Hello • When run successfully, get the following: \soap>java hello.Client Simon Hello Simon, How are you doing? Elapsed ms: 701 • The elapsed time looks very slow • BUT: most of the delay is in loading the client-side classes • Subsequent calls are much quicker!!!
Dynamic Proxies • A Dynamic Proxy can hide the nasty details! • We set up a dynamic proxy by: • specifying an array of interfaces that it will implement • a service end-point to use to invoke methods of those interfaces (i.e. an Invocation Handler) • We can now invoke the methods on the object just as if it were a local object • The following code (Again from Tarak Modi) illustrates this
hello.ProxyClient.java package hello; import proxy.*; public class ProxyClient { public static void main(String[] args) throws Exception { Class[] interfaces = new Class[] {hello.Hello.class}; Hello hello = (Hello) Proxy.newInstance("urn:Hello",interfaces); System.out.println(hello.sayHelloTo("Simon")); } }
Dynamic Proxies Contd. • Dynamic proxies greatly simplify invoking SOAP services • Of course – even without a Dynamic Proxy, we could still write a SOAP-RPC implementation of the Hello interface • And then make RPC call just like with the Dynamic Proxy version • But – with the Dynamic Proxy, we don’t have to write the code! • Clever!!!
TcpTunnelGui • Apache SOAP comes with a simple but great tool – TcpTunnelGui • Can be invoked from the command line like this: java org.apache.soap.util.net.TcpTunnelGui 5050 localhost 8080 • 5050 – the port to listen for client connections • localhost – the server host to connect to • 8080 – the server port to connect to