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

第3章

JMXコネクタ

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

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)トランスポートをサポートしています。このコネクタを使用すると、MBeanサーバーのMBeanにリモート接続し、ローカルで操作を実行するのとまったく同じように、そのMBeanで操作を実行できます。

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

この例を実行する場合

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

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

  1. work_dir/jmx_examples/Basicディレクトリを開きます。

    このディレクトリ内には、次のファイルがあります。

    • Server.java
    • SimpleStandardMBean.java
    • SimpleStandard.java
    • SimpleDynamic.java
    • ClientListener.java
    • Client.java
    • README
  2. テキスト・エディタでそれぞれの*.javaファイルを開きます。

例題クラスの分析

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

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オブジェクトについては、セクション「SimpleStandard.javaを参照してください。

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

  • type。この場合は、mbeanClassName
  • name。このMBeanを、後で作成される同じタイプの他のMBeanと区別します。この場合、name番号は1です。

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

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

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

このコードには記述されていませんが、SimpleDynamic型の2番目のMBeanが、SimpleStandard MBeanとまったく同じ方法でMBeanサーバーに作成され、登録されます。その名前が示すように、このMBeanはセクション「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で表されるデフォルトのRMIトランスポートを使用する。
  • RMIコネクタ・スタブが保存されるRMIレジストリは、ローカル・ホストのポート9999で稼動し、サーバー・アドレスはserverの名前で登録される。例で指定されるポート9999は任意の数字。使用可能なポートを指定できる。

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()を呼び出して、MBean mbeanObjectNameにより開示される属性と操作の詳細を取得します。MBeanAttributeInfoは次のメソッドを定義します。それらのメソッドはそれぞれ、mbeanObjectName MBeanの属性に関する情報を取得する場合に呼び出されます。

  • getName。属性の名前を取得する。
  • getDescription。人間が読むことのできる属性の説明を取得する。
  • getType。属性のクラス名を取得する。
  • isReadable。属性が読出し可能か否かを判断する。
  • isWritable。属性が書込み可能かどうかを判断する。

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

  • MBeanConstructorInfo。MBeanのJavaクラスに関する情報を取得する。
  • MBeanOperationInfo。MBeanで実行される操作の内容、MBeanで使われるパラメータの種類を学習する。
  • MBeanNotificationInfo。MBeanの操作が実行された場合に、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属性を取得します。これらの属性はいずれも、セクション「SimpleStandard.javaに示すように、SimpleStandardクラスで定義されます。

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

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

SimpleStandardMBean.java

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

コード例3-1 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つの操作を公開します。

SimpleStandard.java

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

コード例3-1 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は、セクション「SimpleStandardMBean.javaに示すように、対応するSimpleStandardMBeanインタフェースを実装することで、管理のための操作と属性を開示します。

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

  • 状態を定義する。
  • 現在の状態を更新する。
  • 状態の更新回数をカウントする
  • 状態の値と、変更回数を元の値であるゼロにリセットする
  • リセットが呼び出された場合に常に通知を送信する

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

SimpleDynamic.java

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

コード例3-1 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で開示されるものと同じです。

ClientListener.java

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

コード例3-1 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()メソッドが呼び出され、通知の受領を確認するためのメッセージが出力されます。

Client.java

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

コード例3-1 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環境マップが渡されます。

またクライアントは、セクション「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はオプションです。これはリモート・クライアントで登録されたリスナーは、そのクライアントの終了時に削除されるためです。

MBeanの例題の実行

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

  1. Javaクラスをコンパイルします。

    $ javac *.java

  2. ローカル・ホストのポート9999でRMIレジストリを起動します。

    RMIレジストリは、ServerによってRMIコネクタ・スタブの登録に使用されます。

    $ rmiregistry 9999 &

  3. Serverクラスを起動します。

    $ java -classpath . Server

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

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

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

  4. 別の端末ウィンドウでClientクラスを起動します。

    $ java -classpath . Client

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


目次||


Copyright © 1993, 2020, Oracle and/or its affiliates. All rights reserved.