What is RMI architecture

Java in Distributed Systems - RMI


1 In this part of the course Module 2: Remote Method Invocation RMI Module Introduction What is Java RMI? RMI Architecture Overview The Transport Layer Garbage Collection Remote Reference Layer RMI Stubs and Skeletons RMI Packages and Hierarchies Creating an RMI Application RMI Security Remote Method Invocation Practical Exercise Quiz Summary Java in Distributed Systems - RMI 1.1. Module 2: Remote Method Invocation (RMI) Introduction The Remote Method Invocation (RMI) API allows the Java developer to write programs that access remote objects, just as if these objects were local. Analogous to the so-called Remote Procedure Calls (RPC), RMI abstracts the socket connection and the data conversions that are required for communication with a remote computer. In this way, remote method calls are made in exactly the same way as local method calls. Learning objectives After working through these documents, you should be able to: Describe the RMI architecture, including its various layers and the (distributed) garbage collector. Implement RMI servers and clients in Java. Generate client stubies and skeletons for remote services with the help of the stub compiler. Describe how the RMI registry works. to develop an RMI application to solve a specific distributed task References Parts of this module come partly or completely from "The Java Remote Method Invocation Specification" "Java RMI Tutorial" "Frequently Asked Questions, RMI and Object Serialization" 1/37

2 What is Java RMI? The RMI API consists of a set of classes and interfaces with which the developer can call methods of remote objects, i.e. methods of objects that are located in another Java virtual machine at runtime. This "remote" or "server" JVM can be on the same or different machines as the RMI client. In contrast to RPC, Java RMI is a pure Java solution. In this module you will learn how to write RMI interfaces that will be used by client code. and what RMI implementation classes look like with which objects are instantiated on the server. With the help of the RMI interface descriptions, stubs (client-side code) and skeletons (server-side code) are generated with the help of the rmic, the RMI compiler. In distributed systems, sophisticated failure and recovery mechanisms for distributed programs are very important, simply because there are many more failure modes. In this module you will get to know some of these Java RMI-defined exception types, together with information on how you should use them in your programs on the client side to the transport layer, then transported to the server and finally forwarded several layers up to the server object. This is shown schematically in the picture above (from the RMI documentation). The whole thing still sounds very complex. How does this transport happen and which layers are there? 2/37

3 As a developer, you are only responsible for defining the interfaces and the implementation classes and generating the stub and skeleton classes (with the help of rmic). The Remote Reference Layer (RRL) and the Transport Layer take care of the rest. These layers could even change from release to release without your application programs being affected. Stubs and skeleton, the Java programs that are created on the basis of our interface definitions (whereby skeletons are no longer required in newer releases), are, so to speak, the interface to the application program and the reference layer. The reference layer is necessary because references in one JVM must be mapped to references in a possibly distant JVM. The Transport Layer First, let's take a look at how the Transport Layer works. The transport layer is responsible for establishing the connection, managing the connection and tracking and managing the remote objects (the target objects of the remote calls) in the address space. The transport layer has the following tasks: It receives a request from the remote reference layer on the client side. it locates the RMI server which contains the requested remote object. it establishes a socket connection to this server. it delivers this connection / connection information to the client-side remote reference layer. it enters the remote object in a table containing remote objects that can be communicated with. it monitors the "liveness" of this connection. The client itself cannot terminate a connection to an RMI server. This is one of the tasks of the transport layer. 3/37

4 socket connections Currently, Java RMI only supports TCP sockets. RMI typically uses two socket connections: one for method calls and one for Distributed Garbage Collection (DGC). RMI will try to use existing socket connections multiple times, for several objects from the same server. However, if a socket connection is busy, a new socket connection will be established automatically. A remote object consists of a server endpoint and an object identifier. This is called a live reference. With a given live reference, the transport can use the endpoint information to establish a connection to the address space in which the remote object is present. On the server side, the transport can use the object identifier to find the target of the remote call. The transport layer for the RMI system consists of the following four abstractions: endpoint channel endpoint transport sockets the connection is used to transfer data (input / output). For each connection there is a communication channel, at least two end points, plus a transport. an endpoint describes an address space or Java virtual machine. An end point can be mapped onto its transport. With a given end point, a specific transport instance can be determined. a channel is used as a virtual connection between two address spaces. The channel is responsible for managing the connections between the local address space and the remote address space. a transport is responsible for the management of a specific channel. The channel defines what the actual representation of the end point looks like. There is exactly one transport per address space pair or pair of end points. Given a given end point to a remote address space, a transport establishes a channel between itself and this address space. The transport is also responsible for accepting incoming requests to this address space. A connection object is created for this request and communicated with the higher layers. 4/37

