6 WebLogic RMIの実装方法

この章では、すべてのリモート・オブジェクトの基本的な構成要素であるjava.rmi.Remoteインタフェースについて説明します(ただし、このインタフェースにはメソッドは含まれません)。この「タグ付け」インタフェースを拡張し(リモート・クラスを識別するタグとして機能するように)、リモート・オブジェクトの構造を作成するメソッド・スタブを使って、使用するリモート・インタフェースを作成します。次に、リモート・クラスを使ってリモート・インタフェースを実装します。この実装はレジストリ内の名前にバインドされ、クライアントやサーバーはそこからオブジェクトをルックアップしてリモートで使用できます。

すでにRMIクラスを記述している場合は、リモート・インタフェースとそれを拡張するクラスでimport文を変えるだけでWebLogic RMIをインストールできます。クライアント・アプリケーションにリモート呼出しを追加するには、レジストリ内でオブジェクトを名前でルックアップします。Weblogic RMI例外はjava.rmi例外と同じ機能を備えているので、既存のインタフェースと実装で例外の処理方法を変える必要がありません。

この章には次の項が含まれます:

リモートで呼び出すことができるクラスの作成

RMIクラスを記述してWebLogic RMIに含めて、リモート・インタフェースとリモート・インタフェースを拡張するクラスでimport文を変えることができます。WebLogic RMIは柔軟なランタイムを持つコードを生成し、インタフェースを実装するクラスから独立した動的なバイトコードを作成します。

独自のWebLogic RMIクラスを簡単なステップで記述できます。

ステップ1. リモート・インタフェースの作成

リモートで呼び出せるすべてのクラスは、リモート・インタフェースを実装します。次のガイドラインに従って、リモート・インタフェースを作成します。

  • リモート・インタフェースは、java.rmi.Remoteインタフェースを拡張する必要がありますが、これにはメソッド・シグネチャは含まれません。インタフェースを実装する各リモート・クラスで実装されるメソッド・シグネチャを含めます。

  • リモート・インタフェースはパブリックでなければなりません。パブリックでない場合、クライアントはリモート・インタフェースを実装するリモート・オブジェクトをロードしようとするとエラーを受け取ります。

  • インタフェース内の各メソッドがそのthrowsブロックでjava.rmi.RemoteExceptionを宣言する必要はありません。アプリケーションがスローする例外は、アプリケーション固有の例外である可能性があり、RuntimeException.WebLogic RMI subclasses java.rmi.RemoteExceptionを拡張する場合があります。したがって、すでにRMIクラスがある場合、例外処理を変更する必要はありません。

  • リモート・インタフェースにはコードがあまり記述されていない場合もあります。必要なのは、リモート・クラスで実装するメソッドのメソッド・シグネチャだけです。

    以下の例に、メソッド・シグネチャsayHello()を持つリモート・インタフェースを示します。

    WebLogic RMIは、柔軟性の高い実行時のコード生成をサポートします。つまり、WebLogic RMIは、型さえ正しければ、そのほかはインタフェースを実装するクラスに依存しない動的プロキシと動的に生成されるバイトコードもサポートします。クラスが単一のリモート・インタフェースを実装する場合、コンパイラが生成したプロキシとバイトコードは、リモート・インタフェースと同じ名前になります。クラスが複数のリモート・インタフェースを実装する場合、コンパイルから生じたプロキシとバイトコードの名前は、コンパイラが使用する名前マングリングによって決まります。

例6-1 Hello.javaリモート・インタフェース

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;
}

ステップ2. リモート・インタフェースの実装

リモートで呼び出すクラスを作成します。このクラスは、ステップ1で記述したリモート・インタフェースを実装する必要があります。これは、インタフェースに含まれるメソッド・シグネチャを実装することを意味します。WebLogic RMIで行われるコード生成はすべて、このクラス・ファイルに依存します。

  • クラスは、複数のリモート・インタフェースを実装できます。また、クラスにはリモート・インタフェースにないメソッドも定義できますが、このようなメソッドはリモートで呼び出せません。

  • 例6-2では、HelloImplを作成するクラスを実装し、それをレジストリ内の一意の名前HelloServerにバインドします。メソッドsayHello()により、挨拶が表示されます。

  • main()メソッドは、リモート・オブジェクトのインスタンスを作成し、それを名前(オブジェクトの実装を指し示すURL)にバインドすることによってWebLogic JNDIツリーに登録します。リモートでオブジェクトを使用するためにプロキシを取得しようとするクライアントは、オブジェクトを名前でルックアップできます。

