`
gaofen100
  • 浏览: 1227689 次
文章分类
社区版块
存档分类
最新评论

Introduction to Java Remote Method Invocation (RMI)

 
阅读更多

Introduction to Java Remote Method Invocation (RMI)

What is this course about:

  • the basics of Java RMI (e.g., layers, rmic, registry, etc.) and how to apply and use it to develop distributed computing applications through examples.
Introduction
  • Java RMI is shipped with the Java JDK 1.4.
  • It is a true distributed computing application interface for Java. Unlike other distributed programming interfaces (e.g., Corba, etc.), Java RMI is language specific. This is a good thing because by being language specific, RMI has the ability to provide more advanced feature like serialization, security, etc.
How RMI works
  • RMI uses a network-based registry to keep track of the distributed objects. The server object makes a method available for remote invocation by binding it to a name in the registry. The client object, in turn, can check for availability of an object by looking up its name in the registry . The registry acts as a limited central management point for RMI . The registry is simply a name repository . It does not address the problem of actually invoking the remote method.
  • The two objects may physically reside on different machines. A mechanism is needed to transmit the client's request to invoke a method on the server object to the server object and provide a response. RMI uses an approach similar to RPC in this regard. The code for the server object must be processed by an RMI compiler called rmic, which is part of the JDK.
  • The rmic compiler generates two files: a stub and a skeleton. The stub resides on the client machine and the skeleton resides on the server machine. The stub and skeleton are comprised of Java code that provides the necessary link between the two objects.
  • When a client invokes a server method, the JVM looks at the stub to do type checking (since the class defined within the stub is an image of the server class). The request is then routed to the skeleton on the server, which in turn calls the appropriate method on the server object. In other words, the stub acts as a proxy to the skeleton and the skeleton is a proxy to the actual remote method.
  • The first layer is the Stub/Skeleton Layer. This layer is responsible for managing the remote object interface between the client and server.
  • The second layer is the Remote Reference Layer (RRL). This layer is responsible for managing the "liveliness" of the remote objects. It also manages the communication between the client/server and virtual machines, (e.g., threading, garbage collection, etc.) for remote objects.
  • The third layer is the Transport Layer. This is the actual network/communication layer that is used to send the information between the client and server over the wire. It is currently TCP/IP based.
The example

The example used in this article is an amortization schedule application. The client requests a local schedule object from the server through a remote object and passes an amount and duration of a loan to the server. The server instantiates a local schedule object with the amount and duration along with the interest rate the server knows about. Then the schedule object is serialized and returned back to the client. The client can then print the object or modify it at this point. The client has its own private copy of the schedule object.
Below is an illustration that serves as a reference for the parts of the RMI application.

Creating the Interface Definition File

  • The first thing that you must do to develop an RMI application is to define the remote interface. The interface defines what remote methods/variables are going to be exported from the remote object. Usually the interface defines methods only because variables have to be declared final (i.e., constant) if they are in an interface definition.
  • The remote interface mathCalc.java needs to import the RMI package, and every exported method must throw an RMI remote exception to manage errors during invocation. Below is the code for the mathCalc.java interface definition file in our example.
 /****************************************************
 * module: mathCalc.java
 ****************************************************/
 import java.lang.*;
 import java.rmi.*;

 public interface mathCalc extends java.rmi.Remote
 {
 public schedule amortizeSchedule( float ammount,
 int duration ) throws
 java.rmi.RemoteException;
 public void printRate() throws java.rmi.RemoteException;
 }
  • If you are familiar with using Java and interfaces, converting your local objects to remote objects can be done very quickly with minor modifications to your source. You need only to include the Java RMI package and manage RMI remote exceptions on all your exported local methods.

Creating the Interface Implementation File

  • Once the interface definition file is created, you need to define the actual code that supports the interface on the server . Below is an example of the mathCalcImp.java interface implementation file used to provide that support.
 /****************************************************
 * module: mathCalcImp.java
 ****************************************************/
 import java.rmi.*;
 import java.rmi.server.*;

 class mathCalcImp extends UnicastRemoteObject implements mathCalc
 {
 float interestRate = (float)7.5;

 mathCalcImp() throws java.rmi.RemoteException
 {
 }

 public schedule amortizeSchedule( float ammount, int duration ) throws
 java.rmi.RemoteException
 {
 System.out.println("Amortizeing Schedule.");
 // return a locally created server object to the client
 return( new schedule( interestRate, ammount, duration ) );
 }

 public void printRate() throws java.rmi.RemoteException
 {
 System.out.println("Current Interest Rate is " + interestRate );
 }
 }
  • Notice the implementation file imports the package java.rmi.* . It also imports the java.rmi.server.* package. This is so you can extend the UnicastRemoteObject class to support remote clients. This class manages client/server and peer/peer connection support for RMI.
  • Today there is no MulticastRemoteObject class. There is, however, enough support in JDK 1.3 to allow you to write your own MulticastRemoteObject class to support multicast remote clients with the Factory Pattern which we will discuss in a subsequent course (see also here ).
  • You can also create an activatable object, by extending java.rmi.activation.Activatable instead of the UnicastRemoteObject class. A remote object can be accessed "on demand", i.e. the server is started on "demand", rather than running all the time. We will discuss this issue in the next course.
  • Notice how the file defined above implements mathCalc, the remote interface definition that was defined earlier. Each method in the implementation file that is going to be externalized needs to throw a remote exception.

Object Serialization

  • The amortizeSchedule() method prints a message on the server and instantiates a new local schedule object that is returned to the client (out parameter). The schedule object is a local object to the server that will be serialized and marshaled into a data stream to be sent back to the client.
  • Now is a good time to discuss the serialization of remote objects. To begin that discussion, the schedule.java.local class is presented below.
 /****************************************************
 * module: schedule.java
 ****************************************************/
 import java.lang.*;
 import java.util.*;
 import java.io.*;

 class schedule implements Serializable
 {
 float totalLoanAmt;
 float usrAmmount;
 float interestRate;
 int loanDuration;

 schedule( float rate, float ammount, int duration )
 {
 interestRate = rate;
 usrAmmount = ammount;
 loanDuration = duration;
 totalLoanAmt = ammount + (ammount / rate);
 }

 void print()
 {
 System.out.println("Schedule Created.");
 System.out.println("Calculation information based on:");
 System.out.println(" Rate [%" + interestRate + "]" );
 System.out.println(" Ammount [___FCKpd___3quot; + usrAmmount + "]" );
 System.out.println(" Duration [ " + loanDuration + "]" );
 System.out.println(" Total Loan [___FCKpd___3quot; + totalLoanAmt + "]" );

 int couponNum = 0;
 float balanceRemaining = totalLoanAmt;
 float monthlyPayment = 0;

 System.out.println();
 System.out.println( "Payment Monthly Payment Ammount Balance Remaining");
 System.out.println( "------- ----------------------- -----------------");

 while( balanceRemaining 0 )
 {
 couponNum++;
 monthlyPayment = totalLoanAmt/loanDuration;
 if( balanceRemaining < monthlyPayment )
 {
 monthlyPayment = balanceRemaining;
 balanceRemaining = 0;
 }
 else
 {
 balanceRemaining = balanceRemaining - monthlyPayment;
 }

 System.out.println( couponNum + " " + monthlyPayment + " " +
 balanceRemaining );
 }
 }
 }
  • If you are passing local objects through remote interfaces, this local class must be serializable.
  • Notice that the schedule class implements the Serializable interface, but it does not have to provide any code. This is because Java manages the serialization of serializable interfaces for you.
    If we were to implement externalizable instead of serializable , then the schedule.java class would have to provide the serialize/deserialize methods. This would require the schedule class to serialize and deserialize its own data. If you try to pass a local object that has not implemented the serializeable/externalizeable interface, Java will throw a marshaling exception on the server/client.
  • Note: Be careful when marking a class serializable, because Java will try to "flatten" everything related to that class, inheritance classes, instances within the class, etc.) (in deep copy). As an example, I would not recommend trying to serialize anything like the root drive on your disk. There is also a lot of overhead involved in the serialization/deserialization process. Use serialization with care.
Argument Passing
  • In order for RMI to be useful, it must do more than just plain method invocation. It must be able to pass arguments to these invoked methods (in parameters) and also handle return values from the invoked methods (out parameters). While at first this may sound like a basic operation, it's really quite complex.
  • For one thing, there are no restrictions on the types of arguments to be passed. These arguments can, in example, be remote objects, which complicates the handling of the arguments.
  • Practically speaking, RMI allows two ways to handle the passing of arguments; the deciding factor on which to use is whether or not the arguments refer to remote objects. At the risk of stating the obvious, any object that is an instance of RemoteObject is considered a remote object. So here's the rule:
    • If an argument or return value is a remote object, a reference to the object is passed. This requires a stub that refers to the remote object.
    • If an argument or return value is not a remote object , it is in deep copied over the network. That means the argument is passed by value. Any other objects referenced by the remote object argument are also passed by value, in a chain-like manner.
    • This may sound restrictive or inefficient, but it has at least one virtue: It works. Admittedly, this isn't as extensive or flexible as argument passing in CORBA. But that doesn't mean RMI isn't useful. One should always use the right tool for the job. Some applications will demand the depth of a robust object broker model like CORBA, and others will be served just as well by RMI.

Creating the Stubs/Skeletons

  • Now that the interface and implementation files have been created, you need to generate the stubs and skeleton code.
  • This is done by using the rmic compiler provided by the JDK. The following command will generate the stub and skeleton .class files, but it will not create the .java files. If you want to see the Java-generated code, use the -keepgenerated option. This will leave the .java files files around, but don't try to modify these files.
 rmic mathCalcImp
  • After running the rmic compiler, you should see mathCalcImp_Skel.class and mathCalcImp_Stub.class. These classes are where your references to the remote objects will resolve to in the client's address space.
Creating the Client
  • Now we need to create the client-side application that will use the remote objects. Below is the sample code for calcClient.java.
 /****************************************************
 * module: calcClient.java
 ****************************************************/
 import java.util.*;
 import java.net.*;
 import java.rmi.*;
 import java.rmi.RMISecurityManager;

 public class calcClient
 {
 public static void main( String args[] )
 {
 mathCalc cm = null;
 int i = 0;
 System.setSecurityManager( new RMISecurityManager());

 try
 {
 System.out.println("Starting calcClient");

 String target = new String( "//"+ args[0] + "/calcMath");
 boolean notBound = true;


 while (notBound) {
 try {
 cm = (mathCalc)Naming.lookup( target );
 notBound = false;
 } catch (NotBoundException e) {
 System.out.println("Trying to connect " + target);
 try { Thread.sleep(100000); } catch (InterruptedException e2) {}
 } catch (RemoteException e) {
 System.out.println("Trying to connect " + target);
 try { Thread.sleep(100000); } catch (InterruptedException e2) { }
 } catch (java.net.MalformedURLException e) {
 System.out.println("URL error: " + e);
 System.exit(0);
 } // try
 } // while
 System.out.println("Connection established to " + target);
 System.out.println("Calc Server Lookup: url =" + url);


 if( cm != null )
 {
 String testStr = "Requesting Current Interest Rate...";

 // Print Current Interest Rate from the server
 cm.printRate();

 // Amortize a schedule using the server interest rate.

 float amount = (float)10000.50;
 int duration = 36;
 schedule curschd = cm.amortizeSchedule( amount, duration );

 // Print the schedule
 curschd.print();
 }
 else
 {
 System.out.println("Requested Remote object is null.");
 }
 }
 catch( Exception e )
 {
 System.out.println("An error occured");
 e.printStackTrace();
 System.out.println(e.getMessage());
 }
 }
 }
  • The client code imports the java.rmi package along with the java.rmi.RMISecurityManager. The first thing the client needs to do is register a security manager with the system. The RMI package provides an RMI security manager, but if you like writing security managers, you can register your own. If a security manager is not registered with the system, Java will only allow resolution of classes locally.
  • If you are writing an applet instead of an application, the security manager has already been registered for you by the browser. You cannot register another security manager for the applet.
  • Once you have registered the security manager, you need to create a URL string that is comprised of the server name and remote object name you are requesting. This will enable the client to look up the remote object on the server via the rmiregistry. Your client code will call the Naming.lookup method that makes a request to the server to return a remote object reference.
    Notice the object returned from the Naming.lookup method is cast to the actual interface class. This is because the lookup call returns a reference of type Object, an abstract type that needs to be casted to a concrete class (e.g., the interface definition file, mathCalc). The URL name lookup format for an RMI object via the registry may look like this:
 rmi://pl01-itec.uni-klu.ac.at:Portnumber/myObject
  • If the client is successful in retrieving the remote reference, it can invoke remote methods on the remote object at this point. The example makes a call to print the interest rate on the server, and it makes a request to amortize a schedule. If the amortize schedule is successful, the client gets a local copy of the schedule object. Then the client can call routines in the schedule object, modify the object, etc. This is the client's private copy of the object, and the server has no knowledge of any changes to this object made by the client. Local objects are by copy, and remote objects are by reference (see above)
  • Portnumber is optional, if rmiregistry is started on the server with 1099.

Creating the Server

  • The server has very simple code that is similar to the client. Below is the calcServ.java code for the server:
 /****************************************************
 * module: calcServ.java
 ****************************************************/
 import java.util.*;
 import java.rmi.*;
 import java.rmi.RMISecurityManager;

 public class calcServ
 {
 public static void main( String args[] )
 {
 System.setSecurityManager( new RMISecurityManager());

 try
 {
 System.out.println("Starting calcServer");
 mathCalcImp cm = new mathCalcImp();

 System.out.println("Binding Server");
 Naming.rebind("calcMath", cm );
 System.out.println("Server is waiting");
 }
 catch( Exception e )
 {
 System.out.println("An error occured");
 e.printStackTrace();
 System.out.println(e.getMessage());
 }
 }
 }
  • The server may start the registry from the program, too. Below is an alternative calcServ.java code for the server:
 /****************************************************
 * module: calcServ.java
 ****************************************************/
 import java.util.*;
 import java.rmi.*;
 import java.rmi.registry.*;
 import java.rmi.RMISecurityManager;

 public class calcServ
 {
 public static void main( String args[] )
 {

 try
 {
 System.out.println("Starting calcServer");
 Registry reg = null;
 System.setSecurityManager(new RMISecurityManager());
 try { reg = LocateRegistry.createRegistry(DefaultPort);}
 catch (RemoteException e) {
 try { reg = LocateRegistry.getRegistry(); }
 catch (RemoteException e2) {
 System.out.println("Registry could not be established" + e);
 System.exit(0);
 } // try-catch-e2
 } // try-catch-e
 System.out.println("Registry established");
 mathCalcImp cm = new mathCalcImp();

 System.out.println("Binding Server");
 Naming.rebind("calcMath", cm );
 System.out.println("Server is waiting");
 }
 catch( Exception e )
 {
 System.out.println("An error occured");
 e.printStackTrace();
 System.out.println(e.getMessage());
 }
 }
 }
  • The server has the same requirements as the client has regarding the security manager. Once the server has registered properly with the security manager, the server needs to create an instantiation of the mathCalcImp implementation object. This is the actual remote object the server exports. Since the server uses the rmiregistry, you must bind an instance of the object (e.g. cm) with the name (e.g. calcMath) that will be used to look up the object.
  • Note: The server sample uses rebind instead of bind. This is to avoid the following problem with bind; i.e., if you start your server and bind an object to the registry then later start a newer version of the server, the bind will not take place because a previous version already exists. When your client references the server, it will get the original reference to the object and not the latest. Also, when the client tries to reference the remote object, the server will throw an exception because the object is no longer valid. If you instead use rebind, then each time you start a new server, it will bind the latest object for the name lookup and replace the old object.
  • You can export as many objects as you like. For the sake of simplicity, the example only exports one object. Additionally, you can have a factory class that returns object references. You normally only need one registry running, but Java does not preclude running multiple registries on different ports. The client needs to use the correct lookup method to gain access to the correct registry on a port number.
  • If you are looking at this server application and wondering how it continues to run after it has seemingly completed its mission, the answer is that the main thread goes away at this point. However, when the server calls the registry to bind the object, it creates another thread under the covers that blocks waiting in a loop for a registry derigstration event. This keeps the server from terminating.

Building the Sample

You need to compile the client and the server code by doing the following:
 javac calcClient.java
 javac calcServ.java

Starting the Sample

Now you are ready to run the sample RMI application. The first thing to do is to start the rmiregistry on the server. Ensure that your CLASSPATH is set up so that the registry can find your server classes in its path. Start the rmiregistry as follows:
 rmiregistry & (optional port : default port 1099 )
[The optional port number can be left out, in which case it defaults to 1099. If this is not the desired port, specify one as in "rmiregistry 1095 &". ]

Next, start the server as follows:

 java -Djava.security.policy=java.policy calcServ &

with the java.policy file as e.g. :

grant {
 permission java.net.SocketPermission "*:1024-65535","connect,accept,resolve";
 permission java.net.SocketPermission "*:80,"connect";
};

or a general one :

grant {
	// Allow everything for now
	permission java.security.AllPermission;
};
The server will start and print a message that it is waiting for requests.

Now you are ready to start the client application as follows:

 java -Djava.security.policy=java.policy calcClient pl01-itec.uni-klu.ac.at
At this point you should see a request come into the server to print the interest rate and request a remote object reference. The client will then display the contents of the schedule object returned from the server.


harald.kosch@itec.uni-klu.ac.at - Institute HomePage
Last updated 20/02/2003.
分享到:
评论

相关推荐

    RMI代码 remote method invocation

    远程方法调用(Remote Method Invocation,RMI)是Java平台中一种用于分布式计算的技术,它允许Java对象在不同的 JVM(Java虚拟机)之间调用方法,仿佛这些对象都在同一个JVM中一样。RMI是Java EE(现在被称为...

    JDK9-JSE- Java Remote Method Invocation API Guide-2.pdf

    Java Remote Method Invocation(Java RMI)是一种允许开发者创建分布式应用程序的技术。Java RMI 允许对象在另一个 Java 虚拟机(JVM)上调用远程 Java 对象的方法,可能在不同的主机上。Java RMI 使用对象序列化来...

    JDK10-JSE,Java Remote Method Invocation API Guide-2.pdf

    Java Remote Method Invocation(Java RMI)是一种允许分布式应用程序在Java平台上运行的技术。它允许在不同的Java虚拟机(JVM)上运行的对象之间调用方法,从而实现分布式计算和信息-sharing。 Java RMI使用对象...

    RMI 简单示例-Java Remote Methods Invocation

    Java Remote Method Invocation(RMI)是Java平台提供的一种用于在分布式环境中进行对象间通信的技术。RMI允许一个Java对象在某台计算机上执行其方法,而这个对象实际上存在于另一台计算机上。这种技术使得开发者...

    Remote Method Invocation-远程方法调用

    **远程方法调用**(Remote Method Invocation, RMI)是Java平台中的一个核心概念和技术,它允许开发者创建分布式应用,在这些应用中,位于不同机器上的对象可以互相调用方法。这一技术在JDK 1.1中引入,是Java网络编程...

    jdk20-java-remote-method-invocation-api-guide.pdf

    Java Platform, Standard Edition 的 Java Remote Method Invocation API Guide 介绍了 Java Remote Method Invocation(Java RMI)的概念和应用。Java RMI 是一种分布式应用程序开发技术,允许对象在不同的 Java ...

    JDK19-java-remote-method-invocation-api-guide.pdf

    Java Platform, Standard Edition 的 Java Remote Method Invocation (Java RMI) 是一种允许创建分布式应用程序的技术。Java RMI 允许对象在另一个 Java Virtual Machine (JVM) 上的远程 Java 对象上调用方法,可能...

    JDK15-java-remote-method-invocation-api-guide.pdf

    Java Remote Method Invocation(Java RMI)是 Java 平台提供的一种分布式应用程序开发技术,允许对象在不同的 Java 虚拟机(JVM)上调用远程 Java 对象的方法。RMI 使用对象序列化来 marshal 和 unmarshal 参数,...

    JDK16-java-remote-method-invocation-api-guide.pdf

    Java Platform, Standard Edition 的 Java Remote Method Invocation(Java RMI)允许您创建分布式应用程序。Java RMI 允许对象在另一个 Java Virtual Machine(JVM)上调用远程 Java 对象的方法,可能位于不同的...

    Introduction to Java Distributed Objects - Using RMI and CORBA.pdf

    本课程旨在介绍如何使用Java Remote Method Invocation (RMI) 和 Common Object Request Broker Architecture (CORBA) 进行分布式对象编程。对于希望深入了解Java分布式环境并能够利用这两种技术进行开发的专业...

    Java RMI(Remote Method Invocation)远程方法调用 详解

    Remote Method Invocation是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法。 编写一个RMI的步骤 定义一个远程接口,此接口需要继承java.rmi.Remote 开发远程接口的实现类 创建...

    JDK18-java-remote-method-invocation-api-guide.pdf

    Java RMI(Java Remote Method Invocation,Java 远程方法调用)是一种允许 Java 对象在不同的 Java 虚拟机(JVM)上进行方法调用的一种机制。RMI 使用对象序列化来 marshal 和 unmarshal 参数,并且支持真正的面向...

    java_rmi.rar_RMI java_java.rmi

    Java RMI(Remote Method Invocation,远程方法调用)是Java平台提供的一种分布式计算技术,它允许Java对象在不同的网络环境中进行交互,就像它们在同一个进程内一样。RMI是Java在分布式系统领域的核心特性,极大地...

    java_in_rmi.rar_Java RMI_RMI java_rmi _精通rmi

    Java Remote Method Invocation(RMI)是Java平台中用于构建分布式应用程序的一种关键技术。它允许Java对象在不同的Java虚拟机(JVM)之间进行交互,仿佛它们都在同一台机器上运行。这个"java_in_rmi.rar"压缩包包含...

    rmi.rar_Java RMI_RMI source code_java RMI simple_rmi

    Java Remote Method Invocation (RMI) 是Java平台提供的一种强大的分布式计算技术,允许在不同网络环境中的Java对象之间进行远程调用。RMI的核心概念是使一个Java对象能够调用另一个在不同JVM(Java Virtual Machine...

    JDK12-java-remote-method-invocation-api-guide.pdf

    Java Remote Method Invocation(Java RMI)是一种允许对象在远程Java虚拟机(JVM)上调用方法的技术。RMI使用对象序列化来 marshal 和 unmarshal 参数,不会截断类型,支持真正的面向对象的多态性。然而,RMI应用...

    JDK13-java-remote-method-invocation-api-guide.pdf

    Java Remote Method Invocation (Java RMI) 是Java平台标准版(Java SE)中的一部分,它允许对象在不同的Java虚拟机(JVM)之间进行远程方法调用,这些JVM可能运行在不同的主机上。RMI利用Java的对象序列化机制来...

    java简单示例rmi

    Java Remote Method Invocation (RMI) 是Java平台上的一个特性,它允许在分布式环境中进行对象间的交互,使得一个Java对象能够调用另一个在网络另一端的Java对象的方法。这个技术是Java在分布式计算领域的重要应用,...

    Rmi.rar_Java RMI_RMI java_java RMI 线程_rmi

    Java RMI(Remote Method Invocation)是Java平台提供的一种分布式计算技术,它允许一个Java对象调用网络另一端的Java对象的方法,仿佛它们在同一个进程中执行。这个教程“Rmi.rar”显然包含了关于如何使用Java RMI...

Global site tag (gtag.js) - Google Analytics