5 Garbage Collection RMI uses a reference counting garbage collection. All live references within each JVM are taken into account. Whenever a live reference enters a JVM, its reference counter is incremented by one. If an object no longer has any references, the object finalization (finalizer) reduces the reference counter. If all references have been resolved, an "unreferenced" message is sent to the server. If a remote object is no longer referenced by any client, this is called a 'weak reference'. A weak reference allows the server garbage collector to delete the object if there is no other (local) reference to this object. As long as local references exist, the remote object cannot be regarded as garbage. It could also be used as a parameter or as a return of a remote call. The Garbage Collection Process The following figure illustrates the five-stage Distributed Garbage Collecton process. 1) Creation and launch of an object by the server or the implementation. 2) The remote reference establishes a 'weak reference' to the object. 3) If the client requests this object, the client JVM creates a 'live reference' and the first reference to this object sends a 'Referenced' message to the server. 4) As soon as the object is no longer needed on the client, the client sends an 'Unreferenced' message to the server 5) If the reference counter on the object goes back to zero and there are no local references, the object reference can be sent to the local GC ( garbage collector). The DGC takes care of it; it is part of the RMI runtime system, especially the transport layer. 5/37

6 Distributed Garbage Collection - Step 1 Creation and start of an object by the server or the implementation Distributed Garbage Collection - Step 2 The remote reference establishes a 'weak reference' to the object. 6/37

7 Distributed Garbage Collection - Step 3 If the client requests this object, the Client JVM creates a 'live reference' and the first reference to this object sends a 'Referenced' message to the Distributed Garbage Collection server - Step 4 as soon as the object is on the client is no longer required, the client sends an 'unreferenced' message to the server 7/37

8 Distributed Garbage Collection - Step 4 If the reference counter on the object goes back to zero and there are no local references, the object reference can be reported to the local GC (garbage collector) 8/37

9 Remote Reference Layer The Remote Reference Layer (RRL) is responsible for the correct semantics of the method calls. This layer communicates between the stubs / skeletons and the underlying transport interface. A special remote reference protocol is used for this, which is independent of the client stub and server skeletons. The tasks of the RRL also include the management of references to remote objects and the establishment of a reconnection if an object should no longer be available. RRL has two cooperating components: the client side and the server side. The client-side component contains specific information about the remote server and communicates with the server-side component using the transport layer. The server-side component implements the specific reference semantics before a remote method call is passed to the skeleton. The reference semantics for the server are also dealt with by the RRL. RRL abstracts the different ways in which an object is referenced, which are implemented on servers which run continuously on a machine. run on servers that are only activated if a remote method is activated on them (with the activation interface). These differences are not visible above the RRL. 9/37

