BEA Logo BEA WebLogic Server Release 5.0

  Corporate Info  |  News  |  Solutions  |  Products  |  Partners  |  Services  |  Events  |  Download  |  How To Buy

Using WebLogic RMI

I. Introduction
Overview of RMI in the WebLogic framework
WebLogic RMI architecture
WebLogic RMI compiler
Proxies in WebLogic RMI
How the RMI Registry and Server work in WebLogic
Breadth and depth of WebLogic's implementation

II. The WebLogic RMI API
WebLogic RMI API reference
Overview of the WebLogic RMI API

III. Implementing with WebLogic RMI
Creating classes that can be invoked remotely
Step 1. Write a Remote interface
Step 2. Implement the Remote interface
Step 3. Compile the java class
Step 4. Compile the implementation class with RMI compiler
Step 5. Write a client that invokes on remote objects
Full code examples

Converting existing RMI classes
Step 1. Change the package imports
Step 2. Compile
Step 3. Set up the WebLogic Server for RMI
Step 4. Run the client applet

Using client-side callbacks with RMI
Step 1. Write the Remote interfaces for both client and server
Step 2. Implement the Remote interfaces
Step 3. Compile and install the classes

Setting up WebLogic Server for RMI

WebLogic RMI for clustered services
Cluster-specific RMI compiler options
Non-replicated stubs

Other related documents
Installing WebLogic (non-Windows)
Installing WebLogic (Windows)
Developers Guides
API Reference Manual
Overview of RMI in the WebLogic Framework
Writing a WebLogic client application
Code examples
Glossary

I. Introduction

Overview of RMI in the WebLogic framework

WebLogic RMI, the WebLogic implementation of JavaSoft's Remote Method Invocation (RMI) specification, provides standards-based distributed object computing within WebLogic. WebLogic's implementation of RMI is a drop-in replacement for JavaSoft's RMI that provides scalability and performance, as well as access to all of WebLogic's integrated services, like JDBC, Events, etc.

In addition, WebLogic RMI is fully integrated with WebLogic JNDI. Applications can be partitioned into meaningful name spaces by using either the JNDI API or the Registry interfaces in WebLogic RMI.

The WebLogic RMI compiler generates stubs and skeletons that completely replace the stubs and skeletons produced by RMIC, the RMI compiler. Like RMIC, the WebLogic RMI compiler produces enough compile-time information to support runtime resolution of classes, methods, and instances, to override Object methods, and to deliver Exceptions raised in the server to the invoking clients.

For comparative information on JavaSoft's RMI and WebLogic RMI, read the the WebLogic whitepaper, Overview of WebLogic RMI.

If you are new to the RMI specification

You may want to go through the RMI tutorial on the JavaSoft site before you continue through the implementation section of this document. This document contains information about using WebLogic's RMI, but it is not a beginner's tutorial on remote objects or writing distributed applications.

Top

WebLogic RMI architecture

WebLogic's RMI compiler

You run the WebLogic RMI compiler (rmic) by executing the weblogic.rmic class on the Java class file you want to execute via RMI. The compiler produces a stub and skeleton.

The stub class is the serializable class that is passed to the client. The skeleton is a server-side class that processes requests from the stub on the client. The implementation for the class is bound to a name in the RMI registry in the WebLogic Server.

A client acquires the stub for the class by looking up the class in the registry. WebLogic Server serializes the stub and sends it to the client. The client calls methods on the stub just as if it were a local class and the stub serializes the requests and sends them to the skeleton on the WebLogic Server. The skeleton deserializes client requests and executes them against the implementation classes, serializing results and sending them back to the stub on the client.

With the WebLogic RMI compiler, you can specify that more platform-specific compilers should be used. By default, weblogic.rmic invokes the compiler from the JDK distribution, javac, but you may call any compiler with the -compiler option to weblogic.rmic, as shown in this example which calls the Symantec Java compiler:

 $ java weblogic.rmic -compiler \Cafe\bin\sj.exe

The WebLogic RMI compiler accepts any option supported by the Java compiler; for example, you could add -d \classes examples.hello.HelloImpl to the command above. All other options supported by the compiler can be used, and are passed directly to the Java compiler. The following options for java weblogic.rmic are available for you to use, and should be entered in one line, after java weblogic.rmic and before the name of the remote class.

