7 How to Implement WebLogic RMI

This chapter describes the java.rmi.Remote interface which is the basic building block for all remote objects even though it 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, where a client or server can look up the object and use it remotely.

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 applications, look up the object by name in the registry. WebLogic RMI exceptions are identical to and extend java.rmi exceptions so that existing interfaces and implementations do not have to change exception handling.

This chapter includes the following sections:

Creating Classes That Can Be Invoked Remotely

You can write the RMI classes and drop them in WebLogic RMI and change the import statement on a remote interface and the classes that extend the remote interface. WebLogic RMI generates code that has flexible runtime, and creates dynamic bytecode that is independent of the class that implements the interface.

You can write your own WebLogic RMI classes in just a few steps.

Step 1. Write a Remote Interface

Every class that can be remotely invoked implements a remote interface. Write the remote interface in adherence with the following guidelines.

  • A remote interface must extend the interface java.rmi.Remote, which contains no method signatures. Include method signatures that will be implemented in every remote class that implements the interface.

  • The remote interface must be public. Otherwise a client gets an error when attempting to load a remote object that implements it.

  • It is not necessary for each method in the interface to declare java.rmi.RemoteException in its throws block. The exceptions that your application throws can be specific to your application, and can extend RuntimeException. WebLogic RMI subclasses java.rmi.RemoteException, so if you already have existing RMI classes, you will not have to change your exception handling.

  • 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 with the method signature sayHello().

    WebLogic RMI supports more flexible runtime code generation; WebLogic RMI supports dynamic proxies and dynamically created bytecode that are type-correct but are otherwise independent of the class that implements the interface. If a class implements a single remote interface, the proxy and bytecode 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 proxy and bytecode that result from the compilation depend on the name mangling used by the compiler.

Example 7-1 Hello.java Remote Interface

package examples.rmi.hello;

import java.rmi.RemoteException;
/**
 * This interface is the remote interface. 
 * 
 * Copyright (c) 1999,2012, Oracle and/or its affiliates. All Rights Reserved.
 */
public interface Hello extends java.rmi.Remote {
  String sayHello() throws RemoteException;
}

Step 2. Implement the Remote Interface

Write the class 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. All the code generation that takes place in WebLogic RMI is dependent on this class file.

  • Your class can implement more than one remote interface. Your class can also define methods that are not in the remote interface, but you cannot invoke those methods remotely.

  • Example 7-2 implements a class that creates a HelloImpl and binds it to the unique name, HelloServer, in the registry. The method sayHello() provides a greeting.

  • The main() method creates an instance of the remote object and registers it in the WebLogic JNDI tree, by binding it to a name (a URL that points to the implementation of the object). A client that needs to obtain a proxy to use the object remotely will be able to look up the object by name.

WebLogic RMI does not require that you set a Security Manager in order to integrate security into your application. Security is handled by WebLogic Server support for SSL and ACLs.

Example 7-2 HelloImpl.java Remote Interface Implementation

package examples.rmi.hello;
 
import javax.naming.*;
import java.rmi.RemoteException;
 
/**
 * Copyright (c) 1999,2012, Oracle and/or its affiliates. All Rights Reserved.
 */
public class HelloImpl implements Hello{   
  private String name;
 
  /**
   * Constructs a HelloImpl with the specified string.
   *
   * @param s                 String message
   */
  public HelloImpl(String s) throws RemoteException {
    super();
    name = s;
  }
 
  /**
   * Returns a string.
   *
   * @return                  String message
   * @exception               java.rmi.RemoteException
   */
  public String sayHello() throws java.rmi.RemoteException {
    return  "Hello World!";
  }
 
  /**
   * Allows the WebLogic Server to instantiate this implementation
   * and bind it in the registry.
   */
  public static void main(String args[]) throws Exception {
    
    
    try {
      HelloImpl obj = new HelloImpl("HelloServer");
      Context ctx = new InitialContext();
      ctx.bind("HelloServer", obj);
      System.out.println("HelloImpl created and bound in the registry " +
                         "to the name HelloServer");
      
    }
    catch (Exception e) {
      System.err.println("HelloImpl.main: an exception occurred:");
      System.err.println(e.getMessage());
      throw e;
    }
  }
}

Step 3: Create a Client that Invokes Remote Methods

In general, once you create an initial context, it takes just a single line of code to get a reference to the remote object. Do this with the Naming.lookup() method. The following sections provide additional information on creating clients:

Setting Client Timeouts

You can set client side timeouts while configuring your initial context:

For example:

. . .
// Get an InitialContext
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");
env.put(Context.PROVIDER_URL, url);
env.put("weblogic.jndi.connectTimeout", new Long(15000));
env.put("weblogic.jndi.responseReadTimeout", new Long(15000));
return new InitialContext(env);
. . .
Example HelloClient.java Client

Here is a short WebLogic client application that uses an object created in Example 7-2.

Example 7-3 Example HelloClient.java Client

package examples.rmi.hello;
 
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
 