10 RMI stubs and skeletons The stub / skeleton layer is the interface between the applications, the application layer, and the rest of the RMI system. So this layer does not take care of the transport; it only provides data to the RRL. A client that calls a method on a remote server actually uses a stub or a proxy object for the remote object, i.e. a quasi replacement for the remote object. A skeleton for a remote object is the server-side size that forwards the method calls to the remote object implementation. The stubs communicate with the client-side RRL in the following way: The stub (client-side) receives the call of a remote method and initializes a call, a connection to the remote object. The RRL provides a special type of I / O stream, a 'marshal' (input / output) stream, which is used to communicate with the server side of the RRL. The stub makes the call to the remote method and passes all arguments to that stream. The RRL delivers the return values ​​of the method to the stub. The stub confirms to the RRL that the method call is complete and completed. Skeletons communicate with the server-side RRL in the following way: The skeleton 'unmarshal' (receives and interprets) all arguments from the I / O stream that was established by the RRL. The skeleton calls the current remote object implementation. The skeleton 'marshals' (interprets and sends) the return values ​​of the method call (or an exception, if one was thrown) into the I / O stream. Note Beware of distributed deadlocks. These can occur, for example, if you try to synchronize program code blocks of a remote object. If you have set a lock on an object in a distributed application, there is no longer any way to distinguish whether the lock originates from a certain object or some other object. In the worst case, the lock can remain in place forever. Stub and skeleton are generated automatically depending on the Java version. In older versions, these must be generated using the RMI compiler (rmic helper program under% JAVA_HOME% \ bin). 10/37

11 RMI packages and hierarchies java.rmi packages The basic packages, classes and interfaces that are used to develop RMI clients and servers are: Naming This class is the final class that the RMI clients and servers use to communicate with the server registry . The server application uses the bind and rebind methods to register its object implementations with the registry (hence the name of this lookup server 'Registry'). The client application uses the lookup method of this class to get a reference to the remote object. Remote Interface This interface must be extended by all client interfaces that want to access the remote object. RemoteException This exception must be thrown by every method that is defined in a remote interface and implementation class. All clients must catch this exception. RMISecurityManager This controls access to local and remote applications through RMI classes and interfaces. 11/37

12 The java.rmi.dgc package The java.rmi.dgc package contains classes that are required to implement remote garbage collection. 12/37

13 The java.rmi.server Package From the multitude of classes, let's take a closer look at two: RMIClassLoader The RMI class loader is the class loader with which the stubs and skeletons of the remote objects (as well as arguments and return values ​​of remote methods) are loaded. If the RMIClassLoader tries to load classes from the network, an exception is thrown if no Security Manager has been installed. UnicastRemoteObject The unicast remote object is the upper class for all RMI implementation classes. 13/37

14 applet awt net beans io rmi lang math security sql text util activation dgc registry server 14/37

15 Overview of the RMI Package 15/37

16 Excerpt from the RMI Server Package 16/37

