目次 | 前の項目 | 次の項目 Java Management Extensions (JMX) テクノロジのチュートリアル

第 3 章

JMX コネクタ

この章では、標準および動的な管理 Bean (MBean) の概念を紹介します。また、Java Management Extensions (JMX) テクノロジを使用して MBean 上でローカルおよびリモートから操作を実行する方法について示します。

3.1 RMI コネクタを使用した標準および動的 MBeans へのアクセス

この例では、標準および動的 MBeans のみを説明します。

第 2 章「JMX API の基本要素」で説明したように、標準 MBean は内部のメソッドの名前を使用して管理インタフェースを静的に定義する管理 Bean です。動的 MBean は、特定の Java インタフェースを実装し、実行時に自らの属性と操作を示します。

JMX テクノロジは、RMI に基づいてコネクタを定義します。RMI コネクタは、Java Remote Method Protocol (JRMP) と Internet Inter-Object Request Broker (ORB) Protocol (IIOP) の 2 つの標準 RMI トランスポートをサポートしています。このコネクタを使用すると、MBean サーバーの MBean にリモート接続し、ローカルで操作を実行するのとまったく同じように、その MBean で操作を実行できます。

この例は、標準 MBean と動的 MBean の実装を説明することを目的としています。また、両 MBean 上でローカルに、またサーバーとリモートクライアント間の RMI 接続を通じてリモートに操作を実行する方法も示します。

この例を実行する場合

  1. サーバー側:
    1. MBean サーバーを作成
    2. ローカル MBean サーバーに SimpleStandardSimpleDynamic の MBean を登録
    3. 両 MBean 上でローカル操作を実行
    4. RMI コネクタサーバーを作成
  2. クライアント側:
    1. RMI コネクタを作成
    2. リモート MBean サーバーに SimpleStandardSimpleDynamic の MBean を登録
    3. 両 MBean でリモート操作を実行

RMI コネクタの例は、ディレクトリ work_dir/jmx_examples/Basic 内にあります。

  1. work_dir/jmx_examples/Basic ディレクトリを開きます。
  2. このディレクトリ内には、次のファイルがあります。

  3. テキストエディタでそれぞれの *.java ファイルを開きます。

3.1.1 例題クラスの分析

次のセクションでは、基本的な MBean の例題で使用される各クラスを分析し、各クラスがこれまでのセクションで説明した操作をどのように実行するかについて説明します。

3.1.1.1 Server.java

Server.java クラスは、その大きさにより、いくつかのコード (抜粋) で現れます。

コード例 3-1 MBean の例題クラス Server.java (抜粋 1)
 
public class Server { 
 
