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

第 3 章

JMX コネクタ

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

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 + ",index=1"; 
ObjectName mbeanObjectName = 
createSimpleMBean(mbs, mbeanClassName, mbeanObjectNameStr); 
waitForEnterPressed(); 
 
printMBeanInfo(mbs, mbeanObjectName, mbeanClassName); 
waitForEnterPressed(); 
 
manageSimpleMBean(mbs, mbeanObjectName, mbeanClassName); 
waitForEnterPressed(); 
 
mbeanClassName = "SimpleDynamic"; 
mbeanObjectNameStr = 
domain + ":type=" + mbeanClassName + ",index=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-3 と XXX に例を示しています。

このコードには記述されていませんが、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 コネクタサーバは、MBeans で操作をリモートから実行できるように作成されています。クラス 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 は、createSimpleStandard() メソッドの定義を示しています。このメソッドでは、オブジェクト名 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 と呼ばれるもう一つの MBean 属性を取得します。これらの属性はいずれも、「3.1.1.3 SimpleStandard.java」に示すように、SimpleStandard クラスで定義されます。

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

最後に MBeanServer メソッド invoke() の呼び出しにより、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

SimpleStandard.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,index=2"); 
mbsc.createMBean("SimpleStandard", stdMBeanName, null, null); 
waitForEnterPressed();       
             
// Create SimpleDynamic MBean 
      // 
ObjectName dynMBeanName = 
new ObjectName(domain +":type=SimpleDynamic,index=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 = (SimpleStandardMBean) 
MBeanServerInvocationHandler.newProxyInstance( 
mbsc, 
stdMBeanName, 
SimpleStandardMBean.class, 
false); 
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 サーバに接続されると、MBeans を登録し、接続が両端から完全に透過的な状態で MBeans 上で操作を実行することができます。

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

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

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

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

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

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

 


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