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
ICT337 Advanced Software Development Murdoch University Topic 7 Topic 7 RMI Working with sockets – A quick review What is RMI? How to use RMI? Developing a remote class of objects – examples RMI and firewalls JNDI Java IDL and CORBA topic7.doc Page 1 ICT337 Advanced Software Development Murdoch University Topic 7 Working with sockets – A quick review Different programs can communicate through communications channels called sockets. You can use a socket to transfer data between unrelated processes on the same machine or on different machines on a network. The TCP/IP socket is connection-oriented. When you create a socket, you create an endpoint for a connection between 2 processes. You first determine the port number for the communication. On the server side, you create a ServerSocket object with the selected port number as argument. You then create a Socket object by calling the method accept() of the ServerSocket handle. Finally, you ask the Socket object for its input and output streams. Since a combination of the server host name and the selected port number above make up a unique identifier for the server. On the client side, a Socket object can be created using the server host name and port number. An input stream and output stream on the client side are created in a similar fashion. The client can then write to its output stream to send data to the server and read from its input stream to retrieve data from the server. Server follows a similar procedure to send/retrieve data to/from the client. topic7.doc Page 2 ICT337 Advanced Software Development Murdoch University Topic 7 TCP/IP socket has the following short-coming: It is useful only when you want to move data from one point (machine) to another, eg. to copy the contents of a file from System A to System B. What if you want to directly invoke the methods of objects located on other systems? You could establish a TCP/IP connection and then send/receive messages using some predefined format, eg. if the message from the client to the server was “invoke computeAreaOfCircle radius 5” then the server would execute computeAreaOfCircle(5) and pass the result to the client. The drawbacks are: (1) the messages can become complicated, (2) the messages must be specified in a pre-defined format and a parser is required to parse the messages, and (3) passing complex data type (eg. Java objects) as arguments to methods is not trivial. And… after all of your hard work, you would have merely created a subset of the functionality already provided by Java RMI. topic7.doc Page 3 ICT337 Advanced Software Development Murdoch University Topic 7 What is RMI? RMI (Remote Method Invocation) is a technology that allows programmers to directly call the methods of Java objects that reside on other systems. RMI is based on a similar earlier technology for procedural programming called remote procedure calls (RPC). The goal of RPC was to allow programmers to concentrate on the required tasks of an application by calling functions. RMI makes the networking transparent to the programmer. RMI is the Java’s implementation of RPC for Javaobject-to-Java-object distributed communication. How to use RMI? When using remote objects, you need only take one additional step to locate the object within the network after his application starts. After having the object reference, you use it as if the object resides on the local machine. What happens behind the scenes is: The client program has a reference to a Stub object that is a local surrogate for the remote object. This stub is returned by the local Object Request Broker (ORB) in response to your request to locate the object. topic7.doc Page 4 ICT337 Advanced Software Development Murdoch University Topic 7 The Stub object on the local system (the client side) has all the same methods supported by the remote object. The Stub object forwards the parameters to the remote object and passes back any return value for the method. The technique used to forward the parameters to the remote object is called marshalling, i.e. the data are gathered and put together into a message buffer and then organized or converted into a format that is prescribed by a particular receiver or programming interface. This involves serializing the parameters into a byte stream and sent to the remote system. NOTE: Only primitive and reference types that implement the Serializable interface can be used as parameter types for remote methods. On the remote system (the server side), a skeleton object receives this byte stream and demarshalls to retrieve the contents of the parameter list. This involves deserializing the byte stream. The skeleton object passes the parameters to the remote object and the method is executed. The return value (if any) from the method is serialized and returned using the same process, but in reverse. topic7.doc Page 5 ICT337 Advanced Software Development Murdoch University Topic 7 The diagram below shows the execution flow of a remote method call. local system remote system Stub Skeleton Client Object Remote Object Apparent path Actual path Flow of a remote method call In RMI, local objects (eg. objects created locally on the client and then passed as argument to a method on the server) are passed by copy, ie. all data fields of the objects are copied except for those declared as static or transient. remote objects (eg. An object returned from a server method) are passed by reference. A reference to a topic7.doc Page 6 ICT337 Advanced Software Development Murdoch University Topic 7 remote object is actually a reference to a stub, which is a client-side proxy for the remote object. topic7.doc Page 7 ICT337 Advanced Software Development Murdoch University Topic 7 Developing a remote class of objects – An example STEP 1: Put all the methods of a class that you want to expose to the clients into an interface definition. NOTES: o static methods cannot be part of the interface, and neither can any data fields o the interface must extend java.rmi.Remote, which is a marker interface and defines no methods o all methods in the interface must indicate that you may throw a java.rmi.RemoteException Example: import java.rmi.Remote; import java.rmi.RemoteException; public interface Hello extends Remote { // a method sayHello with no arguments String sayHello() throws RemoteException; } STEP 2: Write the class, say HelloImpl, that implements the above interface. Objects that require remote behaviour should extend the class RemoteObject, typically via the class UnicastRemoteObject. topic7.doc Page 8 ICT337 Advanced Software Development Murdoch University Topic 7 Example: import java.rmi.Remote; import java.rmi.RemoteException; public class HelloImpl extends UnicastRemoteObject implements Hello { // constructor ... // implementation for each remote method } By extending UnicastRemoteObject, the HelloImpl class can be used to create a remote object that: o uses RMI's default sockets-based transport for communication o runs all the time The constructor(s) of the class must declare to throw at least a java.rmi.RemoteException, ie. public HelloImpl() throws RemoteException { super(); } The next task is to provide an implementation for each remote method, ie. put String sayHello() throws RemoteException { return ”Hello world!”; } inside the HelloImpl class. topic7.doc Page 9 ICT337 Advanced Software Development Murdoch University Topic 7 STEP 3: After the implementation class has been successfully compiled, you must create the stub (for the client side) and skeleton (for the server side) classes required by RMI. This can be done easily using the rmic utility provided by Java 2 SDK on the implementation class file. Executing the command rmic HelloImpl would create the Stub file HelloImpl_Stub.class and the Skeleton file HelloImpl_Skel.class. Note that Java 2 no longer requires the skeleton class, so you in fact need only create the stubs for 1.2 JRMP (see later) stub protocol version, ie. use rmic –v1.2 HelloImpl which would create only the file. HelloImpl_Stub.class STEP 4: Write the server program that defines the object handle(s) for the exported method declared in the interface Hello and that does the object binding: import java.rmi.Naming; import java.rmi.RMISecurityManager; public class HelloServer { public static void main(String args[]) { String host = "localhost"; String port = (args.length >= 1 ? args[0] : "1099"); System.out.println("Using port number " + port); // (must do) Create and install a topic7.doc Page 10 ICT337 Advanced Software Development Murdoch University Topic 7 // security manager if (System.getSecurityManager() == null) System.setSecurityManager( new RMISecurityManager()); try { // create a HelloImpl object so that // the method sayHello() can be accessed // via the object handle. HelloImpl obj = new HelloImpl(); // Bind this object instance to the // name "Hi" and register it to the // registry Naming.rebind("//" + host + ":" + port + "/Hi", obj); The HelloImpl object (obj) is bound to the registry with the name “Hi” System.out.println("The name Hi bound in registry"); } catch (Exception e) { System.out.println("HelloImpl err: " + e.getMessage()); e.printStackTrace(); } } } Because the server is opening up an interface to its objects and allowing programs on other systems to access these objects, for security reason, the server program should check if a SecurityManager has been installed and install it if one has not been installed. Each server object will be registered on the RMI registry under some name. The client program should refer to each server object using the associated name. If topic7.doc Page 11 ICT337 Advanced Software Development Murdoch University Topic 7 the registered name of a server object was HelloObj then, to access this server object, the client should refer to //host:port/HelloObj where host is the host address and port is the port number used. STEP 5: Write a client program that uses the remote service. Below is the code for an applet: import import import import java.applet.Applet; java.awt.Graphics; java.rmi.Naming; java.rmi.RemoteException; public class HelloApplet extends Applet { String message = "blank"; // "obj" is the identifier that we'll use to // refer to the remote object that implements // the "Hello" interface Hello obj = null; downcasting public void init() { try { The client obj = (Hello)Naming.lookup("//" + must look up getCodeBase().getHost() + the "/Hi"); HelloImpl // *** remote method call *** object via the message = obj.sayHello(); same name that has been } catch (Exception e) { registered by System.out.println( the server "HelloApplet exception: " + e.getMessage()); e.printStackTrace(); } topic7.doc Page 12 ICT337 Advanced Software Development Murdoch University Topic 7 } // repaint the screen public void paint(Graphics g) { g.drawString(message, 25, 50); } } The HTML file to encapsulate the applet is simply <HTML> <title>Hello World</title> <center> <h1>Hello World</h1> </center> <applet codebase="./" code="HelloApplet" width=450 height=120> </applet> </HTML> NOTE: the applet must be accessible from the directory given by the codebase parameter value For the same security reason, a SecurityManager should be installed if one has not been installed on the client side. Step 6: Compiling and running o compile Hello.java and HelloImpl.java o create the Stub from the HelloImpl class file via rmic o compile the server and the client applet o open 3 separate MS-DOS prompt windows: topic7.doc Page 13 ICT337 Advanced Software Development Murdoch University Topic 7 in the first window, start the registry using the command: rmiregistry The command rmiregistry port starts a remote object registry on the specified port on the current host. Default port number is 1099. must be run in order for the RMI server(s) to register names of objects. rmiregistry in the second window, start the server program that will construct a HelloImpl object and register it. Two additional parameters must be supplied to the JVM in order for RMI to run: 1. a parameter that specifies the codebase from which the stub and skeleton files will be made available, eg. if these files are in the current directory and the class files are not put in a package then use: -Djava.rmi.server.codebase=file:./ 2. a parameter that specifies the file in which the user security policy for the program is located, eg. if the file is named policy in the current directory then use: -Djava.security.policy=policy topic7.doc Page 14 ICT337 Advanced Software Development Murdoch University Topic 7 The contents of the policy file are: grant { permission java.net.SocketPermission ”*:1024-65535”, ”connect,accept”; } which grants code loaded over the network the permission to listen and connect on sockets with port numbers from 1024 and 65535. NOTE: port 1 to port 1023 are reserved ports. Alternatively, the contents of the policy file could be grant { permission java.security.AllPermission; } no space which grants all permissions. before and after “=” So, to start the server, type: java –Djava.rmi.server.codebase=file:./ -Djava.security.policy=policy HelloServer in the third window, start the client applet by typing: appletviewer Hello.html or passing the URL (if one been set up) to a web browser: http://www.it.murdoch.edu.au/ ~mark/ICT337/rmi/hello/Hello.html topic7.doc Page 15 ICT337 Advanced Software Development Murdoch University Topic 7 if the class files have been placed in Mark’s public_html directory and if rmiregistry and HelloServer are both running on the web server dijkstra. The Hello example above assumes that both the client and server are on the same machine (thus the use of localhost). When the server is a remote host, the client must know the host (or IP) address and the port number used If the client program is an application rather than an applet provided by the server, then some class files of the server must be accessible by the client either via the class path or via a prior download, eg. if a HelloClient.java application was used on the client side, the files Hello.class and HelloImpl_Stub.class would be required to compile (javac) and run (java) HelloClient.java. Parameters in RMI In the normal Java context, parameters in RMI are pass-byvalue as you cannot change the value of the passed parameter. Parameter passing in RMI has a different meaning. All parameters will be passed by value, but in RMI the definitions of parameter passing are given below. RMI Parameter Passing topic7.doc Page 16 ICT337 Advanced Software Development Murdoch University Topic 7 RMI Pass-by-value The actual parameter is serialized and passed using a network protocol to the target remote object. Serialization essentially "squeezes" the data out of an object/primitive. On the receiving end, that data is used to build a "clone" of the original object or primitive. Note that this process can be rather expensive if the actual parameters point to large objects (or large graphs of objects). RMI Pass-by-reference The actual parameter, which is itself a remote object, is represented by a proxy. The proxy keeps track of where the actual parameter lives, and anytime the target method uses the formal parameter, another remote method invocation occurs to "call back" to the actual parameter. This can be useful if the actual parameter points to a large object (or graph of objects) and there are few call backs. Example 2: Parameter passing example //simple test oject------------------------------------------------import java.io.Serializable; public class myObject implements Serializable { int size; topic7.doc Page 17 ICT337 Advanced Software Development Murdoch University Topic 7 String name; public myObject() { size=10; name="Your mother"; } public myObject(int s, String n) { size=s; name=n; } public java.lang.String getName() { return name; } public void setName(java.lang.String name) { this.name = name; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public void output() { System.out.println("size= "+size+", name= "+name); } } //the interface------------------------------------------------------- topic7.doc Page 18 ICT337 Advanced Software Development Murdoch University Topic 7 import java.rmi.Remote; import java.rmi.RemoteException; public interface objectParams extends Remote { public myObject returnNewObject(myObject the)throws RemoteException ; public void modObject(myObject the) throws RemoteException; } //the interface implementation--------------------------------------------import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class myObjectImpl extends UnicastRemoteObject implements objectParams { public myObjectImpl() throws RemoteException { super(); } public myObject returnNewObject(myObject the) throws RemoteException { myObject newOj=new myObject(the.getSize(), the.getName()); newOj.setName("My mother"); return newOj; } public void modObject(myObject the) throws RemoteException { the.setName("My mother"); } } topic7.doc Page 19 ICT337 Advanced Software Development Murdoch University Topic 7 //the RMI Server --------------------------------------------import java.rmi.Naming; import java.rmi.RMISecurityManager; public class myObjectServer { public static void main(String args[]) { /* if (System.getSecurityManager() == null) System.setSecurityManager( new RMISecurityManager());*/ try { myObjectImpl mo= new myObjectImpl(); Naming.rebind("rmi://localhost/params", mo); System.out.println("paramsServer is now running..."); } catch (Exception e) { System.out.println("params err: " + e.getMessage()); e.printStackTrace(); } } } import java.rmi.Naming; public class myObjectClient { //the RMI Client --------------------------------------------public static void main(String args[]) { String rmiUrl="rmi://localhost/params"; try{ objectParams h=(objectParams)Naming.lookup(rmiUrl); myObject m=new myObject(); myObject n=h.returnNewObject(m); topic7.doc Page 20 ICT337 Advanced Software Development Murdoch University Topic 7 System.out.println("original:" +m); m.output(); System.out.println("new" +n); n.output(); //test pass by reference h.modObject(m); m.output(); } catch(Exception e) { e.printStackTrace(); } } } Run the Client and you will see that it will not change the value of the parameter passed to the server. The pass-by-value feature is useful only for very large objects where serializing the whole object would involve too much overhead. To support pass-by-reference RMI parameters, make your server implement your interface. I.e. to make myObjectServer support pass-by-reference change – public class myObjectServer { to public class myObjectServer implements objectParams{ Example 3 topic7.doc Page 21 ICT337 Advanced Software Development Murdoch University Topic 7 See the example in the pub/units/ICT337/Resources/DeitelCD/examples/Ch apters/ch13/WeatherService folder, or the corresponding folder on the textbook cd. Note that the interface TemperatureServer.class and the stub file TemperatureServerImpl_Stub.class must be accessible (via CLASSPATH) to the client program Bidirectional messaging Clients can register themselves with the server so that the server can call back to each client (e.g. via a hash table containing a list of registered clients kept by the server). See the WeatherService example. (Optional) Compare the example with that (more complicated) given in fig. 13.1- fig. 13.7 of the textbook. topic7.doc Page 22 ICT337 Advanced Software Development Murdoch University Topic 7 PITFALL It appears that the rmiregistry program must be invoked at the same directory where the server(s) would be started. This suggests that one should arrange each RMI server program into a package, eg. use the following directory structure: rmi_1 src rmi_2 put Java files here ... c:\ICT3 37 classes rmi_1 put class files here rmi_2 and at the beginning of each source Java file of the src\rmi_1 directory (say), put the line package classes.rmi_1; The source files should then be compiled at the root directory c:\ICT337. The rmiregistry utility can be invoked at the c:\ICT337 directory. All the servers can then be started at the same topic7.doc Page 23 ICT337 Advanced Software Development Murdoch University c:\ICT337 Topic 7 directory. This would allow multiple rmi servers to share the same registry. The client needs to know the server object names registered in the registry. It also needs to know the type of each server object (for downcasting). Note that the rmiregistry program can be running several times simultaneously. Each rmiregistry program can be using its own, different port number. For examples on using packages, see files in the hello2 folder. Note also the difference in the makefile. The student folder contains a more complicated example Invalid codebase parameter value and absence of the policy file are two common errors encountered in running RMI. when two different objects (from same or different servers) are registered with the same name in the registry, the latest registration overwrites the earlier one (should perhaps call the bind method instead of rebind to detect duplicated registrations). NOTE: topic7.doc Page 24 ICT337 Advanced Software Development Murdoch University Topic 7 multiple rmi servers sharing the same registry must use the same port. If a different port is desired, then another rmiregistry program with the chosen port number specified must be invoked (recall that default port number is 1099), eg rmiregistery 2001 starts the registry on port 2001 RMI and firewalls By default, RMI makes direct connections from the client to the server. Unless the firewall is configured to permit arbitrary connections (a pretty bad firewall), it will not allow default RMI to work. Since users inside the firewall often want to browse the web outside the firewall using HTTP, most firewalls are configured to allow HTTP requests. Configuration involves setting up a proxy server for a specified port. Remote object activation Rather than having a server running at all time (that has objects registered) to allow client connection, remote object activation (introduced in Java 2) supports the topic7.doc Page 25 ICT337 Advanced Software Development Murdoch University Topic 7 creation of instances of remote objects that can be accessed by the server. This is a great improvement in performance. Remote object activation is managed by a small program called rmid that runs on the server. When a client requests a service, rmid starts the remote object and communication proceeds normally. This allows many services to consume processing time only when the services are actually requested. JNDI The rmiregistry program is useful for small applications but does not scale well when applications are large and spread across many host systems. JNDI (Java Naming and Directory Interface) is a standard Java platform extension. It is a unified interface to multiple naming and directory services that already exist for enterprise development. JNDI classes are in the packages: javax.naming, javax.naming.directory, javax.naming.spi Java IDL and CORBA topic7.doc Page 26 ICT337 Advanced Software Development Murdoch University Topic 7 Java RMI provides support that makes it easy to define and use remote objects, but it only works with remote objects that are developed using the Java programming language. CORBA (Common Object Request Broker Architecture) is a more generic architecture for defining and using remote objects. It allows for the mixing of objects developed using different programming languages. Similarities between RMI and CORBA: the concepts of stubs, skeletons, and ORBs Two significant differences between RMI and CORBA: 1. the way in which the ORBs communicate with each other. o RMI ORBs use a protocol called the JRMP (Java Remote Method Protocol) o CORBA ORBs use a protocol called the IIOP (Internet Inter-ORB Protocol), which is based on the standard TCP/IP protocol. Thus, RMI ORBs and CORBA ORBs cannot communicate with each other. 2. the interfaces of CORBA objects are defined using a special language called IDL (Interface Definition Language). The idlj utility that comes with jdk1.4 makes it easy to generate Java interfaces and stub and skeleton classes. topic7.doc Page 27 ICT337 Advanced Software Development Murdoch University Topic 7 CORBA will be covered in more detail in a later topic. topic7.doc Page 28 ICT337 Advanced Software Development Murdoch University Topic 7 Further reading: (textbook) “Advanced Java 2 Platform – How to Program” by Deitel, Deitel, Santry, chapter 13, sections 13.1 – sections 13.5. (Optional) See also the case study given in section 13.6. JDK rmi tools: rmic, rmiregistry c:/jdk1.3/docs/tooldocs/tools.html#rmi JDK rmi tutorial: c:/jdk1.3/docs/guide/rmi/getstart.doc.html topic7.doc Page 29 ICT337 Advanced Software Development Murdoch University Topic 7 Objectives At the end of this topic, you should be able to describe the notions of client/server distributed computing describe the architecture of RMI describe the notion of stubs use RMI to develop classes of objects that are accessible from a server compile and deploy a client/server distributed application that uses RMI understand the use of JNDI and its related packages discover the relationship between RMI and the Java Interface Definition Language (IDL) topic7.doc Page 30