8 Developing a Java SE Client

This chapter provides information on how to develop and use a Java SE client. A Java SE client is oriented towards the Java EE programming model; it combines the capabilities of RMI with the IIOP protocol without requiring WebLogic Server classes.

Java SE Client Basics

A Java SE client runs an RMI-IIOP-enabled ORB hosted by a Java EE or Java SE container, in most cases a 1.3 or higher JDK. A Java SE client has the following characteristics:

  • It provides a light-weight connectivity client that uses the IIOP protocol, an industry standard.

  • It is a Java SE-compliant model, rather than a Java EE-compliant model—it does not support many of the features provided for enterprise-strength applications. It does not support security, transactions, or JMS.

  • Distributed interoperability for EJBs, based on the EJB 3.0 specification, is supported by WebLogic Server through the EJB 2.1 remote client view from clients.

How to Develop a Java SE Client

To develop an application using RMI-IIOP with an RMI client:

  1. Define your remote object's public methods in an interface that extends java.rmi.Remote.

    This remote interface may not require much code. All you need are the method signatures for methods you want to implement in remote classes. For example:

    public interface Pinger extends java.rmi.Remote {
    public void ping() throws java.rmi.RemoteException;
    public void pingRemote() throws java.rmi.RemoteException;
    public void pingCallback(Pinger toPing) throws java.rmi.RemoteException;
    }
    
  2. Implement the interface in a class named interfaceNameImpl and bind it into the JNDI tree to be made available to clients.

    This class should implement the remote interface that you wrote, which means that you implement the method signatures that are contained in the interface. All the code generation that will take place is dependent on this class file. Typically, you configure your implementation class as a WebLogic startup class and include a main method that binds the object into the JNDI tree. For example:

    public static void main(String args[]) throws Exception {
      if (args.length > 0)
      remoteDomain = args[0];
      Pinger obj = new PingImpl();
      Context initialNamingContext = new InitialContext();
      initialNamingContext.rebind(NAME,obj);
      System.out.println("PingImpl created and bound to "+ NAME);
    }
    
  3. Compile the remote interface and implementation class with a Java compiler. Developing these classes in an RMI-IIOP application is no different than doing so in normal RMI. For more information on developing RMI objects, see Programming RMI for Oracle WebLogic Server.

  4. Run the WebLogic RMI or EJB compiler against the implementation class to generate the necessary IIOP stub. Note that it is no longer necessary to use the -iiop option to generate the IIOP stubs:

    $ java weblogic.rmic nameOfImplementationClass
    

    A stub is the client-side proxy for a remote object that forwards each WebLogic RMI call to its matching server-side skeleton, which in turn forwards the call to the actual remote object implementation. Note that the IIOP stubs created by the WebLogic RMI compiler are intended to be used with the JDK 1.3.1_01 or higher ORB. If you are using another ORB, consult the ORB vendor's documentation to determine whether these stubs are appropriate.

  5. Make sure that the files you have now created -- the remote interface, the class that implements it, and the stub -- are in the CLASSPATH of WebLogic Server.

  6. Obtain an initial context.

    RMI clients access remote objects by creating an initial context and performing a lookup (see next step) on the object. The object is then cast to the appropriate type.

    In obtaining an initial context, you must use com.sun.jndi.cosnaming.CNCtxFactory when defining your JNDI context factory. Use com.sun.jndi.cosnaming.CNCtxFactory when setting the value for the "Context.INITIAL_CONTEXT_FACTORY" property that you supply as a parameter to new InitialContext().

    Note:

    The Sun JNDI client supports the capability to read remote object references from the namespace, but not generic Java serialized objects. This means that you can read items such as EJBHome out of the namespace but not DataSource objects. There is also no support for client-initiated transactions (the JTA API) in this configuration, and no support for security. In the stateless session bean RMI Client example, the client obtains an initial context as is done below:

    Example 8-1 Obtaining an InitialContext

    .
    .
    .
    * Using a Properties object as follows will work on JDK13
    * and higher clients. 
       */
      private Context getInitialContext() throws NamingException {
    try {
      // Get an InitialContext
      Properties h = new Properties();
      h.put(Context.INITIAL_CONTEXT_FACTORY,
       "com.sun.jndi.cosnaming.CNCtxFactory");
      h.put(Context.PROVIDER_URL, url);
      return new InitialContext(h);
    } catch (NamingException ne) {
      log("We were unable to get a connection to the WebLogic server at   "+url);
      log("Please make sure that the server is running.");
      throw ne;
      }
    /**
    * This is another option, using the Java2 version to get an * InitialContext.
    * This version relies on the existence of a jndi.properties file in
    * the application's classpath. See
    * "Programming JNDI for Oracle WebLogic Server" for more information
    private static Context getInitialContext()
      throws NamingException
    {
      return new InitialContext();
    }
    .
    .
    .
    
  7. Modify the client code to perform the lookup in conjunction with the javax.rmi.PortableRemoteObject.narrow() method.

    RMI-IIOP clients differ from regular RMI clients in that IIOP is defined as the protocol when the client is obtaining an initial context. Because of this, lookups and casts must be performed in conjunction with the javax.rmi.PortableRemoteObject.narrow() method.

    For example, an RMI client creates an initial context, performs a lookup on the EJBean home, obtains a reference to an EJBean, and calls methods on the EJBean.

    You must use the javax.rmi.PortableRemoteObject.narrow() method in any situation where you would normally cast an object to a specific class type. A CORBA client may return an object that does not implement your remote interface; the narrow method is provided by your orb to convert the object so that it implements your remote interface. For example, the client code responsible for looking up the EJBean home and casting the result to the Home object must be modified to use the javax.rmi.PortableRemoteObject.narrow() as shown below:

    Example 8-2 Performing a lookup

    .
    .
    .
    /**
     * RMI/IIOP clients should use this narrow function
     */
    private Object narrow(Object ref, Class c) {
      return PortableRemoteObject.narrow(ref, c);
    }
    /**
     * Lookup the EJBs home in the JNDI tree
     */
    private TraderHome lookupHome()
      throws NamingException
    {
      // Lookup the beans home using JNDI
      Context ctx = getInitialContext();
      try {
    Object home = ctx.lookup(JNDI_NAME);
    return (TraderHome) narrow(home, TraderHome.class);
    } catch (NamingException ne) {
    log("The client was unable to lookup the EJBHome. Please
    make sure ");
    log("that you have deployed the ejb with the JNDI name 
    "+JNDI_NAME+" on the WebLogic server at "+url);
    throw ne;
      }
    }
    /**
     * Using a Properties object will work on JDK130
     * and higher clients
     */
    private Context getInitialContext() throws NamingException {
      try {
    // Get an InitialContext
    Properties h = new Properties();
    h.put(Context.INITIAL_CONTEXT_FACTORY,
    "com.sun.jndi.cosnaming.CNCtxFactory");
    h.put(Context.PROVIDER_URL, url);
    return new InitialContext(h);
      } catch (NamingException ne) {
    log("We were unable to get a connection to the WebLogic
    server at "+url);
    log("Please make sure that the server is running.");
    throw ne;
      }
    }
    .
    .
    .
    

    The url defines the protocol, hostname, and listen port for the WebLogic Server and is passed in as a command-line argument.

    public static void main(String[] args) throws Exception {
      log("\nBeginning statelessSession.Client...\n");
      String url = "iiop://localhost:7001";
    
  8. Connect the client to the server over IIOP by running the client with a command such as:

    $ java -Djava.security.manager -Djava.security.policy=java.policy examples.iiop.ejb.stateless.rmiclient.Client iiop://localhost:7001
    
  9. Set the security manager on the client:

    java -Djava.security.manager -Djava.security.policy==java.policy myclient
    

    To narrow an RMI interface on a client, the server needs to serve the appropriate stub for that interface. The loading of this class is predicated on the use of the JDK network classloader and this is not enabled by default. To enable it you set a security manager in the client with an appropriate java policy file. For more information on Java SE security, see http://www.oracle.com/technetwork/java/javase/tech/index-jsp-136007.html at the Oracle Technology Network. The following is an example of a java.policy file:

    grant { 
    // Allow everything for now 
    permission java.security.AllPermission;
    }