 public static void main(String[] args) { 
     try { 
          
         MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 
         waitForEnterPressed(); 
 
         String domain = mbs.getDefaultDomain(); 
         waitForEnterPressed(); 
 
         String mbeanClassName = "SimpleStandard"; 
         String mbeanObjectNameStr = 
             domain + ":type=" + mbeanClassName + ",name=1"; 
         ObjectName mbeanObjectName = 
             createSimpleMBean(mbs, mbeanClassName, mbeanObjectNameStr); 
         waitForEnterPressed(); 
 
         printMBeanInfo(mbs, mbeanObjectName, mbeanClassName); 
         waitForEnterPressed(); 
 
         manageSimpleMBean(mbs, mbeanObjectName, mbeanClassName); 
         waitForEnterPressed(); 
 
         mbeanClassName = "SimpleDynamic"; 
         mbeanObjectNameStr = 
             domain + ":type=" + mbeanClassName + ",name=1"; 
         mbeanObjectName = 
             createSimpleMBean(mbs, mbeanClassName, mbeanObjectNameStr); 
         waitForEnterPressed(); 
 
         printMBeanInfo(mbs, mbeanObjectName, mbeanClassName); 
         waitForEnterPressed(); 
 
         manageSimpleMBean(mbs, mbeanObjectName, mbeanClassName); 
         waitForEnterPressed(); 
 
         [...] 
 

このクラスを検討すると、次のイベントが起こっていることがわかります。

まず、Server.java クラスは、MBeanServerFactory クラスの createMBeanServer() メソッドを呼び出して mbs と呼ばれる新しい MBean サーバーを作成します。

次に MBean サーバーを登録するデフォルトドメインを、MBeanServer インタフェースの getDefaultDomain() メソッドを呼び出して取得します。このドメインは、文字列 domain で識別されます。

MBean クラス SimpleStandard も、この場合は文字列 mbeanClassName という変数により識別されます。SimpleStandard は、この MBean をインスタンスとする Java オブジェクトの Java クラスの名前です。SimpleStandard.java オブジェクトについては、「3.1.1.3 SimpleStandard.javaを参照してください。

もう一つの変数、文字列 mbeanObjectNameStr は、ドメインと次のキー=値ペアを組み合わせて定義されます。

mbeanObjectNameStr の目的は、人間が読むことができる識別子を MBean に割り当てることです。

createSimpleMBean() の呼び出しにより、指定されたオブジェクト名の SimpleStandard MBean がローカル MBean サーバーで作成され、登録されます。

次に、printMBeanInfo()manageSimpleMBean() の両方の操作が、SimpleStandard MBean で実行されます。createSimpleMBean() と同様、これらのメソッドは後で Server.java コードで定義され、コード例 3-4コード例 3-5で示されます。

このコードには記述されていませんが、SimpleDynamic 型の 2 番目の MBean が、SimpleStandard MBean とまったく同じ方法で MBean サーバーに作成され、登録されます。その名前が示すように、この MBean は 「3.1.1.4 SimpleDynamic.javaで説明する SimpleDynamic Java オブジェクトのインスタンスです。

コード例 3-2 MBean の例題クラス Server.java (抜粋 2)
 
[...] 
 
JMXServiceURL url = 
  new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9999/server"); 
JMXConnectorServer cs = 
  JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); 
cs.start(); 
waitForEnterPressed(); 
cs.stop(); 
 
[...] 
 

コード例 3-2 では、RMI コネクタサーバーは MBean でリモート操作ができるように作成されています。JMXServiceURL クラスを呼び出すと、コネクタサーバーのアドレスとなる url という新しいサービス URL が作成されます。この例では、サービス URL は「エンコード形式」ではなく「JNDI 形式」で指定されます (JNDI 形式の詳細は、javax.management.remote.rmi パッケージの API ドキュメントを参照)。このサービス URL は、次の内容を定義しています。

RMI コネクタサーバー cs は、パラメータにサービス URL urlnull 環境マップ、および MBean サーバー mbs を使用して、コンストラクタ JMXConnectorServerFactory を呼び出して作成されます。コネクタサーバー cs は、JMXConnectorServerstart() メソッドを呼び出し、RMIConnectorServer が RMI オブジェクト server を RMI レジストリにエクスポートすることで起動されます。この接続は、Enter キーを押すまで有効です。 これは Server コードの後半で定義する簡単なメソッド waitForEnterPressed の手順に従ったものです。

コード例 3-3 MBean の例題クラス Server.java (抜粋 3)
 
[...] 
 
private static ObjectName createSimpleMBean(MBeanServer mbs, 
                                              String mbeanClassName, 
                                              String mbeanObjectNameStr) { 
     echo("\n>>> Create the " + mbeanClassName + 
          " MBean within the MBeanServer"); 
     echo("ObjectName = " + mbeanObjectNameStr); 
     try { 
          ObjectName mbeanObjectName = 
             ObjectName.getInstance(mbeanObjectNameStr); 
          mbs.createMBean(mbeanClassName, mbeanObjectName); 
             return mbeanObjectName; 
          } catch (Exception e) { 
            echo(	"!!! Could not create the " +  
                  mbeanClassName + " MBean !!!"); 
            e.printStackTrace(); 
            echo("\nEXITING...\n"); 
            System.exit(1); 
        } 
        return null; 
     } 
 
[...] 
 

コード例 3-3 は、createSimpleMBean() メソッドの定義を示しています。このメソッドでは、オブジェクト名 mbeanObjectNameStr を使用した MBean インスタンスが、ObjectName インタフェースの getInstance() メソッドに渡され、MBean サーバー内で MBean に登録するための新しいオブジェクト名が作成されます。最終的なオブジェクト名インスタンスは、mbeanObjectName に設定されます。次に MBeanServer のメソッド createMBean() により、mbeanClassName で識別される Java オブジェクトと MBean インスタンス mbeanObjectName の組み合わせにより MBean のインスタンスが作成され、MBean サーバー mbs にこの MBean が登録されます。

コード例 3-4 MBean の例題クラス Server.java (抜粋 4)
[...] 
 
private static void printMBeanInfo(MBeanServer mbs, 
                                     ObjectName mbeanObjectName, 
                                     String mbeanClassName) { 
     MBeanInfo info = null; 
     try { 
         info = mbs.getMBeanInfo(mbeanObjectName); 
     } catch (Exception e) { 
         echo(	"!!! Could not get MBeanInfo object for " + 
     	 mbeanClassName +" !!!"); 
         e.printStackTrace(); 
         return; 
     } 
 
     MBeanAttributeInfo[] attrInfo = info.getAttributes(); 
     if (attrInfo.length > 0) { 
         for (int i = 0; i < attrInfo.length; i++) { 
     	echo(" ** NAME: 	" + attrInfo[i].getName()); 
     	echo("    DESCR: 	" + attrInfo[i].getDescription()); 
     	echo("    TYPE: 	" + attrInfo[i].getType() + 
               	"READ: "+ attrInfo[i].isReadable() + 
               	"WRITE: "+ attrInfo[i].isWritable()); 
        } 
     } else echo(" ** No attributes **"); 
 
[...] 

コード例 3-4 は、printMBeanInfo() メソッドの定義を示しています。printMBeanInfo() メソッドは MBeanServer のメソッド getMBeanInfo() を呼び出して、mbeanObjectName により開示される属性と操作の詳細を取得します。MBeanAttributeInfo は次のメソッドを定義します。それらのメソッドはそれぞれ、mbeanObjectName MBean の属性に関する情報を取得する場合に呼び出されます。

ここには示していませんが、呼び出しが行われるのは、mbeanObjectName MBean のコンストラクタ、操作、および通知に関する情報を取得するためです。

コード例 3-5 MBean の例題クラス Server.java (抜粋 5)
[...] 
 
private static void manageSimpleMBean(MBeanServer mbs, 
                                        ObjectName mbeanObjectName, 
                                        String mbeanClassName) { 
        try { 
            printSimpleAttributes(mbs, mbeanObjectName); 
 
            Attribute stateAttribute = new Attribute("State", 
                                                     "new state"); 
            mbs.setAttribute(mbeanObjectName, stateAttribute); 
 
            printSimpleAttributes(mbs, mbeanObjectName); 
	     
            echo("\n    Invoking reset operation..."); 
            mbs.invoke(mbeanObjectName, "reset", null, null); 
 
            printSimpleAttributes(mbs, mbeanObjectName); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
    } 
 
    private static void printSimpleAttributes( 
                                        MBeanServer mbs, 
                                        ObjectName mbeanObjectName) { 
        try { 
            String State =  
               (String) mbs.getAttribute(mbeanObjectName, "State"); 
            Integer NbChanges = 
               (Integer) mbs.getAttribute(mbeanObjectName, 
                                          "NbChanges"); 
        } catch (Exception e) { 
            echo(	"!!! Could not read attributes !!!"); 
            e.printStackTrace(); 
        } 
   } 
 
[...]  

コード例 3-5 は簡単な MBean を管理するための方法を示しています。

まず、manageSimpleMBean() メソッドが、Server でも定義される printSimpleAttributes() メソッドを呼び出します。printSimpleAttributes() メソッドは、MBean mbeanObjectName から state という MBean 属性と、NbChanges というもう 1 つの MBean 属性を取得します。これらの属性はいずれも、「3.1.1.3 SimpleStandard.javaに示すように、SimpleStandard クラスで定義されます。

次に manageSimpleMBean() メソッドは、Attribute クラスのインスタンスである属性 stateAttribute を定義します。stateAttribute 属性は、値 new stateSimpleStandard で定義される既存の属性 state に関連付けます。次に MBeanServersetAttribute() メソッドに呼び出すことで、mbeanObjectName MBean の状態が stateAttribute で定義される新しい状態に設定されます。

最後に MBeanServerinvoke() メソッドに呼び出すことで、mbeanObjectName MBean の reset 操作が起動します。reset 操作は、SimpleStandard クラスで定義されます。

3.1.1.2 SimpleStandardMBean.java

SimpleStandardMBean.java クラスをコード例 3-6 に示します。

コード例 3-6 MBean の例題クラス SimpleStandardMBean.java
 
public interface SimpleStandardMBean { 
 
       public String getState(); 
       public void setState(String s); 
       public int getNbChanges(); 
       public void reset(); 
 
} 
 

SimpleStandardMBean.java クラスは、MBean SimpleStandard の簡単な JMX 仕様の管理インタフェースです。このインタフェースは、JMX エージェントからの管理のために SimpleStandard で定義された 4 つの操作を公開します。

3.1.1.3 SimpleStandard.java

SimpleStandardMBean.java クラスをコード例 3-7 に示します。

コード例 3-7 MBean の例題クラス SimpleStandard.java
 
public class SimpleStandard 
    extends NotificationBroadcasterSupport 
    implements SimpleStandardMBean { 
    public String getState() { 
       return state; 
    } 
    public void setState(String s) { 
       state = s; 
       nbChanges++; 
    } 
     
    public int getNbChanges() { 
        return nbChanges; 
    } 
     
    public void reset() { 
       AttributeChangeNotification acn =  
           new AttributeChangeNotification(this, 
                                          0, 
                                          0, 
                                          "NbChanges reset", 
                                          "NbChanges", 
                                          "Integer", 
                                          new Integer(nbChanges), 
                                          new Integer(0)); 
       state = "initial state"; 
       nbChanges = 0; 
       nbResets++; 
       sendNotification(acn); 
    } 
     
    public int getNbResets() { 
       return nbResets; 
    } 
 
    public MBeanNotificationInfo[] getNotificationInfo() { 
        return new MBeanNotificationInfo[] { 
	  new MBeanNotificationInfo( 
	  new String[] { 
	    AttributeChangeNotification.ATTRIBUTE_CHANGE }, 
	    AttributeChangeNotification.class.getName(), 
	    "This notification is emitted when the reset()  
	     method is called.") 
	}; 
    } 
     
    private String state = "initial state"; 
    private int nbChanges = 0; 
    private int nbResets = 0; 
 
}	  
 

SimpleStandard クラスは、簡単な JMX 仕様の標準 MBean を定義します。

SimpleStandard MBean は、「3.1.1.2 SimpleStandardMBean.javaに示すように、対応する SimpleStandardMBean インタフェースを実装することで、管理のための操作と属性を開示します。

この MBean で開示される簡単な操作を次に示します。

リセット操作により発行される通知は、クラス AttributeChangeNotification のインスタンスであり、リセットの呼び出し前に State 属性で実行された変更数に関する情報を収集します。送信される通知の内容は、MBeanNotificationInfo インスタンスで定義されます。

3.1.1.4 SimpleDynamic.java

SimpleDynamic クラスをコード例 3-8 に示します。

コード例 3-8 MBean の例題クラス SimpleDynamic.java
 
public class SimpleDynamic 
    extends NotificationBroadcasterSupport 
    implements DynamicMBean { 
 
    public SimpleDynamic() { 
        buildDynamicMBeanInfo(); 
    } 
 
[...] 

SimpleDynamic の動的 MBean では、DynamicMBean インタフェースを実装することで、実行時に管理用の属性と操作を開示する方法を示します。ここでは、まず、MBean に関する情報を動的に取得するためのメソッド buildDynamicMBeanInfo() の定義から開始します。buildDynamicMBeanInfo() メソッドは、動的 MBean に MBeanInfo を構築します。

SimpleDynamic の他のコードは、DynamicMBean インタフェースの実装に対応しています。開示される属性、操作、通知は、SimpleStandard MBean で開示されるものと同じです。

3.1.1.5 ClientListener.java

ClientListener.java クラスをコード例 3-9 に示します。

コード例 3-9 MBean の例題クラス ClientListener.java
 
 
public class ClientListener implements NotificationListener {  
 public void handleNotification(Notification notification, Object handback)  
     {  
         System.out.println("\nReceived notification: " + notification);  
     }  
} 
 

ClientListener クラスは、簡単な JMX 仕様の通知リスナを実装します。

通知が受領されると、NotificationListener インタフェースの handleNotification() メソッドが呼び出され、通知の受領を確認するためのメッセージが印刷されます。

3.1.1.6 Client.java

Client.java クラスをコード例 3-10 に示します。

コード例 3-10 MBean の例題クラス Client.java
 
public class Client { 
 
  public static void main(String[] args) { 
    try { 
      // Create an RMI connector client 
      // 
      JMXServiceURL url = new JMXServiceURL( 
         "service:jmx:rmi:///jndi/rmi://localhost:9999/server"); 
      JMXConnector jmxc = JMXConnectorFactory.connect(url, null); 
      ClientListener listener = new ClientListener(); 
      MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); 
      waitForEnterPressed();       
       
      // Get domains from MBeanServer 
      // 
      String domains[] = mbsc.getDomains(); 
      for (int i = 0; i < domains.length; i++) { 
          System.out.println("Domain[" + i + "] = " + domains[i]); 
      } 
      waitForEnterPressed();       
 
      String domain = mbsc.getDefaultDomain();       
   
      // Create SimpleStandard MBean  
      ObjectName mbeanName =  
             new ObjectName(domain +":type=SimpleStandard,name=2"); 
      mbsc.createMBean("SimpleStandard", stdMBeanName, null, null); 
      waitForEnterPressed();       
             
      // Create SimpleDynamic MBean 
      ObjectName dynMBeanName = 
          new ObjectName(domain +":type=SimpleDynamic,name=2"); 
      echo("\nCreate SimpleDynamic MBean..."); 
      mbsc.createMBean("SimpleDynamic", dynMBeanName, null, null); 
      waitForEnterPressed(); 
       
      // Get MBean count 
      echo("\nMBean count = " + mbsc.getMBeanCount()); 
 
      // Query MBean names 
      echo("\nQuery MBeanServer MBeans:"); 
      Set names = mbsc.queryNames(null, null); 
      for (Iterator i = names.iterator(); i.hasNext(); ) { 
      echo(	"ObjectName = " + (ObjectName) i.next()); 
      } 
      waitForEnterPressed(); 
       
      mbsc.setAttribute(stdMBeanName, 
                        new Attribute("State", "changed state")); 
 
      SimpleStandardMBean proxy = JMX.newMBeanProxy( 
          mbsc, stdMBeanName, SimpleStandardMBean.class, true); 
      echo("\nState = " + proxy.getState()); 
 
      ClientListener listener = new ClientListener(); 
      mbsc.addNotificationListener(stdMBeanName, listener, null, null); 
 
      mbsc.invoke(stdMBeanName, "reset", null, null); 
 
      mbsc.removeNotificationListener(stdMBeanName, listener); 
      mbsc.unregisterMBean(stdMBeanName); 
       
      [...] 
       
      jmxc.close(); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
  } 
} 
[...] 

Client.java クラスは、RMI コネクタクライアントを作成します。 このクライアントは、Server.java で作成される RMI コネクタサーバーへの接続用に設定されます。

Client.javaServer.java で定義されるのと同じサービス URL、url を定義します。これによって、コネクタクライアントは、ローカルホストのポート 9999 で動作する RMI レジストリから RMI コネクタサーバースタブ server を取得し、RMI コネクタサーバーに接続することができます。

RMI レジストリがこのように特定された後、コネクタクライアントを作成できます。コネクタクライアント jmxc は、JMXConnectorFactoryconnect() メソッドにより作成されたインタフェース JMXConnector のインスタンスです。connect() メソッドは、呼び出されると、パラメータ urlnull 環境マップが渡されます。

またクライアントは、「3.1.1.5 ClientListener.javaに示すように、ClientListener のインスタンスを作成して通知を待機します。

次に、JMXConnector インスタンス jmxcgetMBeanServerConnection() メソッドを呼び出して、JMX 仕様 MBeanServerConnection のインスタンス mbsc が作成されます。

これによってコネクタクライアントは Server.java で作成された MBean サーバーに接続され、両端への接続が完全に透過的な状態にあれば MBean の登録と MBean での操作が可能になります。

クライアントは、MBeanServerConnectioncreateMBean() メソッドを呼び出して、MBean サーバーに SimpleStandard MBean と SimpleDynamic MBean を作成および登録します。 そして、SimpleStandardSimpleDynamic で定義された操作を、ローカル JMX 仕様の MBean 操作とまったく同様に実行します。

MBean プロキシにより Java インタフェースを介して MBean にアクセスできるため、長いコードを記述しなくても、プロキシ上で呼び出してリモート MBean にアクセスできます。SimpleStandardMBean の MBean プロキシをここで作成するには、javax.management.JMX クラスの newMBeanProxy() メソッドを呼び出し、MBean の MBeanServerConnection、オブジェクト名、MBean インタフェースのクラス名、および true を渡して、このプロキシが NotificationBroadcaster として動作する必要があることを知らせます。MXBean のプロキシを標準 MBean の場合と全く同じ方法で作成するには、newMBeanProxy() ではなく newMXBeanProxy() を呼び出します。

SimpleDynamic で実行される各操作は、SimpleStandard で実行されるものと同じであるため、ここでは操作のコードを記載していません。

最後に、クライアントは SimpleStandard MBean の登録を解除し、接続を終了します。最後の removeNotificationListener は省略可能です。 これはリモートクライアントで登録されたリスナは、そのクライアントの終了時に削除されるためです。

3.1.2 MBean の例題の実行

クラスの例題を検証した後、今度は例題を実行します。例題を実行するには、次の手順に従うか、README ファイルを参照します。

  1. Java クラスをコンパイルします。
  2. $ javac *.java

  3. ローカルホストのポート 9999 で RMI レジストリを起動します。
  4. RMI レジストリは、Server によって RMI コネクタスタブの登録に使用されます。

    $ rmiregistry 9999 &

  5. Server クラスを起動します。
  6. $ java -classpath .サーバー

    MBean サーバーの作成、および MBean サーバーでの SimpleStandard MBean の作成を確認するプロンプトが表示されます。次に SimpleStandard MBean に関する情報を取得し、この MBean で操作を実行する場合は、Enter キーを押すように要求されます。

    SimpleStandard での操作が終了すると、SimpleDynamic MBean について、同じプロセスが繰り返されます。

    標準および動的 MBean が作成され、各 MBean 上での操作が実行された後、RMI コネクタサーバーの作成が表示されます。 このサーバーを使用すると、リモート Client から MBeans 上で操作を実行できます。

  7. 別の端末ウィンドウで Client クラスを起動します。
  8. $ java -classpath .クライアント

    RMI コネクタの作成、およびコネクタサーバーとの接続の作成の確認が表示されます。ドメイン名と、SimpleStandard および SimpleDynamic の MBean の作成と登録についても通知されます。クライアントは次に、SimpleStandard と SimpleDynamic の両 MBean で操作を実行し、その後、両 MBean の登録を解除します。

 


目次 | 前の項目 | 次の項目 Java Management Extensions (JMX) テクノロジのチュートリアル
Java Management Extensions (JMX), Java Platform, Standard Edition 6