WebLogic RMIでは、アプリケーションにセキュリティを統合するためにセキュリティ・マネージャを設定する必要はありません。セキュリティは、WebLogicのSSLとACLのサポートによって処理されます。

例6-2 HelloImpl.javaリモート・インタフェースの実装

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;
    }
  }
}

ステップ3: リモート・メソッドを呼び出すクライアントの作成

一般に、初期コンテキストを作成すると、リモート・オブジェクトの参照を取得する単一行のコードのみが取得されます。これは、Naming.lookup()メソッドで行います。次の項では、クライアント作成に関するその他の情報について説明します。

クライアント・タイムアウトの設定

初期コンテキストを構成しながら、クライアント側のタイムアウトを設定できます。

たとえば:

. . .
// 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);
. . .
HelloClient.javaクライアントの例

次に、例6-2で作成したオブジェクトを使用する短いWebLogicクライアント・アプリケーションを示します。

例6-3 HelloClient.javaクライアントの例

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);
  }
 
 
}

ステップ4. Javaクラスのコンパイル

javacまたは他のJavaコンパイラを使用して.javaファイルをコンパイルし、リモート・インタフェースとそれを実装するクラス用の.classファイルを作成します。

例6-4に、WebLogic Server examplesServerに構成されるserverclassesディレクトリとclientclassesディレクトリに対して、.javaファイルをコンパイルしたり.classファイルをインストールする場合にWebLogic Serverのサンプル環境で使用できるAntスクリプトを示します。

例6-4 Javaクラスをコンパイルするbuild.xmlファイルの例

<?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>

RMI Helloサンプル・コードの実行

次の手順を使用して、WebLogic RMI Helloサンプルを実行します。

前提条件

サンプルを含むWebLogicサーバーをインストールします。examplesServerの起動方法と、シェルに環境を設定してサンプルを実行する方法を把握していることが前提になります。

RMI Helloサンプルの設定

次のステップを使用して、Helloサンプルを設定します。

  1. シェルを開き、サンプル環境を設定します。
  2. ORACLE_HOME\wlserver\samples\server\examples\src\examplesディレクトリに移動します(ORACLE_HOMEは、WebLogic Serverをインストールしたディレクトリを表します)。WebLogic Serverのコード例の詳細は、Oracle WebLogic Serverの理解サンプル・アプリケーションとコード例を参照してください。
  3. helloというサブディレクトリを含むrmiディレクトリを作成します。
  4. 例6-1のコンテンツをコピーして、Hello.javaという名前のファイルでhelloディレクトリに保存します。
  5. 例6-2のコンテンツをコピーして、HelloImpl.javaという名前のファイルでhelloディレクトリに保存します。
  6. 例6-3のコンテンツをコピーして、HelloClient.javaという名前のファイルでhelloディレクトリに保存します。
  7. 例6-4のコンテンツをコピーして、build.xmlという名前のファイルでhelloディレクトリに保存します。
  8. サンプル・ファイルをコピーしたシェルから次のコマンドを実行します。

    ant build

起動クラスの構成

exampleServerのインスタンスを起動します。起動クラスを次の情報で作成します。

  • 名前: MyHello

  • クラス名: examples.rmi.hello.HelloImpl

  • ターゲット: examplesServer

Oracle WebLogic Server管理コンソール・オンライン・ヘルプ起動クラスの構成を参照してください。

ノート:

このサンプルでは、ビルド・スクリプトは、起動クラスがサーバーのクラスパスの場所にあるかどうかを確認します。

examplesServerの再起動

examplesServerを再起動します。サーバーが起動したら、サーバー・ログで次の内容を確認する必要があります。

HelloImpl created and bound in the registry to the name HelloServer

サーバーが実行すると、JNDIを表示してHelloServerが登録されていることを確認できます。Oracle WebLogic Server管理コンソール・オンライン・ヘルプJNDIツリーでのオブジェクトの表示を参照してください。

サンプルの実行

サンプル・ファイルをコピーしたシェルから次のコマンドを実行します。

java examples.rmi.hello.HelloClient localhost 7001

結果は次のようになります。

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