-help Prints a description of the options
-version Prints version information
-d <dir> Target (top-level) directory for complation
-verbosemethods Instruments proxies to print debug info for std err
-descriptor Associates or creates a descriptor for each remote class
-nomanglednames Does not mangle the names of stubs and skeletons
-idl Generates IDLs for remote interfaces
-idlOverwrite Overwrites existing IDL files
-idlVerbose Displays verbose information for IDL information
-idlDirectory <idlDirectory>Specifies the directory where IDL files will be created (Default = current directory)
-clusterable Marks the service as clusterable (can be hosted by multiple servers in a WebLogic cluster). Each hosting object, or replica, is bound into the naming service under a common name. When the service stub is retrieved from the naming service, it contains a replica-aware reference that maintains the list of replicas and performs load-balancing and fail-over between them.
-loadAlgorithm <algorithm> Only for use in conjunction with -clusterable. Specifies a service specific algorithm to use for load-balancing and failover (Default = weblogic.cluster.loadAlgorithm). Must be one of the following: round-robin, random, or weight-based.
-callRouter <callRouterClass> Only for use in conjunction with -clusterable. Specifies the class to be used for routing method calls. This class must implement weblogic.rmi.extensions.CallRouter. If specified, an instance of the class will be called before each method call and be given the opportunity to choose a server to route to based on the method parameters. It either returns a server name or null--indicating that the current load algorithm should be used.
-stickToFirstServer Only for use in conjunction with -clusterable. Enables 'sticky' load balancing. The server chosen for servicing the first request will be used for all subsequent requests.
-methodsAreIdempotent Only for use in conjuction with -clusterable. Indicates that the methods on this class are idempotent. This allows the stub to attempt recovery form any communication failure, even if it can not ensure that failure occurred before the remote methode was invoked. By default (if this option is not used) the stub will only retry on failures that are guaranteed to have occured before the remote method was invoked.
-replicaListRefreshInterval <seconds> Only for use in conjunction with -clusterable. Specifies the minimum time to wait between attempts to refresh the replica list from the cluster (Default = 180 seconds).
-keepgenerated Keeps the generated .java files
-commentary Emits commentary
-compiler <compiler> Specifies the java compiler (Default = javac)
-comilerclass <null> Loads the compiler as a class instead of an executable
-g Compiles debugging information into a class file
-O Compiles with optimization enabled
-debug Compiles with debugging enabled
-nowarn Compiles without warnings
-verbose Compiles with verbose output
-nowrite Does not generate .class files
-deprecation Warns of deprecated calls
-normi Passes through to Symantec's sj
-J <option> Flags passed through to java runtime
-classpath <path> Classpath to use during compilation

Other features of the WebLogic RMI compiler address some of the limitations of the JavaSoft RMI compiler:

  • Signatures of remote methods do not need to throw RemoteException.

  • Remote exceptions can be mapped to RuntimeException.

  • Remote classes can also implement non-remote interfaces. For example, java.io.Input/OutputStream classes are not serializable and do not implement an interface that conforms to the specification for a remote interface. How would one make a RemoteInputStream that is type-equivalent (that is, satisfies instanceof) to java.io.InputStream?

  • Code generation can be done on the descendants of a class.

  • Code generation can be done from an abstract class.
Note: If you are upgrading from an earlier version of WebLogic, you need to re-run rmic on any existing code to regenerate the wrapper classes so that they're compatible with the WebLogic Server version.

Proxies in WebLogic RMI

A proxy is a class used by the clients of a remote object, in the case of RMI, a skeleton and a stub. The stub class is the instance that is invoked upon in the client's Java Virtual Machine (JVM); the stub marshals the invoked method name and its arguments, forwards these to the remote JVM, and -- after the remote invocation is completed and returns -- unmarshals the results on the client. The skeleton class, which exists in the remote JVM, unmarshals the invoked method and arguments on the remote JVM, invokes the method on the instance of the remote object, and then marshals the results for return to the client.

In JavaSoft's RMI reference implementation, there is invariably a one-to-one correspondence between the proxy classes and the remote objects. For example, running the JavaSoft RMI compiler against example.hello.HelloImpl -- which implements the remote class example.hello.Hello -- will produce two classes, example.hello.HelloImpl_Skel and example.hello.HelloImpl_Stub. If another class -- for example, counter.example.CiaoImpl also implements the same remote interface (example.hello.Hello), a virtually identical pair of proxy classes will be produced with the JavaSoft RMI compiler (counter.example.CiaoImpl_Skel and counter.example.CiaoImpl_Stub).

The WebLogic RMI compiler works differently for increased efficiency. The default behavior of WebLogic's RMI compiler is to produce proxies for the remote interface, and for the remote classes to share the proxies. For example, with WebLogic's RMI compiler, example.hello.HelloImpl and counter.example.CiaoImpl are represented by a single stub and skeleton, the proxy that matches the remote interface(s) implemented by the remote object -- in this case, example.hello.Hello.

When a remote object implements more than one interface, the proxy names and packages are determined by encoding the set of interfaces. You can override this default behavior with the WebLogic RMI compiler option -nomanglednames, which will cause the compiler to produce proxies specific to the remote class. When a class-specific proxy is found, it takes precedence over the interface-specific proxy.

In addition, with WebLogic RMI proxy classes, the stubs are not final. References to colocated remote objects are references to the objects themselves, not to the stubs.

How the RMI Registry and Server work in WebLogic

One of the great strengths of WebLogic's implementation of RMI is that it depends upon and benefits from the infrastructure provided by WebLogic. The WebLogic Server hosts the RMI registry and provides server infrastructure for RMI clients. With WebLogic's high-performance, efficient client-to-server and server-to-network communications, the overhead for RMI registry and server communications is minimal, since registry traffic is multiplexed over the same connection as JDBC, Event, and other kinds of traffic. WebLogic's sophisticated communications model means that clients use a single socket for RMI; scaling for RMI clients is linear in the WebLogic environment, unlike with JavaSoft's RMI reference implementation.

WebLogic's RMI registry is created when the WebLogic Server starts up, and calls to create new registries simply locate the existing registry. Objects that have been bound in the registry can be accessed with a variety of client protocols, including the standard rmi://, as well as t3://, t3s://, http://, or https://. In fact, all of the Naming services use JNDI (Java Naming and Directory Interface).

Breadth and depth of WebLogic's implementation

In general, functional equivalents of all methods in the java.rmi package are provided in WebLogic RMI, except for those methods in the RMIClassLoader and the method java.rmi.server.RemoteServer.getClientHost().

A functional equivalent for the RMI classloader will be available in a release subsequent to version 3.0, and at that point classloading from the WebLogic Server will be automatic. Because the RemoteServer.getClientHost() method is related to enabling information used for security, which WebLogic implements at the server level in a more sophisticated fashion, WebLogic may not choose to implement this method in a future release.