/**
 * This client uses the remote HelloServer methods.
 *
 * @author Copyright (c) 1999,2012, Oracle and/or its affiliates. All Rights Reserved.
 */
public class HelloClient
{
  // Defines the JNDI context factory.
  public final static String JNDI_FACTORY="weblogic.jndi.WLInitialContextFactory";
  int port;
  String host;
  
  private static void usage() {
    System.err.println("Usage: java examples.rmi.hello.HelloClient " +
                       "<hostname> <port number>");
  } 
  
  public HelloClient() {}
  
  public static void main(String[] argv) throws Exception {
    if (argv.length < 2) {
      usage();
      return;
    }
    String host = argv[0];
    int port = 0;
    try {
      port = Integer.parseInt(argv[1]);
    }
    catch (NumberFormatException nfe) {
      usage();
      throw nfe;
    }
 
    try {
      InitialContext ic = getInitialContext("t3://" + host + ":" + port);
      Hello obj = (Hello) ic.lookup("HelloServer");
      System.out.println("Successfully connected to HelloServer on " +
                         host + " at port " +
                         port + ": " + obj.sayHello() );
    }
    catch (Exception ex) {
      System.err.println("An exception occurred: "+ex.getMessage());
      throw ex;
    }
  }
 
  private static InitialContext getInitialContext(String url)
    throws NamingException
  {
    Hashtable<String,String> env = new Hashtable<String,String>();
    env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
    env.put(Context.PROVIDER_URL, url);
    return new InitialContext(env);
  }
 
 
}

Step 4. Compile the Java Classes

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

Example 7-4 provides an Ant script that can be used in the WebLogic Server examples environment to compile the .java files and install the .class files into the serverclasses and clientclasses directories configured for the WebLogic Server examplesServer.

Example 7-4 Example build.xml file to Compile Java Classes

<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="rmi.hello" default="all" basedir=".">
  <property environment="env"/>
  <property file="../../../examples.properties"/>
  <property name="build.compiler" value="${compiler}"/>
  <!-- set global properties for this build -->
  <property name="source" value="${basedir}"/>
  <target name="all" depends="build"/>
  <target name="build" depends="compile.server, compile.client"/>
  <!-- Compile server classes into the serverclasses directory -->
  <target name="compile.server">
    <javac srcdir="${source}"
      destdir="${server.classes.dir}"
      includes="Hello.java, HelloImpl.java"
      classpath="${ex.classpath};${server.classes.dir}"
      deprecation="${deprecation}" debug="${debug}" debugLevel="${debugLevel}"
    />
  </target>
  <!-- Compile client classes into the clientclasses directory -->
  <target name="compile.client">
    <javac srcdir="${source}"
      destdir="${client.classes.dir}"
      includes="HelloClient.java"
      classpath="${ex.classpath};${server.classes.dir}"
      deprecation="${deprecation}" debug="${debug}" debugLevel="${debugLevel}"
    />
   </target>
</project>

Run the RMI Hello Code Sample

Use the following instructions to run the WebLogic RMI Hello example:

Prerequisites

Install WebLogic server, including the examples. It is assumed that you know how to start the examplesServer and how to set an environment in a shell to run examples.

Setup the RMI Hello Example

Use the following steps to setup the Hello example:

  1. Open a shell and set the samples environment.
  2. Change to the ORACLE_HOME\wlserver\samples\server\examples\src\examples directory, where ORACLE_HOME refers to the directory in which you installed WebLogic Server. For more information on the WebLogic Server code examples, see Sample Applications and Code Examples in Understanding Oracle WebLogic Server.
  3. Create an rmi directory with a subdirectory named hello.
  4. Copy and save the contents of Example 7-1 as a file named Hello.java in the hello directory.
  5. Copy and save the contents of Example 7-2 as a file named HelloImpl.java in the hello directory.
  6. Copy and save the contents of Example 7-3 as a file named HelloClient.java in the hello directory.
  7. Copy and save the contents of Example 7-4 as a file named build.xml in the hello directory.
  8. Execute the following command from the shell where you copied the example files:

    ant build

Configure a Startup Class

Start an instance of the exampleServer. Create a startup class with the following information:

  • Name: MyHello

  • Class Name: examples.rmi.hello.HelloImpl

  • Targets: examplesServer

See Configure startup classes in Oracle WebLogic Server Administration Console Online Help.

Note:

In this example, the build script makes sure that the startup class is in a location on the server's classpath.

Restart the examplesServer

Restart the examplesServer. As the server boots, you should see the following in the server log:

HelloImpl created and bound in the registry to the name HelloServer

Once the server is running, you can verify that HelloServer is registered by viewing the JNDI tree. See View objects in the JNDI tree in Oracle WebLogic Server Administration Console Online Help.

Run the Example

Execute the following command from the shell where you copied the example files:

java examples.rmi.hello.HelloClient localhost 7001

The results are:

Successfully connected to HelloServer on localhost at port 7001: Hello World!