17 Creating an RMI Application The following example uses a bank account and a (bank) account manager to illustrate how RMI can be used. So a bank is involved, with which you can open an account. The accounts are managed by an account manager, an employee of the bank. After opening an account, you can deposit funds, withdraw funds and check the account balance. If you want to solve this problem with RMI, you could define two interfaces: bank account.java package rmi.bank; interface bank account extends Remote {public float query account balance (); public void withdraw (float amount); Pay in public void (float amount); Account Manager.java package rmi.bank; interface account manager extends Remote {open public account (string name, float start capital); Note These interfaces are defined in such a way that you can only open an account with the help of the account manager. You will receive an account (object) from the account manager (object). The account manager provides you with a current instance of an account, if one already exists. This way of creating objects is an example of the use of a particular 'design pattern' in object-oriented programming methodology. This pattern is known as the factory method. The factory method allows one object to create other objects. In our case, that is exactly what we need. The account manager controls the creation of a new account. If you would like to go to a bank and open a new account, you should be informed whether you already have an account with this bank (and if so, which one). 17/37

18 Process for creating an RMI application To create a remotely available application in RMI, proceed as follows: 1. Define the remote objects to be worked with as Java interfaces. 2. Create implementation classes for the interfaces. 3. Compile interfaces and implementation classes. 4. Create stub and skeleton classes using the rmic command applied to the implementation classes. Caution: with CORBA or some other techniques, you must first compile the interface description and then create the implementation classes (and incorporate the generated program code). 5. Create a server application that administrates the remote objects and compile the server application. 6. Start the RMIregistry (or build it yourself as part of the server application: in this case, this step is not necessary). 7. Test the client.The complete example of our problem looks like this: The account interface package bank account; import java.rmi.remote; import java.rmi.remoteexception; / ** * Definition of the methods for our bank account * check the account balance * deposit a certain amount * withdraw a certain amount * / public interface account extends Remote {/ ** * inquire about the account balance: returns the account balance as a float * / public abstract float account balance () throws RemoteException; / ** * Pay in a (float) amount f to the account * / Pay in public abstract void (float f) throws invalid amount exception, RemoteException; / ** * withdraw a (float) amount f from the account * / public abstract void withdraw (float f) throws invalid amount exception, RemoteException; 18/37

19 Our account interface must extend java.rmi.remote and be declared as public in order to be available remotely (for clients in other virtual machines). Note All methods throw the java.rmi.remoteexception. This exception is thrown whenever a problem occurs when calling a method of a remote object. The methods deposit (...) and withdraw (...) also throw an invalid amount exception if a negative amount is to be deposited or more money is to be withdrawn than is in the account. Every method in a remote interface must throw at least one RemoteException (not a subclass of RemoteException). This is checked by rmic. The Account Manager Interface The complete Account Manager Interface looks like this: package bank account; / ** * The account manager creates (on behalf of, as an object factory) a * new account for a customer * Parameters: customer name and starting amount. * / import java.rmi.remote; import java.rmi.remoteexception; public interface AccountManager extends Remote {/ ** * open an account for the customer s with initial balance f * / public abstract open account (string s, float f) throws invalid amount exception, RemoteException; Arguments or return values ​​of a remote method can be of any Java data type, including objects, as long as these objects are either serializable or externalizable (in the case of an Externalizable class, the object serialization delegates control over the external format and the way in which the supertypes are stored and be restored completely to the object). This interface also extends java.rmi.remote and the method open (...) can throw the exception RemoteException (plus invalid amount exception if the initial amount is negative). 19/37

20 The account interface is implemented by a class which implements all of its methods and extends UnicastRemoteObject. A naming convention has become established here: all classes that implement interfaces take on the name of the interface plus the addition "Impl". // Account Impl - implementation of the account interface // // Instances of this class implement the methods: // account balance, withdraw, deposit // which were defined in the account interface package bank account; import java.rmi. *; import java.rmi.server.unicastremoteobject; public class accountImpl extends UnicastRemoteObject implements account {// current account balance private float account balance = 0; // open a new account: constructor public AccountImpl (float new account balance) throws RemoteException {System.out.println ("AccountImpl: Constructor"); account balance = new account balance; // Methods // Query account balance public float kontostand () throws RemoteException {System.out.println ("AccountImpl.kontostand (): query account balance; account balance =" + account balance); return balance; // Pay in amount, if amount is positive public void pay in (float amount) throws invalid amount exception, RemoteException {System.out.println ("AccountImpl.inpay (): Pay in amount;"); System.out.println ("AccountImpl: Account balance old:" + account balance); if (amount <0) {throw new invalid amount exception ("error: trying to pay in a negative amount!"); else {account balance = account balance + amount; System.out.println ("AccountImpl.inpay (): New account balance:" + account balance); // Withdraw amount, if the account has it public void withdraw (float amount) throws invalid amount exception, RemoteException {System.out.println ("AccountImpl.drawal (): withdraw amount; amount =" + amount + "account balance old:" + account balance ); System.out.println ("Account Impl. Withdraw (): account balance old:" + account balance); if (amount <0) {throw new invalid amount exception ("account impl.draw () error: attempt to withdraw a negative amount!"); else {if ((account balance - amount) <0) {throw new invalid amount exception ("account impl. withdraw () error: attempt to overdraw account!"); else {account balance = account balance - amount; System.out.println ("Account Impl.draw (): New account balance:" + account balance); 20/37

21 The account manager is implemented by a class which is able to create new accounts and to save or manage the accounts. Specifically, the account manager uses a vector as a memory. The objects are created with the help of an Account Info class. This class is purely an auxiliary class! It is also used to quickly search for existing accounts. package bank account; / ** * The account manager creates (on behalf of, as an object factory) a * new account for a customer * Parameters: customer name and starting amount. * / import java.io.printstream; import java.rmi.remoteexception; import java.rmi.server.unicastremoteobject; import java.util.vector; public class AccountManagerImpl extends UnicastRemoteObject implements AccountManager {private static Vector accounts = new Vector (); public AccountManagerImpl () throws RemoteException {System.out.println ("AccountManager: Constructor"); Open public account (string name, float start capital) throws RemoteException, invalid amount exception {System.out.println ("AccountManager.eropen (): Start capital =" + start capital); Account Info a; for (int i = 0; i

22 package bank account; // Container class for managing the accounts class AccountInfo {String name; AccountImpl account = null; The class path is one of the sticking points for distributed Java applications! You should consider using the -d option when compiling Java programs in order to clearly localize the class files. In our examples, the BAT files are therefore usually specified explicitly and the CLASSPATH is also destroyed (set to empty): javac -d. * .java The package directories are also created with this flag. This is solved differently in the BAT files. After you have implemented the interfaces, you have to create stubs and skeletons if your Java version is older than 1.5. These classes are used to access the respective remote objects. The generation is done with the help of the rmic, the RMI compiler. This happens after the implementations have been written, but before the server application is started. rmic options Package.InterfaceImpl ... Go to off cd .. echo RMI Compile bank account.KontoImpl rmic -classpath. -keep bank account.KontoImpl echo RMI Compile bank account.KontoManagerImpl rmic -classpath. -keep bank account.KontoManagerImpl cd bank account echo Create an archive (bank account.jar) jar cvf bank account.jar * _ *. class copy bank account.jar .. \ *. * echo The archive (bank account.jar) is in the banks and directories Bank account pause The RMI compiler creates four additional files (with the keep option these remain available): AccountImpl_Skel.java AccountImpl_Stub.java AccountManagerImpl_Skel.java AccountManagerImpl_Stub.java Note If you change an implementation class, you have to recompile it, the RMI compiler has to stubs and Regenerate skeletons, the registry has to be stopped and restarted and the server too. 22/37

23 The bank server (BankServer.java) is an application that instantiates the account manager implementation class (AccountManagerImpl.java) in response to customer inquiries and makes it available to the client. 1. // Bank Server - class which represents the RMI server 2. // 3. package Bank; 4. import java.rmi. *; 5. import bank account. *; 6. public class BankServer {7. public static void main (string args []) {8. System.out.println ("BankServer: start and set the SecurityManager"); 9. // create and install a SecurityManager 10. //System.setSecurityManager(new RMISecurityManager ()); 11. try {12. // Instances: objects which are registered 13. System.out.println ("BankServer.main (): create an AccountImpl object"); 14. AccountManagerImpl kmi = new AccountManagerImpl (); 15. // bind the instance to the registry 16. System.out.println ("BankServer.main (): bind the account manager to the bank server [registry] r"); 17. // for testing: query the registry 18. for (int i = 0; i

24 Exception java.rmi.alreadyboundexception is thrown if the object is already registered. The argument for bind and rebind are URL-like strings and the name of the instance of the object implementation (see above for an example). The format of the URL string is: rmi: // host: port / name where: rmi is the protocol, host is the name of the RMI server (DNS notation), port is the port number on which the server waits for requests, name is the exact name that the client must use in the Naming.lookup call if it needs this object. If the protocol is not specified, the standard value is rmi, for host the standard value is localhost and for port For security reasons, an application can only be linked to a registry that runs locally on the same computer. The RMIRegistry is an application that provides a simple name lookup service. In our example, the application provides the RMI registry with a name and an object reference. As you saw above, the program consists of a few lines. If you integrate the registry into the server, the RMI registry consists of exactly one line. The RMI registry also provides information about references to the garbage collector. The rmiregistry program must run before the server is started and tries to bind its remote objects: rmiregistry java -classpath. -Djava.security.policy = java.policy Bank.BankServer Possible options for rmiregistry: Port or Sun Options: rmiregistry -J-Dsun.rmi.loader.logLevel = VERBOSE Note On the Win32 platform you can also start the registry with start rmiregistry . Look at the syntax in a DOS window. This gives you a few options with regard to priorities, closing the DOS window, etc. 24/37