All other interfaces, exceptions, and classes are supported in WebLogic RMI. Here are notes on particular implementations that may be of interest to developers:

  • rmi.Naming is implemented as a final class in WebLogic RMI with all public methods supported by JNDI, which is the preferred mechanism for naming objects in WebLogic RMI.

  • rmi.RMISecurityManager is implemented as a non-final class with all public methods in WebLogic RMI and, unlike the restrictive JavaSoft reference implementation, is entirely permissive. Security in WebLogic RMI is an integrated part of the larger WebLogic environment, for which there is support for SSL (Secure Socket Layer) and ACLs (Access Control Lists).

  • rmi.registry.LocateRegistry is implemented as a final class with all public methods, but a call to LocateRegistry.createRegistry(int port) will not create a colocated registry, but rather will attempt to connect to the server-side instance that implements JNDI, for which host and port are designated by a property. In WebLogic RMI, a call to this method allows the client to find the JNDI tree on the WebLogic Server. You can use protocols other than the default (rmi) as well, and provide the scheme, host, and port as a URL, as shown here:
      LocateRegistry.getRegistry(t3s://localhost:7002);
    which will locate a WebLogic Server registry on the local host at port 7002, using a standard SSL WebLogic protocol.

  • rmi.server.LogStream diverges from the JavaSoft reference implementation in that the write(byte[]) method logs messages through WebLogic's server-wide logfile.

  • rmi.server.RemoteObject is implemented in WebLogic RMI to preserve the type equivalence of UnicastRemoteObject, but the functionality is provided by the WebLogic RMI base class Stub.

  • rmi.server.RemoteServer is implemented as the abstract superclass of rmi.server.UnicastRemoteObject and all public methods are supported in WebLogic RMI with the exception of getClientHost().

  • rmi.server.UnicastRemoteObject is implemented as the base class for remote objects, and all the methods in this class are implemented in terms of the WebLogic RMI base class Stub. This allows the stub to override non-final Object methods and equate these to the implementation without making any requirements on the implementation.

  • In WebLogic RMI, all method parameters are pass-by-value, unless the invoking object resides in the same Java Virtual Machine (JVM) as the RMI object. In this scenerio, method parameters are pass-by-reference.

  • WebLogic RMI, does not support uploading classes from the client. In other words, any classes passed to a remote object must be available within the server's CLASSPATH.

The setSecurityManager() method is provided in WebLogic RMI for compilation compatibility only. No security is associated with it, since WebLogic RMI depends on the more general security model within WebLogic. If, however, you do set a SecurityManager, keep in mind that you can set only one. Before setting a SecurityManager, you should test to see if one has already been set; if you try to set another, your program will throw an exception. Here is an example:

  if (System.getSecurityManager() == null)
    System.setSecurityManager(new RMISecurityManager());

The following classes are implemented but unused in WebLogic RMI:

  • rmi.dgc.Lease
  • rmi.dgc.VMID
  • rmi.server.ObjID
  • rmi.server.Operation
  • rmi.server.RMIClassLoader
  • rmi.server.RMISocketFactory
  • rmi.server.RemoteStub
  • rmi.server.UID

Top

II. The WebLogic RMI API

WebLogic RMI API reference

There are several packages shipped as part of WebLogic RMI. The public API includes WebLogic's implementation of the RMI base classes, the registry, and the server packages. WebLogic's implementation also includes the WebLogic RMI compiler and supporting classes that are not part of the public API.

Package weblogic.rmi
Package weblogic.rmi.registry
Package weblogic.rmi.server
Class java.lang.Object
    Interface weblogic.rmi.server.LoaderHandler
    Class weblogic.rmi.registry.LocateRegistry
     (implements weblogic.rmi.registry.Registry)
    Class weblogic.rmi.Naming
    Class weblogic.rmi.server.ObjID
     (implements java.io.Serializable)
    Class weblogic.rmi.server.Operation
    Class java.io.OutputStream
         Class java.io.FilterOutputStream
             Class java.io.PrintStream
                 Class weblogic.rmi.server.LogStream
    Class weblogic.rmi.server.RMIClassLoader
    Interface weblogic.rmi.server.RMIFailureHandler
    Class weblogic.rmi.server.RMISocketFactory
    Interface weblogic.rmi.registry.Registry
     (extends weblogic.rmi.Remote)
    Interface weblogic.rmi.registry.RegistryHandler
    Interface weblogic.rmi.Remote
    Interface weblogic.rmi.server.RemoteCall
    Class weblogic.rmi.server.RemoteObject
     (implements weblogic.rmi.Remote)
         Class weblogic.rmi.server.RemoteServer
             Class weblogic.rmi.server.UnicastRemoteObject
              (implements java.lang.Cloneable)
         Class weblogic.rmi.server.RemoteStub
    Interface weblogic.rmi.server.RemoteRef
     (extends java.io.E ternalizable)
    Class java.lang.SecurityManager
           Class weblogic.rmi.RMISecurityManager
    Interface weblogic.rmi.server.ServerRef
     (extends weblogic.rmi.server.RemoteRef)
    Interface weblogic.rmi.server.Skeleton
    Class java.lang.Throwable
     (implements java.io.Serializable)
         Class java.lang.Exception
             Class weblogic.rmi.AlreadyBoundException
             Class java.lang.CloneNotSupportedException
                 Class weblogic.rmi.server.ServerCloneException
             Class weblogic.rmi.NotBoundException
             Class weblogic.rmi.RemoteException
              (implements java.io.Serializable)
                 Class weblogic.rmi.AccessException
                 Class weblogic.rmi.ConnectException
                 Class weblogic.rmi.ConnectIOException
                 Class weblogic.rmi.server.ExportException
                 Class weblogic.rmi.server.SocketSecurityException
                 Class weblogic.rmi.MarshalException
                 Class weblogic.rmi.NoSuchObjectException
                 Class weblogic.rmi.ServerError
                 Class weblogic.rmi.ServerException
                 Class weblogic.rmi.ServerRuntimeException
                 Class weblogic.rmi.server.SkeletonMismatchException
                 Class weblogic.rmi.server.SkeletonNotFoundException
                 Class weblogic.rmi.StubNotFoundException
                 Class weblogic.rmi.UnexpectedException
                 Class weblogic.rmi.UnknownHostException
                 Class weblogic.rmi.UnmarshalException
             Class java.lang.RuntimeException
                 Class java.lang.SecurityException
                     Class weblogic.rmi.RMISecurityException
             Class weblogic.rmi.server.ServerNotActiveException
    Class weblogic.rmi.server.UID
     (implements java.io.Serializable)
    Interface weblogic.rmi.server.Unreferenced

Top

Overview of the WebLogic RMI API

weblogic.rmi.Remote
weblogic.rmi.Naming

If you have written RMI classes, you can drop them in WebLogic RMI by changing the import statement on a remote interface and the classes that extend it. To add remote invocation to your client apps, look up the object by name in WebLogic's built-in registry.

The basic building block for all Remote objects is the interface weblogic.rmi.Remote, which contains no methods. You extend this "tagging" interface -- that is, it functions as a tag to identify remote classes -- to create your own remote interface, with method stubs that create a structure for your remote object. Then you implement your own remote interface with a remote class. This implementation is bound to a name in the registry, from whence a client or server may look up the object and use it remotely.

As in JavaSoft's reference implementation of RMI, the weblogic.rmi.Naming class is an important one. It includes methods for binding, unbinding, and rebinding names to remote objects in the registry. It also includes a lookup() method to give a client access to a named remote object in the registry.

In addition, WebLogic JNDI, WebLogic's implementation of the JavaSoft Java Naming and Directory Interface, is used throughout WebLogic to provide naming and lookup services. WebLogic RMI also supports naming and lookup in JNDI.

WebLogic RMI Exceptions are identical to and extend java.rmi Exceptions so that existing interfaces and implementations do not have to change Exception handling.

Top

III. Implementing with WebLogic RMI

There are two parts to using WebLogic RMI. First you create the interfaces and classes that you will invoke remotely. Then you add code to your client application that carries out the remote invocations. Each part of the implementation guide is divided into two step-by-step sections that detail these implementation phases.

Following the implementation examples are instructions on how to set up and run the WebLogic Server to host your WebLogic RMI apps.

Creating classes that can be invoked remotely
Step 1. Write a Remote interface
Step 2. Implement the Remote interface
Step 3. Compile the java class
Step 4. Compile the implementation class with RMI compiler
Step 5. Write a client that invokes on remote objects
Full code examples

Converting existing RMI classes
Step 1. Change the package imports
Step 2. Compile
Step 3. Set up the WebLogic Server for RMI
Step 4. Run the client applet

Using client-side callbacks with RMI
Step 1. Write the Remote interfaces for both client and server
Step 2. Implement the Remote interfaces
Step 3. Compile and install the classes

Setting up WebLogic Server for RMI

WebLogic RMI for clustered services
Cluster-specific RMI compiler options
Non-replicated stubs

Top

Creating classes that can be invoked remotely

You can write your own WebLogic RMI classes in just a few steps. Here we demonstrate another simple example to show how you start from scratch. Using WebLogic's RMI is simpler than using JavaSoft's RMI, since you do not need to extend UnicastRemoteObject and you do not need to set a SecurityManager.

Step 1. Write a Remote interface

Every class that can be remotely invoked implements a remote interface. A remote interface must extend the interface weblogic.rmi.Remote, which contains no method signatures.

Remote hierarchy

The interface that you write should include method signatures that will be implemented in every remote class that implements it. Interfaces in Java are a powerful concept, and allow great flexibility at both design time and runtime. If you need more information on how to write an interface, check out the JavaSoft tutorial Creating Interfaces.

Your Remote interface should follow guidelines similar to those followed if you are using JavaSoft's RMI:

  • It must be public. Otherwise a client will get an error when attempting to load a remote object that implements it.

  • It must extend the interface weblogic.rmi.Remote.

  • Unlike JavaSoft's RMI, it is not necessary that each method in the interface declares weblogic.rmi.RemoteException in its throws block. The Exceptions that your application throws can be specific to your application, and may extend RuntimeException. WebLogic's RMI subclasses java.rmi.RemoteException so if you already have existing RMI classes, you will not have to change your exception handling.

With JavaSoft's RMI, every class that implements a remote interface must have accompanying, precompiled stubs and skeletons. WebLogic RMI supports more flexible runtime code generation; WebLogic RMI supports stubs and skeletons that are type-correct but are otherwise independent of the class that implements the interface. If a class implements a single remote interface, the stub and skeleton that is generated by the compiler will have the same name as the remote interface. If a class implements more than one remote interface, the name of the stub and skeleton that result from compilation will depend on the name mangling used by the compiler.

Your Remote interface may not contain much code. All you need are the method signatures for methods you want to implement in Remote classes.

Here is an example of a Remote interface. It has only one method signature.

package examples.rmi.multihello;

import weblogic.rmi.*;

public interface Hello extends weblogic.rmi.Remote {

  String sayHello() throws RemoteException;

}

Top

Step 2. Implement the Remote interface

Now write the class that will be invoked remotely. The class should implement the Remote interface that you wrote in Step 1, which means that you implement the method signatures that are contained in the interface. Currently, all the code generation that takes place in WebLogic RMI is dependent on this class file, but this will change in future releases.

With WebLogic's RMI, there is no need for your class to extend UnicastRemoteObject, which is required by JavaSoft's RMI. (If you extend UnicastRemoteObject, WebLogic RMI will not care, but it isn't necessary.) This allows you to retain a class hierarchy that makes sense for your application.

Your class may implement more than one Remote interface. Your class may also define methods that are not in the Remote interface, but you will not be able to invoke those methods remotely. You should also define at least a default constructor.

In this example, we implement a class that creates multiple HelloImpls and binds each to a unique name in the Registry. The method sayHello() greets the user and identifies the object which was remotely invoked.

Remote hierarchy

package examples.rmi.multihello;

import weblogic.rmi.*;

public class HelloImpl implements Hello {

  private String name;

  public HelloImpl(String s) throws RemoteException {
    name = s;
  }

  public String sayHello() throws RemoteException {
    return "Hello! From " + name;
  }

Finally, write a main that creates an instance of the remote object and registers it in WebLogic RMI's registry, by binding it to a name (a URL that points to the implementation of the object). A client that wants to obtain a stub to use the object remotely will be able to look up the object by name.

Here is an example of a main() for the HelloImpl class. This registers the HelloImpl object under the name HelloRemoteWorld in a WebLogic Server's Registry.

  public static void main(String[] argv) {

    // Not needed with WebLogic RMI
    // System.setSecurityManager(new RmiSecurityManager());
    // But if you include this line of code, you should make
    // it conditional, as shown here:
    // if (System.getSecurityManager() == null)
    //   System.setSecurityManager(new RmiSecurityManager());

    int i = 0;
    try {
      for (i = 0; i < 10; i++) {
        HelloImpl obj = new HelloImpl("MultiHelloServer" + i);
        Naming.rebind("//localhost/MultiHelloServer" + i, obj);
	System.out.println("MultiHelloServer" + i + " created.");
      }
      System.out.println("Created and registered " + i +
                         " MultiHelloImpls.");
    }
    catch (Exception e) {
      System.out.println("HelloImpl error: " + e.getMessage());
      e.printStackTrace();
    }
  }

Note that, unlike JavaSoft's RMI reference implementation, WebLogic RMI doesn't require that you set a SecurityManager in order to integrate security into your application. Security is handled in a more general, server-wide way within WebLogic, with WebLogic Secure (support for SSL and ACLs). If you must, you may use your own security manager, but do not install it in the WebLogic Server.

Top

Step 3. Compile the java class

First compile the .java files with javac or some other Java compiler to produce .class files for the Remote interface and the class that implements it.

Step 4. Compile the implementation class with RMI compiler

Run the WebLogic RMI compiler against the remote class to generate the stub and skeleton. A stub is the client-side proxy for a remote object that forwards each WebLogic RMI call to its matching serverside skeleton, which in turn forwards the call to the actual remote object implementation. To run WebLogic RMI's compiler, use the command pattern:

  $ java weblogic.rmic nameOfRemoteClass
where nameOfRemoteClass is the full package name of the class that implements your Remote interface. With the examples we have used previously, the command would be:
  $ java weblogic.rmic examples.rmi.hello.HelloImpl

You should set the flag -keepgenerated when you run the WebLogic RMI compiler if you want to keep the generated stub and skeleton files. For a listing of the available WebLogic RMI compiler options, see WebLogic's RMI compiler.

Running the WebLogic RMI compiler creates two new classes, a stub and a skeleton. These appear as nameOfInterface_Stub.class and nameOfInterface_Skel.class. The four files created -- the remote interface, the class that implements it, and the stub and skeleton created by the WebLogic RMI compiler -- should be placed in the appropriate directory in the CLASSPATH of the WebLogic Server whose URL you used in the naming scheme of the object's main().

Top

Invoking methods on remote objects in your client code

Once you compile and install the remote class, the interface it implements, and its stub and skeleton on the WebLogic Server, you can add code to a WebLogic client application to invoke methods in the remote class.

In general, it takes just a single line of code: you need to get a reference to the remote object. Do this with the Naming.lookup() method. Here is a short WebLogic client application that uses the object we created in the first part of this guide.

package mypackage.myclient;

import weblogic.rmi.*;
import weblogic.common.*;

public class HelloWorld throws Exception {

  // Look up the remote object in the
  // WebLogic's registry
  HelloImpl hi = (HelloImpl)Naming.lookup("HelloRemoteWorld");
  // Invoke a method remotely
  String message = hi.sayHello();
  System.out.println(message);
}
This example demonstrates using a Java application rather than an applet as the client.

Top

Full code examples

Here is the full code for the Hello interface.
package examples.rmi.hello;
import weblogic.rmi.*;

public interface Hello extends weblogic.rmi.Remote {

  String sayHello() throws RemoteException;

}
Here is the full code for the HelloImpl class that implements it.
package examples.rmi.hello;

import weblogic.rmi.*;

public class HelloImpl
    // Don't need this in WebLogic RMI:
    // extends UnicastRemoteObject
    implements Hello {

  public HelloImpl() throws RemoteException {
    super();
  }

  public String sayHello() throws RemoteException {
    return "Hello Remote World!!";
  }

  public static void main(String[] argv) {
    try {
      HelloImpl obj = new HelloImpl();
      Naming.bind("HelloRemoteWorld", obj);
    }
    catch (Exception e) {
      System.out.println("HelloImpl error: " + e.getMessage());
      e.printStackTrace();
    }
  }
}

Top

Converting an existing RMI class to use WebLogic RMI

It's easy to use WebLogic's RMI with classes written for JavaSoft's reference implementation of RMI. Here we use a simple example to demonstrate the four steps for conversion. For this example we use the HelloWorld example from JavaSoft documentation distribution.

Step 1. Change the package imports

If you have a class written to use JavaSoft's reference implementation of RMI, only one change is needed in your class to start using WebLogic RMI.

Change the import packages to point to weblogic.rmi instead of java.rmi. If you use any explicit full package names for java.rmi. classes, you need to change those class names as well to use weblogic.rmi.

WebLogic supplies a PERL script in the examples/rmi directory of the distribution that you may use for this purpose -- called sub.pl. This script is provided purely as a convenience, and comes with no warranty.

Step 2. Compile

Compile the implementation class and the remote interface that it extends, and any other associated Java files -- perhaps an applet file that you use to invoke. You need to specify the destination of the output with the -d flag when you compile so that the classes are compiled into your weblogic/myserver/serverclasses directory, which should already be in your CLASSPATH. On Windows NT, if you are compiling from the directory where the Hello example Java files are located, the command looks like this:
 $ javac -classpath %CLASSPATH% -d c:\weblogic\myserver\serverclasses *.java

Then run the WebLogic RMI compiler on the implementation class. Again, you specify the destination with the -d flag. On a UNIX system, the RMI compiler command looks like the following example. Note that the command should be typed on a single command-line:

 $ java weblogic.rmic -d /weblogic/myserver/serverclasses
   examples.rmi.hello.HelloImpl

For a listing of the available WebLogic RMI compiler options, see WebLogic's RMI compiler. If you have compiled classes as we illustrated into the WebLogic classes directory, you'll see these files in the directory weblogic/myserver/serverclasses/examples/rmi/hello:

  Hello.class
  HelloApplet.class
  HelloClient.class
  HelloImpl.class
  Hello_WLSkel.class
  Hello_WLStub.class

Step 3. Set up the WebLogic Server for RMI

Identify the remote classes that you want to be bound when the WebLogic Server starts up by registering these classes in the WebLogic weblogic.properties file. (For more information on the properties file, see Setting WebLogic properties.)

Distribution layout

The weblogic.properties file is located in root directory of the distribution, parallel with the myserver/ directory. Both the properties file and the myserver/ directory must exist in order to run the WebLogic Server.

To register each remote class for startup:

  • Using the property weblogic.system.startupClass.virtualName=fullPathName, register the HelloImpl like this:
    weblogic.system.startupClass.hello=examples.rmi.hello.HelloImpl

    Note that the property "weblogic.rmi.startupClass" has been merged with "weblogic.system.startupClass" to make the use of startup classes in WebLogic consistent. (The former property name is deprecated.) No changes are required other than changing the "rmi" in the property name to "system".

    This registers the virtual name "hello" in the WebLogic RMI Registry for the impl you prepared in Step 3. This remote class will be bound to this name in the Registry when the WebLogic Server is started. The virtual name you use to register this class has nothing to do with how the class is bound in the Registry. The virtual name is merely part of the pattern of registering classes that is used in this file, and if the remote class has initialization arguments, the virtual name is used to match args with classes.

  • If the class has initialization arguments, add them with the property weblogic.system.startupArgs.virtualName=startupArg1 startupArg2.

Note that the startup args for a main() method in RMI startup classes is a space-delimited list of arguments (unlike the comma-delimited name=value pairs used for system startup class arguments).

Start the WebLogic Server. If WebLogic Server is set up to write log messages to the console (the default), you will see the messages:

Wed Jul 23 14:13:44 PDT 1997:<I> <RMI> Registry started
Wed Jul 23 14:13:45 PDT 1997:<I> <WebLogic> Invoke rmi startup
class hello: examples.rmi.hello.HelloImpl
HelloImpl created and bound in the registry to the name HelloServer
scroll by as the WebLogic starts up.

Note that the name you assign to the remote class in the call to Naming.bind() in the main() is the name under which the remote class will be available. The virtual name you assign to the class when you register it has nothing to do with the way you access the class in the Registry.

Step 4. Run the client applet

If you are using a webserver other than WebLogic:

  1. Place the index.html and applet files in the appropriate directories of your webserver host.
  2. Set your webserver to proxy requests to the WebLogic Server where you have loaded the remote class files.
  3. Adjust the CODEBASE of the applet HTML file.
If you are using WebLogic as a webserver:
  1. Place the index.html file that loads the applet in the directory that you registered as your HTTP "document root".
  2. Edit the CODEBASE of the HTML file. The codebase should use a URL after the pattern:
    http://WebLogicURL:portname/virtualName/fileName
    There is an example of this in the discussion of document root in the first example.

Then call the applet with your browser.

Top

Using client-side callbacks with RMI

WebLogic RMI supports client-to-server, client-to-client, and server-to-client invocations, with callbacks from server-side objects into applets.

With WebLogic RMI, there is no need to export a client-side object as a remote object, as there is with JavaSoft's reference implementation. (The reason you must export an object with JavaSoft's RMI is that Remote objects are required to extend UnicastRemoteObject, which prevents the class from extending any other superclass -- in this case, Applet. JavaSoft's implementation must provide a way for classes that do not extend UnicastRemoteObject to be treated as Remote objects, which is done by exporting. WebLogic RMI does not require that Remote objects extend UnicastRemoteObject.)

In an application that uses client-side callbacks to a remote client, you partition the application logic between tasks carried out on the server, and those that are exclusive to the client -- a common scenario with any distributed application. In this case, however, you write your remote interfaces for the server-side classes with methods that take the remote client object as a parameter or return it, when appropriate. For example, a server-side task that watches stock quotes will take as an argument the remote object that is interested in changes in stock prices. It can then operate on the remote object, for example, to make changes to the tables that the remote object keeps of stock prices.

In practical use, being able to use a remote object as a parameter or a return value for a remotely invoked method is convenient for such things as updating the display of an applet in response to server-side events. Here, for example, you would merely export the applet itself as a remote object that registers an interest in server-side events, and whose display changes in response to those events.

We illustrate how to make callbacks to a remote client in this section with the Stock example included in the distribution.

There are two parts to this application: the first is the StockWatch, which acts as an event manager for this application and allows the StockApplet to register an interest in the stock events it will receive. The second part is the StockApplet, which displays realtime stock information, according to the events it receives from the StockServer.

You can find the code for this application in your WebLogic distribution, in weblogic/examples/rmi/stock.

The WebLogic
examples in the distribution

Top

Step 1. Write the Remote interfaces for both client and server

You will write two remote interfaces for this application: the StockWatch (the server-side logic that accepts incoming stock price events and allows clients to register an interest in them) and the StockNotify (the client-side logic that registers an interest in stock prices). Both, of course, extend weblogic.rmi.Remote.

The StockWatch interface has 4 methods:

  • A method watch() that allows a remote StockNotify object to register an interest in a particular stock. It takes two arguments, the name of the stock of interest, and the remote object that is interested in it.

  • A method list() that returns an array of stocks that a particular remote object is watching, or null if the object isn't registered for any stock updates. It takes the remote object as an argument.

  • A method cancel(), to cancel a registered interest in a stock. It takes the same two arguments as watch().

  • A method cancelAll() that cancels all registrations of interest for a particular remote object. It takes the remote object as an argument.

The StockNotify interface has just one method:

  • update(), which asks for notification of stock prices at a particular time. It takes two arguments, a Date, and an array of stocks.

There are other classes that make up this application:

  • Stock. Stock is a serializable object that is constructed with a name and, in this example, a random number generator that sets prices for the stock. You can also call its update() method to generate a random change. The remote client keeps a Hashtable of Stock objects for the stocks the client has registered an interest in with the StockServer. Stock isn't a Remote class, but it must implement Serializable, since it is passed over the wire between client and server.

  • StockNotFoundException. This is thrown in various places in the application.

Top

Step 2. Implement the Remote interfaces

You will need to write an implementation for your server-side logic -- the Remote interface StockWatch in this example -- and your client-side logic -- in this example, the Remote interface StockNotify. The implementation classes for this example are, respectively, StockServer and StockApplet.

The StockServer class supplies information about stocks to its clients. In summary, the StockServer keeps a notifyTable, which is a Hashtable of the remote objects that have registered an interest in stocks, and a stockTable, a Hashtable of the stocks the server is watching.

The real work of the StockServer is carried out in its run() method. It first calls a private method to get new stock prices, and then it enumerates through all of the remote objects (these are StockApplet object -- they implement the remote StockNotify interface -- kept in the StockServer's notifyTable) that have registered an interest in stock prices and updates each remote object where appropriate, by calling the remote object's update() method. Here is a code snippet:

  // Get the date and time
  Date date = new Date();
  // Enumerate through all the stock watchers
  Enumeration enum = notifyTable.keys();
  while (enum.hasMoreElement()) {
    StockNotify clientapplet = (StockNotify)enum.nextElement();
    Stock[] stockList = list(clientapplet);
    if (stockList != null) {
      // Update the remote object
      try {
        clientapplet.update(date, stockList);
      }
      catch (RemoteException re) {
        // Watcher is unavailable or unreachable
	// Cancel the notification
	e.printStackTrace();
	cancelAll(clientapplet);
      }
    }
  }
  

The StockApplet class has several interesting features: it manages the AWT display, which we will not describe in detail here; it keeps a Hashtable of those stocks in which it has registered an interest; and it sets up some boundaries for how often it will update its display, and for how long. Most importantly, it exports itself as the callback destination for its remotely invoked update() method, which receives notification of changing stock prices.

The init() method in the applet is where the real work takes place. Note that there is no need in WebLogic RMI for this particular method call -- although it will not break your code to make the method call. We show it here as commented out:

  // Export the applet as a remote object
  // UnicastRemoteObject.exportObject(this);

The real initial action is to look up the StockWatch server, in order to call its methods for registering interest in stocks, as shown here. We use the document base of the applet as part of the URL; the applet must load all of its classes from the same host. Note that in our example, we use getCodeBase() instead of getDocumentBase(), which doesn't always properly load the applet, depending upon the browser.

// Look up the base URL
  URL base = getCodeBase();
  String port = getParameter("registryPort");
  if (port == null) {
    int p = base.getPort();
    if (p == -1) p = 80;
    port = String.valueOf(p);
  }
  String serverName = "//" + base.getHost() + ":" +
    port + "/example.stock.StockServer";

  stockWatch = (StockWatch)Naming.lookup(serverName);

Now we remotely invoke methods on the StockServer object (it implements the StockWatch remote interface) to register an interest in stocks, as shown here. Note that one of the parameters passed to the watch() method is the client object itself.

 // Register an interest in stock updates
  for (int i = 0; i < name.length; i++) {
    stockWatch.watch(name[i], this);
    stockTable.put(name[i], new StockData(name[i], color[i]));
  }

The StockApplet class also has inner classes -- like StockData used in the previous code snippet -- that take the stock information and display it in the applet.

Top

Step 3. Compile and install the classes

After you write the implementation classes, compile them with the WebLogic RMI compiler, as shown in this example. Note that the symbol $(CLASSES) stands for your WebLogic classes directory, or the destination of your compiled class files. Each of these commands should be typed on a single command-line (although the last is displayed on multiple lines for clarity):

 $ javac -d $(CLASSES) *.java
 $ cd $(CLASSES)
 $ java weblogic.rmic -d $(CLASSES) examples.rmi.stock.StockApplet
   examples.rmi.stock.StockServer

Then you will need to register the StockServer as an RMI startup class in your weblogic.properties file. The StockServer will be bound in the registry when the WebLogic Server is started. Here is the correct property entry:

weblogic.system.startupClass.stock=examples.rmi.stock.StockServer

Finally, you will also want to place the HTML file that calls the StockApplet in a registered document root. Then start the WebLogic Server with the URL of the applet.

Top

Setting up WebLogic Server for RMI

The WebLogic Server hosts the RMI registry and the RMI server. In order to start the appropriate processes in WebLogic, you need to set one or two properties in your WebLogic properties file -- that's the weblogic.properties file that exists in the root directory of the WebLogic distribution.

Properties to be set:

  • weblogic.system.startupClass.virtualName is used to register implementations at startup time. For example, to add a Registry entry for HelloImpl, add the following to your properties file:
    weblogic.system.startupClass.hello=examples.rmi.hello.HelloImpl

    Adding remote implementations as startup classes instantiates the class at startup time, which invokes the main() method and calls Naming.bind() or Naming.rebind() immediately to advertise the instance.

  • weblogic.system.startupArgs.virtualName is used to provide command-line arguments for each implementation class. An argument list is used as the value of this argument as it would be used with a call to main() of the implementation class. For example, if the HelloWorld example class used initialization arguments (which it doesn't), you would add the following to your properties file:
    weblogic.system.startupArgs.hello=arg1 arg2

    Note that the startup args for RMI startup classes is a space-delimited list of arguments (unlike the comma-delimited name=value pairs used for system startup class arguments). Also note that the virtual name you assign to remote classes with these properties has nothing to do with the binding of names in the Registry.

Start the WebLogic Server and call the main of your client application.

Top

Using WebLogic's RMI Compiler for Clustered Services

Cluster-specific RMI compiler options

The RMI compiler (RMIC) has several flags that relate to clusters. For a full list of options, see WebLogic's RMI compiler. Note that these argument tags are not case sensitive; inner caps are used in these descriptions for ease of reading.
-clusterable
Generates a stub that can failover and load balance. By default, the generated stub will be capable of failover and will load balance between replicas using a round-robin scheduling algorithm.

-methodsAreIdempotent
May only be used in conjunction with "-clusterable". Indicates to the stub that it can attempt retries after failover even if it might result in executing the same method multiple times. If this flag isn't present, methods for this stub are not considered idempotent. The exceptions that are handled by this are described in Exceptions used for failover.

-loadAlgorithm load algorithm name
May only be used in conjunction with "-clusterable". Specifies a service-specific algorithm that will be used by the stub to handle failover and load balancing. If this argument is unspecified, the default load balancing algorithm specified by the property weblogic.cluster.defaultLoadAlgorithm in the weblogic.properties file will be used. For example, to specify weight-based load balancing:
 $ java weblogic.rmic -clusterable -loadAlgorithm=weight-based

-stickToFirstServer
May only be used in conjunction with "-clusterable". Enables 'sticky' load balancing. The server chosen for servicing the first request will be used for all subsequent requests.

-replicaListRefreshInterval seconds
May only be used in conjunction with "-clusterable". Specifies the minimum time to wait between attempts to refresh the replica list from the Cluster. Default is 180 seconds (3 minutes).

-callRouter callRouterClass
May only be used in conjunction with "-clusterable". Specifies the class to be used for routing method calls. This class must implement weblogic.rmi.extensions.CallRouter. If specified, an instance of this class will be called before each method call and be given the opportunity to choose the server given the method parameters. It either returns a server name or null indicating that the current load algorithm should be used to pick the server.

Non-Replicated Stubs

You can also generate stubs that are not replicated; these are known as "pinned" services, because -- after they are registered in a per-server properties file -- they will be available only from the host with which they are registered and will not provide transparent failover or load balancing. Pinned services are available cluster-wide, since they are bound into the replicated cluster-wide JNDI tree; but if the individual server that hosts them fails, the client cannot failover to another server.

Client-side RMI objects can only be reached through a single Server, even in a cluster. If a client-side RMI object is bound into the JNDI naming service, it will only be reachable as long as the Server that carried out the bind is reachable.

 

Copyright © 2000 BEA Systems, Inc. All rights reserved.
Required browser: Netscape 4.0 or higher, or Microsoft Internet Explorer 4.0 or higher.
Last updated 11/04/1999