Java Platform Standard Edition

Java Management Extensionsガイド

リリース9

E91921-01(原本部品番号:E79011-02)

2017年9月

このガイドでは、Java Management Extensionsテクノロジを使用して、Javaコードの計測、有用なJavaエージェントの作成、分散管理ミドルウェアやマネージャの実装などのソリューションを既存の管理およびモニタリング・システムに統合する方法を説明します。

Java Platform, Standard Edition Java Management Extensionsガイド、リリース9

E91921-01

Copyright © 2006, 2017, Oracle and/or its affiliates.  All rights reserved.

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクル社までご連絡ください。

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations.As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs.No other rights are granted to the U.S. Government.

このソフトウェアまたはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアまたはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用する際、このソフトウェアまたはハードウェアを安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、オラクル社およびその関連会社は一切の責任を負いかねます。

OracleおよびJavaはOracle およびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXはThe Open Groupの登録商標です。

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。適用されるお客様とOracle Corporationとの間の契約に別段の定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。適用されるお客様とOracle Corporationとの間の契約に定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

目次

タイトルおよび著作権情報

はじめに

- 対象読者

- ドキュメントのアクセシビリティについて

- 関連ドキュメント

- 表記規則

パートI Java Management Extensions Technology User's Guide

1 JMXテクノロジの紹介

- JMXテクノロジについて

- JMXテクノロジを使用する理由

2 JMXテクノロジ・アーキテクチャ

- アーキテクチャの概要

- MBeanを使用したリソースの計測

- JMXエージェントの作成

- リソースのリモート管理

3 JMXテクノロジのリソースの計測

- 管理可能なリソース

- 管理対象Bean (MBean)

- Java仮想マシンのインストゥルメンテーション

4 JMXエージェントの使用

- MBeanサーバー

- エージェント・サービス

- プロトコル・アダプタとコネクタ

- プロトコル・アダプタ

- コネクタ

5 JMXコネクタを使用したリソースのリモート管理

- RMIコネクタ

- ジェネリック・コネクタ

- ユーザー定義プロトコル

6 検出、検索サービス

- 検索サービスについて

7 JMXテクノロジのバージョン

- JMXの計測およびエージェント仕様(JSR 3)

- JMX Remote API Specification (JSR 160)

8 Java Management Extensions (JMX) APIの仕様

パートII Java Management Extensions (JMX)テクノロジのチュートリアル

9 スタート・ガイド

- プラットフォーム情報

10 JMX APIの基本要素

- 標準MBean

- MBeanインタフェース

- MBeanの実装

- リソースの管理

- 標準MBeanの例題の実行

- 通知の送信

- NotificationBroadcasterインタフェース

- MBeanの通知の例題の実行

- MXBeanの導入

- QueueSamplerMXBeanインタフェース

- QueueSamplerクラス

- QueueSampleクラス

- MXBeanの作成とMBeanサーバーへの登録

- MXBeanの例題の実行

- MBean記述子

- DescriptorKey注釈

- MBean記述子の使用

- MBean記述子の例題の実行

11 JMXコネクタ

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

- MBeanの例題のServer.java

- MBeanの例題のSimpleStandardMBean.java

- MBeanの例題のSimpleStandard.java

- MBeanの例題のSimpleDynamic.java

- MBeanの例題のClientListener.java

- MBeanの例題のClient.java

- MBeanの例題の実行

12 検索サービス

- 初期設定

- 外部RMIレジストリ

- 外部LDAPレジストリ

- Service Location Protocol (SLP)検索サービス

- SLP検索の例題のServer.java

- SLP検索の例題のClient.java

- SLP検索サービスの例題の実行

- Jini検索サービス

- Jini検索サービスの例題のServer.java

- Jini検索サービスの例題のClient.java

- Jini検索サービスの例題のjava.policy

- jini.properties.template

- Jini検索サービスの例題の実行

- Java Naming and Directory Interface (JNDI)/LDAP検索サービス

- JNDI/LDAP検索サービスの例題のServer.java

- JNDI/LDAP検索サービスの例題のClient.java

- jmx-schema.txt

- 60jmx-schema.ldif

- JNDI/LDAP検索サービスの例題の実行

13 セキュリティ

- 簡単なセキュリティ

- 簡単なセキュリティの例題のServer.java

- 簡単なセキュリティの例題のSimpleStandardMBean.java

- 簡単なセキュリティの例題のSimpleStandard.java

- 簡単なセキュリティの例題のClientListener.java

- 簡単なセキュリティの例題のClient.java

- 簡単なセキュリティを使用したRMIコネクタの例題の実行

- 主体委譲

- 主体委譲の例題のServer.java

- 主体委譲の例題のjava.policy

- 主体委譲の例題のSimpleStandardMBean.java

- 主体委譲の例題のSimpleStandard.java

- 主体委譲の例題のClientListener.java

- 主体委譲の例題のClient.java

- 主体委譲を使用したセキュアなRMIコネクタの例題の実行

- 詳細なセキュリティ

- 詳細なセキュリティの例題のServer.java

- 詳細なセキュリティの例題のjava.policy

- 詳細なセキュリティの例題のSimpleStandardMBean.java

- 詳細なセキュリティの例題のSimpleStandard.java

- 詳細なセキュリティの例題のClientListener.java

- 詳細なセキュリティの例題のClient.java

- 詳細なセキュリティを使用したRMIコネクタの例題の実行

パートIII Java Management Extensionsの例

14 JMXの基本要素

- examples/Essential/README

- examples/Essential/com/example/mbeans/Main.java

- examples/Essential/com/example/mbeans/Hello.java

- examples/Essential/com/example/mbeans/HelloMBean.java

15 JMX MBeanの通知

- examples/Notification/README

- examples/Notification/com/example/mbeans/Main.java

- examples/Notification/com/example/mbeans/Hello.java

- examples/Notification/com/example/mbeans/HelloMBean.java

16 MXBean

- examples/MXBean/README

- examples/MXBean/com/example/mxbeans/Main.java

- examples/MXBean/com/example/mxbeans/QueueSamplerMXBean.java

- examples/MXBean/com/example/mxbeans/QueueSampler.java

- examples/MXBean/com/example/mxbeans/QueueSample.java

17 MBean記述子

- examples/Descriptors/README

- examples/Descriptors/com/example/mxbeans/Author.java

- examples/Descriptors/com/example/mxbeans/DisplayName.java

- examples/Descriptors/com/example/mxbeans/Main.java

- examples/Descriptors/com/example/mxbeans/QueueSample.java

- examples/Descriptors/com/example/mxbeans/QueueSampler.java

- examples/Descriptors/com/example/mxbeans/QueueSamplerMXBean.java

- examples/Descriptors/com/example/mxbeans/Version.java

18 JMXコネクタ

- examples/Basic/README

- examples/Basic/Server.java

- examples/Basic/SimpleStandardMBean.java

- examples/Basic/SimpleStandard.java

- examples/Basic/SimpleDynamic.java

- examples/Basic/ClientListener.java

- examples/Basic/Client.java

19 Service Location Protocol (SLP)検索サービス

- examples/Lookup/slp/README

- examples/Lookup/slp/Server.java

- examples/Lookup/slp/Client.java

20 Jini検索サービス

- examples/Lookup/jini/README

- examples/Lookup/jini/Server.java

- examples/Lookup/jini/Client.java

- examples/Lookup/jini/java.policy

21 Java Naming and Directory Interface (JNDI)/LDAP検索サービス

- examples/Lookup/ldap/README

- examples/Lookup/ldap/Server.java

- examples/Lookup/ldap/Client.java

- examples/Lookup/ldap/jmx-schema.txt

- examples/Lookup/ldap/60jmx-schema.ldif

22 簡単なセキュリティ

- examples/Security/simple/README

- examples/Security/simple/server/Server.java

- examples/Security/simple/client/Client.java

- examples/Security/simple/client/ClientListener.java

- examples/Security/simple/config/access.properties

- examples/Security/simple/config/password.properties

- examples/Security/simple/mbeans/SimpleStandard.java

- examples/Security/simple/mbeans/SimpleStandardMBean.java

23 主体委譲を使用したセキュリティ

- examples/Security/subject_delegation/README

- examples/Security/subject_delegation/server/Server.java

- examples/Security/subject_delegation/client/Client.java

- examples/Security/subject_delegation/client/ClientListener.java

- examples/Security/subject_delegation/config/access.properties

- examples/Security/subject_delegation/config/password.properties

- examples/Security/subject_delegation/config/java.policy

- examples/Security/subject_delegation/mbeans/SimpleStandard.java

- examples/Security/subject_delegation/mbeans/SimpleStandardMBean.java

24 詳細なセキュリティ

- examples/Security/fine_grained/README

- examples/Security/fine_grained/server/Server.java

- examples/Security/fine_grained/client/Client.java

- examples/Security/fine_grained/client/ClientListener.java

- examples/Security/fine_grained/config/password.properties

- examples/Security/fine_grained/config/java.policy

- examples/Security/fine_grained/mbeans/SimpleStandard.java

- examples/Security/fine_grained/mbeans/SimpleStandardMBean.java

はじめに

Java Platform, Standard Edition Java Management Extensionsガイドでは、Java Management Extensionsテクノロジを紹介します。

対象読者

このガイドは、Javaコードの計測、有用なJavaエージェントの作成、分散管理ミドルウェアやマネージャの実装、既存の管理およびモニタリング・システムに対するソリューションのスムーズな統合などにJMXテクノロジを使用するJava開発者を対象としています。

ドキュメントのアクセシビリティについて

Oracleのアクセシビリティについての詳細情報は、Oracle Accessibility ProgramのWebサイト(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc)を参照してください。

Oracleサポートへのアクセス

サポートをご購入のOracleのお客様は、My Oracle Supportにアクセスして電子サポートを受けることができます。詳細は、http://www.oracle.com/pls/topic/lookup?ctx=acc&id=infoまたはhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs (聴覚障害者向け)を参照してください。

関連ドキュメント

詳細は、次を参照してください。

- JMXホーム・ページ: JMX仕様に関するニュース、ダウンロード、ブログ、その他の情報を記載したページ。

- JSR 3: JMX APIに関するJCPのページ。

- JSR 160: JMX Remote APIに関するJCPのページ。

- Java Platform, Standard Edition Management Developer's Guide

表記規則

本文では、次の表記規則を使用します。

規則

意味

太字

太字は、操作に関連するGraphical User Interface要素、または本文中で定義されている用語および用語集に記載されている用語を示します。

イタリック

イタリックは、特定の値を指定するプレースホルダ変数を示します。

固定幅フォント

固定幅フォントは、パラグラフ内のコマンド、URL、例に記載されているコード、画面に表示されるテキスト、または入力するテキストを示します。

パートI Java Management Extensions Technology User's Guide

JMXテクノロジの概要

Java Management Extensions (JMX)テクノロジは当初、Java Community Process (JCP)を通じて、Java Specification Request (JSR) 3、Java Management Extensions、およびJSR 160, JMX Remote APIとして開発されました。JMX APIは、アプリケーション、デバイス、サービス、Java仮想マシンなどのリソースを管理およびモニタリングするための標準APIです。

JMXテクノロジの一般的な用途には次のようなものがあります。

- アプリケーションの構成のモニタリングおよび変更

- アプリケーション動作に関する統計の累積と、統計の公開

- 状態の変化とエラー条件の通知の送付。

JMX APIには、リモート管理アプリケーションが実行中のアプリケーションと対話してこれらのアクションを実行できるように、リモート・アクセスが含まれています。

1 JMXテクノロジの紹介

Java Management Extensions (JMX)テクノロジについてすでに理解している場合は、バージョン情報についてJMXテクノロジのバージョンを参照してください。

JMXテクノロジでは、アプリケーション、デバイス、サービスなどのリソースを管理するための簡単で標準的な方法が用意されています。JMXテクノロジは動的であるため、リソースが作成、インストール、および実装されると、そのリソースをモニターおよび管理するために使用できます。JMXテクノロジを使用して、Java仮想マシン (Java VM)をモニターおよび管理することもできます。

JMXテクノロジは、密接に関連する2つのJava Specification Requests (JSR)として、Java Community Process (JCP)によって開発されました。

- JSR 3: Java Management Extensions (JMX) Specification

- JSR 160: Java Management Extensions (JMX) Remote API

JSRはJavadocツールで生成されたAPIドキュメントによって定義され、各JSRのPDF仕様ドキュメントに記載されています。

名前が示すとおり、JMX Remote APIではリモート機能がJMX仕様に追加されており、アプリケーション、システム、およびネットワークをリモートでモニターおよび管理できます。このガイドでは、JMXテクノロジという語はJMX仕様とJMX Remote APIの両方を記述するために使用されています。

この章では、次のセクションでJMXテクノロジについて紹介します。

- JMXテクノロジについて

- JMXテクノロジを使用する理由

JMXテクノロジについて

JMX仕様では、Javaプログラミング言語でアーキテクチャ、設計パターン、およびAPIについて定義しています。また、アプリケーションとネットワークの管理およびモニタリングのサービスについても定義しています。

JMXテクノロジを使用して、指定されたリソースが管理対象Bean (MBean)と呼ばれる1つ以上のJavaオブジェクトによって計測されます。これらのMBeanは、MBeanサーバーと呼ばれるコアの管理オブジェクト・サーバーに登録されます。MBeanサーバーは管理エージェントとして働き、Javaプログラミング言語に対応するほとんどのデバイス上で実行できます。

仕様では、仕様に準拠して計測されたリソースを管理するために使用できるJMXエージェントを定義しています。JMXエージェントは、MBeanが登録されているMBeanサーバーと、MBeanを処理する一連のサービスで構成されます。JMXエージェントは、リソースを直接制御し、リモート管理アプリケーションで利用できるようにします。

リソースが計測される方法は、管理インフラストラクチャとはまったく無関係です。そのためリソースは、その管理アプリケーションが実装されている方法に関係なく管理可能です。

JMXテクノロジでは、標準コネクタ(JMXコネクタ)を定義しています。JMXコネクタを使用すると、リモート管理アプリケーションからJMXエージェントにアクセスできます。別のプロトコルを使用するJMXコネクタでも、同じ管理インタフェースを用意しています。管理アプリケーションでは、使用している通信プロトコルに関係なく、リソースを透過的に管理できます。JMXエージェントは、JMX仕様に準拠していないがJMXエージェントをサポートしているシステムやアプリケーションでも使用できます。

JMXテクノロジを使用する理由

Javaコードの計測、有用なJavaエージェントの作成、分散管理ミドルウェアやマネージャの実装、既存の管理およびモニタリング・システムに対するソリューションのスムーズな統合など、JMXテクノロジでは、あらゆる業界のJava開発者に柔軟性の高い実現方法を提供します。

- JMXテクノロジを使用すると、最小限の投資でJavaアプリケーションを管理できます: JMXテクノロジ・エージェントは、Javaテクノロジ対応のほとんどのデバイスで実行できるため、Javaアプリケーションの設計に大きな影響を与えることなく管理できます。Javaアプリケーションでは、管理オブジェクト・サーバーを埋め込み、その機能の一部をオブジェクト・サーバーに登録された1つまたはいくつかの管理対象Bean (MBean)として利用できるようにすることのみが必要です。

- JMXテクノロジは、Javaテクノロジベースのアプリケーション、システム、およびネットワークを管理する標準的な方法を提供します: たとえば、Java Platform, Enterprise Edition (Java EE) 5アプリケーション・サーバーは、JMXアーキテクチャに準拠しており、その結果としてJMXテクノロジを使用して管理できます。

- JMXテクノロジを使用すれば、難しい設定なしでJava仮想マシン(JVM)を管理できます: JVMはJMXテクノロジを使用して高度に計測されています。JMXエージェントを起動して、簡単に組込みのJVMインストゥルメンテーションにアクセスしてリモートにJVMをモニターおよび管理できます。

- JMXテクノロジでは、拡大可能で動的な管理アーキテクチャを用意しています: それぞれのJMXエージェント・サービスが、管理エージェントにプラグインできる独立モジュールです。このコンポーネント・ベースの考え方により、JMXソリューションは、設置面積の小さなデバイスから大規模な遠距離通信スイッチ、さらにはそれ以上の規模にまで拡大可能です。JMX仕様では、一連のコア・エージェント・サービスを用意しています。サービスは追加で開発でき、管理インフラストラクチャで動的にロード、アンロード、または更新が可能です。

- JMXテクノロジは既存の標準Javaテクノロジを活用しています: JMX仕様では、Java Naming and Directory Interface (JNDI)などの既存のJava仕様を必要に応じて参照しています。

- NetBeans IDEのJMXモジュールにより、JMXアプリケーションの作成がより簡単になります: JMXモジュールはNetBeansアップデート・センターから取得できます。

- JMXテクノロジは、既存の管理ソリューションや最新技術と統合できます: たとえば、JMXエージェントはHTMLブラウザを使用して管理できます。JMX APIはオープン・インタフェースを提供しており、あらゆる管理システム・ベンダーが使用できます。JMXソリューションでは、JiniテクノロジやService Location Protocol (SLP)などの検索、検出サービスおよびプロトコルを使用できます。

2 JMXテクノロジ・アーキテクチャ

Java Management Extensions (JMX)テクノロジには、リソースを管理およびモニタリングするための標準APIが用意されています。APIには、リモート管理アプリケーションでアプリケーション、システム、およびネットワークを管理およびモニターできるように、リモート・アクセスが含まれています。

この章では、次のセクションでJMXアーキテクチャの概要を説明します。

- アーキテクチャの概要

- MBeanを使用したリソースの計測

- JMXエージェントの作成

- リソースのリモート管理

アーキテクチャの概要

JMXテクノロジは、密接に関連する2つのJava Specification Requests (JSR)として、Java Community Process (JCP)によって開発されました。

- JSR 3: Java Management Extensions (JMX) Specification

- JSR 160: Java Management Extensions (JMX) Remote API

次の表に、管理アーキテクチャのレベルを示します。計測およびエージェント・レベルはJSR 3によって定義されます。リモート管理レベルは、JSR 160で定義されます。

レベル

説明

インストゥルメンテーション

アプリケーション、デバイス、サービスなどのリソースは、Managed Bean (MBean)と呼ばれるJavaオブジェクトを使用して計測されている。MBeanはリモート管理およびモニタリング用のJMXエージェントを通じて、管理インタフェース(属性と操作からなる)を公開している。

エージェント

JMXエージェントの主コンポーネントは、MBeanサーバーである。MBeanサーバーはMBeanが登録されているコアの管理オブジェクト・サーバーである。JMXエージェントには、MBeanを処理するための一連のサービスも含まれる。JMXエージェントは、リソースを直接制御し、リモート管理エージェントで利用できるようにする。

リモート管理

プロトコル・アダプタと標準コネクタにより、JMXエージェントはエージェントのJava仮想マシン(JVM)の外部にあるリモート管理アプリケーションからアクセスできるようになる。

MBeanを使用したリソースの計測

JMXテクノロジを使用してリソースを管理するには、最初にリソースをJavaプログラミング言語で計測する必要があります。MBeanと呼ばれるJavaオブジェクトを使用して、リソースのインストゥルメンテーションへのアクセスを実装できます。MBeanはJMX仕様に定義された設計パターンおよびインタフェースに従う必要があります。これにより、すべてのMBeanで管理対象リソースの計測が標準化された方法で提供されることが保証されます。

リソースがMBeanで計測された後、そのリソースはJMXエージェントを通じて管理できるようになります。MBeanでは、JMXエージェントでMBeanを操作するための知識は不要です。

MBeanは、実装が柔軟、簡潔、容易であるように設計されています。アプリケーション、システム、およびネットワークの開発者は、複雑な管理システムに投資せずに製品を標準的な方法で管理可能なものにできます。最小限の努力で、既存のリソースを管理可能にします。

さらに、JSR 3: Java Management Extensions (JMX) Specificationのインストゥルメンテーション・レベルでは、MBeanが他のレベルのコンポーネントに対する通知イベントを生成して伝播できる通知メカニズムを指定します。

JMXエージェントの作成

JMXエージェントは標準的な管理エージェントであり、リソースを直接管理し、リモート管理アプリケーションでリソースを利用できるようにします。JMXエージェントは通常は制御するリソースと同じシステム上にありますが、これは必須ではありません。

JMXエージェントのコア・コンポーネントはMBeanサーバーです。MBeanサーバーは、MBeanが登録されている管理オブジェクト・サーバーのことです。また、JMXエージェントには、MBeanを管理するための一連のサービスと、管理アプリケーションからアクセス可能な通信アダプタまたはコネクタが少なくとも1つ含まれています。

JMXエージェントを実装する場合は、管理にエージェントが使用されるリソースのセマンティクスや機能を理解しておく必要はありません。実際のところ、JMXエージェントでは、提供するリソースの情報は必要ありません。これは、JMX仕様に準拠して計測されたあらゆるリソースは、必要なサービスを提供するすべてのJMXエージェントを使用できるためです。さらに、エージェントでは、アクセスする管理アプリケーションの機能についての情報は必要ありません。

リソースのリモート管理

JMX APIインストゥルメンテーションは、Simple Network Management Protocol (SNMP)のような既存の管理プロトコルや独自のプロトコルを使用してアクセスされます。MBeanサーバーでは、プロトコル・アダプタやコネクタを使用して、エージェントのJava仮想マシン(JVM)の外部にあるリモート管理アプリケーションからJMXエージェントにアクセスできるようにします。

どのアダプタも、MBeanサーバーに登録されたすべてのMBeanに特有のプロトコルを使用して、ビューを提供します。たとえばHTMLアダプタは、MBeanをブラウザに表示できます。

コネクタは、マネージャとJMXエージェントの間の通信を処理する、マネージャ側のインタフェースを備えています。各コネクタは異なるプロトコルを通じて、同じリモート管理インタフェースを提供します。リモート管理アプリケーションでこのインタフェースを使用すると、プロトコルに関係なく、透過的にネットワークを介してJMXエージェントに接続できます。

JMXテクノロジには、JMX APIインストゥルメンテーションをリモート・アプリケーションにエクスポートするための、Remote Method Invocation (RMI)を基にした標準的なソリューションがあります。JMX Remote APIでは、TCPソケットを直接基にしたオプションのプロトコルであるJMX Messaging Protocol (JMXMP)も定義しています。JMX Remote APIの実装では、このオプションのプロトコルをサポートする必要はありません。Java SEプラットフォームにはオプションのコネクタは含まれていません。詳細は、JMXテクノロジのバージョンを参照してください。

JMX Remote API仕様では、既存の検出、検索インフラストラクチャを使用してJMXエージェントを通知したり検索したりする方法が説明されています。たとえば、Java Management Extensions (JMX)テクノロジのチュートリアルを参照してください。この仕様では、独自の検出、検索サービスは定義されていません。既存の検出、検索サービスの使用はオプションです。JMXエージェントのアドレスをURLの形式でエンコードし、そのURLをマネージャに通知することもできます。

3 JMXテクノロジのリソースの計測

この章では、JMXテクノロジを使用した管理でリソースを計測する際の概念について、次のセクションで説明します。

- 管理可能なリソース

- 管理対象Bean (MBean)

- Java仮想マシンのインストゥルメンテーション

管理可能なリソース

JMXテクノロジを使用すると、アプリケーション、サービスの実装、デバイス、ユーザーなど、様々なタイプのリソースを管理できます。指定されたリソースをJMXテクノロジで管理するには、そのリソースはJava言語で開発されているか、少なくともJava言語ラッパーが提供されている必要があります。また、リソースは管理対象Bean (MBean)として知られている1つ以上のJavaオブジェクトによって、JMX仕様に従って計測されている必要があります。

アプリケーションやデバイスの開発者は、MBeanとして計測されているオブジェクトの細分性を自由に選択できます。MBeanはアプリケーションで最小のオブジェクトを表すこともあれば、アプリケーション全体を表す場合もあります。管理インタフェースを念頭に置いて設計されたアプリケーション・コンポーネントは、通常、MBeanになることができるように記述されています。MBeanは、管理インタフェースを持たないレガシー・コードのラッパーとして、またはレガシー管理インタフェースを持つコードのプロキシとして使用できます。

管理対象Bean (MBean)

リソースとその計測を実装したJavaオブジェクトは、管理対象Bean (MBean)と呼ばれます。MBeanはJMX仕様(JSR 3)に定義された設計パターンおよびインタフェースに従う必要があります。これにより、すべてのMBeanで管理対象リソースの計測が標準化された方法で提供されることが保証されます。

指定されたリソースの計測は、標準または動的な1つ以上のMBeanによって行われます。標準MBeanは、JavaBeans(TM)コンポーネント・モデルに由来する特定の設計パターンに準拠したJavaオブジェクトです。動的MBeanは、実行時に柔軟性が高い方のインタフェースに準拠します。MXBeanは、定義済の型セットのみを参照します。

JMXエージェントの使用で説明するように、リソースの計測により、リソースがエージェント・レベルで管理可能になります。MBeanでは、JMXエージェントでMBeanを操作するための知識は不要です。

MBeanは、実装が柔軟、簡潔、容易であるように設計されています。アプリケーション、サービス、またはデバイスの開発者は、標準的な方法で製品を管理することができ、複雑な管理システムに対する理解や投資は必要ありません。既存のオブジェクトは、標準MBeanを生成するように発展させることや、動的MBeanとしてラップすることが簡単に行えるため、既存のリソースは、最小限の労力で管理可能になります。

計測レベルは、MBeanが他のレベルのコンポーネントに対する通知イベントを生成して伝播できる通知メカニズムを指定します。

MBeanの管理インタフェースは、次で構成されています。

- 読出しや書込み可能な名前付きおよび型付き属性

- 呼出し可能な名前付きおよび型付き操作

- MBeanが送出可能な型付き通知

標準MBeanのJavaクラスでは、その属性や操作で直接管理可能なリソースを公開しています。属性は、ゲッターおよびセッター・メソッドを介して公開されている内部エンティティです。操作は、クラスのその他のメソッドのうち、管理側で利用可能なメソッドです。これらのメソッドはすべてMBeanインタフェースに静的に定義されており、JMXエージェントでは、イントロスペクションを通じてこれらのメソッドを確認できます。これが新しいリソースを管理可能にするいちばんわかりやすい方法です。

動的MBeanは、実行時にその管理インタフェースを定義します。たとえば、構成MBeanは、XMLファイルの解析により、公開する属性の名前と型を決定できます。

MXBeanは新しいタイプのMBeanで、定義済みの型セットだけを参照するMBeanのコーディングが簡単にできます。この方法なら、リモート・クライアントを含むクライアントは、MBeanの型を示すモデル固有のクラスにアクセスしなくても、MBeanを利用できます。

Java仮想マシンのインストゥルメンテーション

Java仮想マシン(JVM)は、JMXテクノロジを使用して高度に計測されています。JMXエージェントを起動して、組込みのJVMインストゥルメンテーションへのアクセスが簡単にできます。これによって、JMXテクノロジでリモートにJVMをモニターおよび管理できます。

JMXテクノロジを使用してJVMをモニターおよび管理する詳細については、Java Platform, Standard Edition Management Developer's Guideを参照してください。

4 JMXエージェントの使用

Java Management Extensions (JMX)エージェントは、Java仮想マシン(JVM)内で実行される管理エンティティです。管理対象Bean (MBean)と管理アプリケーションとのパイプ役として機能します。次のセクションでは、JMXエージェントの様々なコンポーネントについて説明します。

- MBeanサーバー

- エージェント・サービス

- プロトコル・アダプタとコネクタ

MBeanサーバー

MBeanサーバーは、JMXエージェントのコア・コンポーネントです。管理操作に公開されているJMXエージェント内のオブジェクトのレジストリです。MBeanサーバーに登録されているオブジェクトが、管理アプリケーションに公開されます。MBeanサーバーはMBeanの管理インタフェースのみを公開し、オブジェクトの直接参照は公開しません。

エージェントのJVMの外部から管理するリソースは、MBeanとしてサーバーに登録する必要があります。MBeanサーバーには同じJVM内でMBeanにアクセスするための標準化されたインタフェースがあり、ローカル・オブジェクトにとって管理可能なリソースを操作できるという利点があります。MBeanは次によってインスタンス化され登録されます。

- 別のMBean

- エージェント自身

- リモート管理アプリケーション

MBeanを登録する場合は、一意のオブジェクト名を割り当てる必要があります。管理アプリケーションではオブジェクト名を使用して、管理操作を実行する対象となるオブジェクトを特定します。MBeanで利用可能な操作には、次の操作があります。

- MBeanの管理インタフェースの検出

- 属性値の読み書き

- MBeanによって定義された操作の実行

- MBeanによって送られた通知の取得

- オブジェクト名または属性値を使用したMBeanのクエリー

エージェント・サービス

エージェント・サービスとは、MBeanサーバーに登録されたMBeanの管理操作を実行できるオブジェクトのことです。エージェントに管理機能を持たせることで、JMXを使用すればより強力な管理ソリューションを構築できます。エージェント・サービスはMBeanとなる可能性もあり、このときはエージェント・サービスとその機能をMBeanサーバーから制御できます。JMX仕様では、次のエージェント・サービスを定義しています。

- 管理アプレット(m-let)サービスを介した動的クラス・ローディングにより、ネットワークから動的にダウンロードされた新しいクラスとネイティブ・ライブラリを取得し、インスタンス化する。

- MBean属性の数値または文字列値をモニターし、各種の変更を他のオブジェクトに通知できる。

- タイマーにより、スケジューリング・メカニズムを提供し、事前に定義した間隔で通知を送信できる。

- 関係サービスではMBean間の関係を定義し、その関係の一貫性を維持する。

プロトコル・アダプタとコネクタ

プロトコル・アダプタとコネクタを使用すると、リモート管理アプリケーションからエージェントにアクセスできます。MBeanサーバーでインスタンス化され登録された、すべてのMBeanに特有のプロトコルを使用してビューを提供します。JVMの外部の管理アプリケーションでは、次のことが可能になります。

- 既存のMBeanの属性の取得または設定

- 既存のMBean上で操作の実行

- 新しいMBeanのインスタンス化と登録

- MBeanが送る通知の登録と受信

したがってJMXエージェントを管理するには、少なくとも1つはプロトコル・アダプタやコネクタを含まなければなりません。Java SEプラットフォームには、標準Remote Method Invocation (RMI)コネクタが含まれています。エージェントは1つ以上のプロトコル・アダプタやコネクタを含めることができ、様々なプロトコルによって同時にリモートで管理およびモニターできます。

プロトコル・アダプタ

プロトコルアダプタは、指定されたプロトコルを介したJMXエージェントの管理ビューを提供します。MBeanの操作およびMBeanサーバーを指定されたプロトコルの形式に変換します。また、SNMPのような別の情報モデルへの変換も行います。Java SEプラットフォームは、プロトコルアダプタを標準装備していません。

プロトコル・アダプタに接続する管理アプリケーションは、通常、指定されたプロトコル専用です。これは、特定の管理プロトコルに依存した従来の管理ソリューションの典型的なケースです。管理アプリケーションはJMXエージェントに対して、MBeanサーバーのリモート形式でアクセスするのではなく、MBeanサーバーの操作にマップされた操作でアクセスします。

コネクタ

コネクタは、エージェントとリモート管理アプリケーションを接続するために使用されます。この場合のリモート管理アプリケーションは、JMXテクノロジに対応し、つまり、JMX仕様の分散サービスを使用して開発された管理アプリケーションのことです。この種の通信は、エージェント内のコネクタ・サーバーや、マネージャ内のコネクタ・クライアントが行います。

これらのコンポーネントは、特定のプロトコルを使用してポイントツーポイントで管理操作を透過的に伝送します。JMXリモートAPIはMBeanサーバーに対するリモート・インタフェースを提供し、管理アプリケーションはこのインタフェースを通じて操作を実行します。コネクタは指定されたプロトコル専用ですが、あらゆるコネクタは同じリモート・インタフェースを備えているため、管理アプリケーションではどのコネクタも同じように使用できます。

標準JMXコネクタの詳細は、JMXコネクタを使用したリソースのリモート管理を参照してください。

5 JMXコネクタを使用したリソースのリモート管理

『Java Management Extensions Instrument and Agent Specification』では、「コネクタ」という概念を定義しています。コネクタを使用すると、Java Management Extensions (JMX)テクノロジのMBeanサーバーからJavaテクノロジベースのリモート・クライアントへのアクセスが可能になります。コネクタのクライアント側は、MBeanサーバーと基本的に同じインタフェースをエクスポートします。

コネクタは、コネクタ・クライアントとコネクタ・サーバーからなります。コネクタ・サーバーはMBeanサーバーに接続して、クライアントからの接続要求を待機します。コネクタ・クライアントは、コネクタ・サーバーとの接続を確立します。通常、コネクタ・クライアントは、コネクタ・サーバーとは別のJava仮想マシン(JVM)内にあり、別のマシン上で実行されることが多くあります。

コネクタは、さまざまな実装が可能です。特に、クライアントとサーバーの間の接続で通信するためのプロトコルは多種多様です。

コネクタ・サーバーには通常、アドレスがあり、コネクタ・クライアントとコネクタ・サーバーの間で接続を確立するために使用されます。コネクタによっては、接続の確立のために、接続スタブを用意している場合もあります。接続が確立される方法は、使用する検出、検索テクノロジに依存します。検出、検索サービスを参照してください。

このセクションでは、JMX Remote API仕様で定義されたさまざまな種類のコネクタと、コネクタで使用されるプロトコルについて説明します。

- RMIコネクタ: JMX Remote API標準に準拠する実装では、標準Remote Method Invocation (RMI)プロトコルをサポートする必要があります。

- ジェネリック・コネクタ: JMX Remote API標準では、TCPソケットを直接基にしたオプションのプロトコルであるJMX Messaging Protocol (JMXMP)を定義しています。標準の実装では、JMXMPコネクタを除外することもできますが、RMIコネクタは除外できません。Java SEプラットフォームにはオプションのJMXMPコネクタは含まれていません。

- ユーザー定義プロトコル: コネクタではJMXテクノロジで定義されていないプロトコルを実装することもできます。

RMIコネクタ

JMX Remote API標準では、RMIを基にした標準プロトコルを定義しています。RMIコネクタは、JMX Remote APIの各実装に存在しなければなりません。

RMIコネクタは、Java Remote Method Protocol (JRMP)トランスポートをサポートします。

JRMP上のRMIコネクタでは、クライアントとサーバーの間の接続をセキュリティ保護および認証するための単純なメカニズムを備えています。このメカニズムでは、RMIコネクタを使用する環境に対して、基本的なレベルのセキュリティを提供します。ジェネリックJMXMPコネクタでは、より高度なレベルのセキュリティを提供しています。

クライアントとサーバーの間の接続でSecure Socket Layer (SSL)を使用するようにRMIソケット・ファクトリを使用することで、JRMP上のRMIコネクタのセキュリティを向上できます。

ジェネリック・コネクタ

JMX Remote API仕様では、Java SEプラットフォームに含まれていないオプションのジェネリック・コネクタを定義しています。このコネクタは、プラガブルなモジュールを追加することで構成でき、次の内容を定義します。

- 要求をクライアントからサーバーに送信したり、応答や通知をサーバーからクライアントに送信したりするためのトランスポート・プロトコル

- クライアントからサーバーに送信され、そのクラス・ローダーがターゲットMBeanに依存するようなオブジェクトのオブジェクト・ラッピング

JMX Messaging Protocol (JMXMP)コネクタは、トランスポート・プロトコルがTCPベースで、オブジェクト・ラッピングがネイティブJava直列化であるような構成のジェネリック・コネクタになります。セキュリティはRMIコネクタの場合より高度です。セキュリティは、Java Secure Socket Extension (JSSE)、Java Authentication and Authorization Service (JAAS)、およびSimple Authentication and Security Layer (SASL)が基になります。

ジェネリックコネクタとそのJMXMP構成はオプションです。つまり、JMX Remote APIの実装に常に含まれているわけではありません。Java SEプラットフォームにはオプションのジェネリックコネクタは含まれていません。

ユーザー定義プロトコル

JMX Remote API仕様では、すべてのプロトコル用のコネクタは定義していません。JMX Remote API標準に定義されていないプロトコルを基にしたコネクタを実装できます。たとえば、HTTP/Sを使用するプロトコルを基にしたコネクタを実装できます。JMX仕様では、ユーザー定義プロトコルを基にしたコネクタの実装方法について説明しています。

6 検出、検索サービス

『Java Management Extensions (JMX) Remote API Specification』では、既存の検出、検索インフラストラクチャを使用してJMX APIエージェントを通知したり検索したりする方法が説明されています。この仕様では、JMXテクノロジ固有の検出、検索APIについては定義されていません。

この章では、JMXテクノロジで使用できる既存の検出、検索インフラストラクチャの概要を、次のセクションで簡単に説明します。

- 検索サービスについて

検出および検索インフラストラクチャの詳細は、『Java Management Extensions Remote API 1.0 Specification』の「References」セクションを参照してください。

検索サービスについて

JMXエージェントとJMXクライアントが検索サービスを使用できます。1つのJava VMには、多数のJMXエージェントやJMXクライアントが含まれている場合があります。

- JMXエージェントは、次の機能からなる論理サーバー・アプリケーションです。

- 1つの管理対象Bean (MBean)サーバー

- JMXコネクタ・サーバーが1つ以上。JMXコネクタ・サーバーにより、そのMBeanサーバーに格納されるMBeanに対してリモート・クライアントがアクセスできるようになる

- JMXクライアントは、JMXエージェントとのクライアント接続を開く論理クライアント・アプリケーションです。

『Java Management Extensions (JMX)テクノロジのチュートリアル』では、検索サービスを使用してJMXエージェントを通知したり検索したりする方法が示されています。3つのインフラストラクチャの手順は似ています。これらの間で大きく異なる点は、SLPとJNDIの場合は、検索サービスでエージェントが登録するのはアドレスですが、Jiniネットワーク・テクノロジを使用した場合に登録するのはJMXコネクタ・スタブです。

注意:

既存の検出、検索サービスの使用はオプションです。JMX APIエージェントのアドレスをURLの形式でエンコードし、そのURLをマネージャに通知することもできます。

Service Location Protocol (SLP)の使用

Service Location Protocol (SLP)では、企業ネットワーク内でネットワーク化されたサービスの存在、位置、および構成をネットワーク機能アプリケーションが検出できるフレームワークを提供します。

次の手順は、SLP検索サービスを使用してJMXエージェントを通知および検索するための、JMX Remote API仕様で定義された手順をまとめたものです。

- JMXエージェントは1つ以上のJMXコネクタ・サーバーを作成します。

- 公開する各コネクタについて、JMXエージェントはSLP検索サービスを使用して、そのアドレスを登録します。このとき場合によっては、エージェントやコネクタを限定し、フィルタとして使用できるような追加の属性を指定します。

- JMXクライアントはSLP検索サービスをクエリーし、クエリーに当てはまる1つ以上のアドレスを取得します。

- 最後に、JMXクライアントは、取得したアドレスで特定されるサーバーに対して接続しているコネクタを取得します。

JMX Remote API仕様では、SLPプロトコルに準拠したURLスキームを定義しています。『Java Management Extensions (JMX) Remote API Specification』を参照してください。仕様では、登録時に指定される、必須およびオプションのSLP検索属性も定義しています。

Jiniネットワーク・テクノロジの使用

Jiniネットワーク・テクノロジは、オープンなソフトウェア・アーキテクチャで、開発者はネットワークの変化に対応可能なサービスを作成できます。Jiniの仕様では、標準の検索サービスがあります。実行中のJini検索サービスは、API呼出しで検出できます。

次の手順は、Jini検索サービスを使用してJMXエージェントを通知および検索するための、JMX Remote API仕様で定義された手順をまとめたものです。

- JMXエージェントは1つ以上のJMXコネクタ・サーバーを作成します。

- 公開する各コネクタについて、JMXエージェントはJini検索サービスを使用して、JMXコネクタ・スタブを登録します。このとき場合によっては、エージェントやコネクタを限定し、フィルタとして使用できるような追加の属性を指定します。

- JMXクライアントはJini検索サービスをクエリーし、クエリーに当てはまる1つ以上のコネクタ・スタブを取得します。

- 最後に、JMXクライアントは、取得したコネクタ・スタブを使用して、サーバーに直接接続します。

JMX Remote API仕様では、Jiniテクノロジベースのエントリによるバインドを定義しています。『Java Management Extensions (JMX) Remote API Specification』を参照してください。仕様では、エージェント・コネクタの登録時に指定する、必須およびオプションのエントリも定義しています。

LDAPバックエンドでのJava Naming and Directory Interface (JNDI) APIの使用

Java Naming and Directory Interface(JNDI) APIは、Javaプラットフォームの標準の機能拡張です。Javaテクノロジ対応のアプリケーションに、複数のネームおよびディレクトリ・サービスに対する統一的なインタフェースを提供します。

JMX Remote API仕様では、LDAPサーバーを使用して、JMXエージェントに公開されたJMXコネクタの情報を格納および取得する方法が説明されています。

次の手順は、JNDI検索サービスを使用するための、JMX Remote API仕様で定義された手順をまとめたものです。

- JMXエージェントは1つ以上のJMXコネクタ・サーバーを作成します。

- 公開する各コネクタについて、JMXエージェントはJNDI検索サービスを使用して、そのアドレスを登録します。このとき場合によっては、エージェントやコネクタを限定し、フィルタとして使用できるような追加の属性を指定します。

- JMXクライアントはJNDI検索サービスをクエリーし、クエリーに当てはまる1つ以上のアドレスを取得します。

- 最後に、JMXクライアントは、取得したアドレスで特定されるサーバーに対して接続しているコネクタを取得します。

JMX Remote APIでは、アドレスを登録するためのLDAPスキーマを定義し、また登録したエージェントをクライアントが検出する方法について説明しています。詳細は、「JMX 1.4仕様」を参照してください。仕様では、リース・メカニズムも定義しています。

7 JMXテクノロジのバージョン

Java Management Extensionsテクノロジ(JMX)は、Java Platform Standard Edition (Java SE) 5.0のJavaプラットフォームに標準装備されています。JMXテクノロジは、密接に関連する2つのJava Specification Requests (JSR)として、Java Community Process (JCP)によって開発されました。次のセクションでは、Java SE 5.0に実装されているJSRのバージョンについて説明します。

JMXの計測およびエージェント仕様(JSR 3)

Java SE 9プラットフォームは、JMX Specificationのバージョン1.4 (保守リリース、2006年10月)を実装しています。ダウンロードで提供されていた正誤表にあった修正が含まれています。

JMX Remote API Specification (JSR 160)

Java SE 9プラットフォームは、JMX Remote API Specificationのバージョン1.4 (保守リリース、2006年10月)を実装しています。

JSR 160では、標準のRMIコネクタの他に、TCPソケットを基にした、オプションのJMX Messaging Protocol (JMXMP)も定義しています。Java SEプラットフォームにこれらのオプションのコネクタは含まれていません。より高度なレベルのセキュリティを必要とする場合は、JMXMPコネクタを使用できます。

JMXMPコネクタを使用する場合は、JSR 160リファレンス実装をこのセクションの冒頭で指定したダウンロード・ページからダウンロードし、jmxremote_optional.jarファイルをclasspathに追加してください。JSR 160リファレンス実装に含まれるJMX Remote API Tutorialには、JMXMPコネクタの使用例があります。

8 Java Management Extensions (JMX) APIの仕様

JMXの目次Java Management Extension (JMX) APIは、管理とモニタリングのための標準APIです。

JMX APIには、Javadocユーティリティで生成された次のドキュメント・パッケージが提供されています。

- javax.management

- javax.management.loading

- javax.management.modelmbean

- javax.management.monitor

- javax.management.openmbean

- javax.management.relation

- javax.management.remote

- javax.management.remote.rmi

- javax.management.timer

パートII Java Management Extensions (JMX)テクノロジのチュートリアル

JMXテクノロジのチュートリアルの概要

このチュートリアルには、Java Platform, Standard Editionに提供されているJMXテクノロジの主要な機能の使用方法の例が用意されています。

このチュートリアルは、例題に沿って作業を進めながら最初から順番に読む構成をとっています。チュートリアルの冒頭で行う作業が、チュートリアルの後半部分で必要な場合があります。したがって、チュートリアルの途中から始めた場合、特定の例題に必須のアクションが抜けてしまう可能性があります。

タスクを実行する必要があるところでは、手順がアクション番号でマークされ、サブタスクが小文字でマークされています。

このチュートリアルを開始する前に

このチュートリアルでは、Java Management Extensions Technology User's Guideで紹介した概念とテクノロジを例をあげて示します。したがって、このチュートリアルの作業に入る前に、概要を読んでおく必要があります。このチュートリアルの情報を十分に活用するためには、次のプロトコルおよび仕様も熟知している必要があります。

- Remote Method Invocation

- Lightweight Directory Access Protocol

- Service Location Protocol (SLP)

- JiniTMネットワーク・テクノロジ

- Java Naming and Directory InterfaceTM (JNDI) API

- Java Secure Socket Extension (JSSE)

- JAAS (Java Authentication and Authorization Service)

- 『Java Management Extensionsの仕様1.4』

このチュートリアルの構成

このチュートリアルでは、以降の章に幅広いカテゴリの例が用意されています。

- スタート・ガイドには、初期設定情報の一部を記載します。

- JMX APIの基本要素では、JMX仕様のコア概念を紹介します。

- JMXコネクタでは、標準タイプと動的タイプのMBeanを実装し、MBean上で操作をローカルおよびリモートに実行する方法の例を示します。

- 検索サービスでは、JMXテクノロジと併用できる検索サービスを例をあげて示します。

- セキュリティでは、セキュリティ構成の例をいくつか示します。

9 スタート・ガイド

この章では、Java Management Extensions (JMX)の例題を使用した、入門に必要な手順について説明します。以降の章で説明するすべての例に適用される手順を説明します。

プラットフォーム情報

このチュートリアルの例で使用されるすべての変数割当ておよびコマンドは、UNIX Kornシェル構文を使用して定義しています。Solaris、Linux、またはMac OS XプラットフォームでKornシェル以外のシェルを実行している場合は、これらのコマンドを現在使用しているシェル環境に合わせて変更する必要があります。

Microsoft Windowsオペレーティング環境を実行している場合の変更作業は、ほとんどの場合、パスのスラッシュ(/)をバックスラッシュ(\)に置き換え、コロン(:)をセミコロン(;)に置き換えるのみです。特定のMicrosoft Windowsのコマンドが指定されるのは、提示されたSolaris、Linux、またはMac OS Xのコマンドと大きく異なる場合のみです。

10 JMX APIの基本要素

この章では、Java Management Extensions (JMX) APIのコア・コンポーネントである管理対象Bean (MBean)について説明します。

MBeanはJavaBeanTMに似た管理対象Javaオブジェクトであり、その設計パターンはJMX仕様の計測レベルの規定に従います。MBeanは、管理対象となるデバイス、アプリケーションまたは任意のリソースを表示できます。MBeanは管理インタフェース、すなわち読込みと書込みの一方または両方が可能な属性セットと、呼出し可能な操作セット、および自己記述を開示しています。管理インタフェースは、MBeanインスタンスの生存期間を通じて変化しません。また、MBeanは、定義済みの特定のイベントが起こった場合に通知を発行します。

JMX仕様では、標準MBean、動的MBean、open MBean、およびmodel MBeanという4種類のMBeanを定義しています。このチュートリアルの例では、もっとも単純なMBeanである標準MBeanについて説明します。

標準MBean

標準MBeanは、JavaインタフェースSomethingMBeanとそのインタフェースを実装するJavaクラスSomethingを記述することで定義できます。インタフェースのすべてのメソッドは、MBeanの属性か操作のいずれかを定義します。デフォルトでは、すべてのメソッドは操作を定義します。属性と操作は、特定の設計パターンに従った簡単なメソッドです。標準MBeanは、開示されたすべての属性と操作のメソッドを一覧にしたMBeanインタフェースと、このインタフェースを実装し、計測されたリソースに機能を割り当てるクラスから構成されます。

以降のセクションでは、標準MBeanの例と、MBeanを管理する簡単なJMXエージェントについて説明します。コード・サンプルはJMXの基本要素にあります。例をディレクトリwork_dir/jmx_examples/Essential/com/example/mbeansから実行できます。

MBeanインタフェース

HelloMBeanという基本的なMBeanインタフェースの例を、コード例2-1 MBeanインタフェース、HelloMBeanに示します。

コード例2-1 MBeanインタフェース、HelloMBean

package com.example.mbeans;

public interface HelloMBean {

public void sayHello();
public int add(int x, int y);

public String getName();

public int getCacheSize();
public void setCacheSize(int size);
}

MBeanインタフェースは、このインタフェースを実装するJavaクラスの名前の後にMBeanを加えて名前を構成します。このインタフェースがHelloMBeanです。このインタフェースを実装するHelloクラスについては、MBeanの実装で説明します。

JMX仕様によると、MBeanインタフェースは、名前と型の指定された読込み可能で、場合によっては書込み可能な属性と、MBeanが管理するアプリケーションにより呼び出すことが可能な、名前と型の指定された操作から構成されます。コード例2-1 MBeanインタフェース、HelloMBeanに示したHelloMBeanインタフェースでは、2つの操作(Javaメソッドadd()とsayHello())を宣言しています。

HelloMbeanで宣言される2つの属性のうち、Nameは読込み専用の文字列で、CacheSizeは読み込みと書込みの両方が可能な整数です。取得メソッドと設定メソッドは、管理対象アプリケーションに属性の値へのアクセスと、場合によっては値の変更を許可するために宣言されます。JMX仕様に定義されるように、取得メソッドはgetから名前が始まり、voidを返さないすべてのpublicメソッドです。取得メソッドを使用すると、マネージャは返されたオブジェクトの型と一致する属性の値を読み込むことができます。設定メソッドは名前がsetから始まり、単一のパラメータをとるすべてのpublicメソッドです。設定メソッドを使用すると、マネージャはパラメータと同じ型の値を属性に新たに書き込むことができます。

次のセクションでは、これらの操作および属性の実装を説明します。

MBeanの実装

コード例2-2 MBeanの実装クラス、Helloに示したHelloクラスは、HelloMBeanを実装します。

コード例2-2 MBeanの実装クラス、Hello

package com.example.mbeans;

public class Hello implements HelloMBean {
public void sayHello() {
System.out.println("hello, world");
}

public int add(int x, int y) {
return x + y;
}

public String getName() {
return this.name;
}

public int getCacheSize() {
return this.cacheSize;
}

public synchronized void setCacheSize(int size) {
this.cacheSize = size;

System.out.println("Cache size now " + this.cacheSize);
}

private final String name = "Reginald";
private int cacheSize = DEFAULT_CACHE_SIZE;
private static final int DEFAULT_CACHE_SIZE = 200;
}

例2-2では、JavaクラスHelloは、HelloMBeanで宣言された操作と属性を定義します。この例からわかるように、例sayHello()とadd()の操作はきわめて簡単ですが、実際の操作は必要に応じて簡単にも、複雑なものにもできます。

Name属性を取得するメソッドと、cacheSize属性を取得し設定するメソッドも定義されます。この例では、Name属性の値は変わりませんが、実際の場面では、管理対象リソースの実行により変わる場合があります。たとえば、属性は稼動時間やメモリーの使用量などの統計を表す場合があります。ここでは、属性は「Reginald」という名前だけです。

setCacheSizeメソッドを呼び出すと、cacheSize属性の値を、宣言されたデフォルトの値200から変更できます。実際には、cacheSize属性を変更する場合は、エントリの破棄や新しいエントリの割り当てなど、ほかの操作を実行しなければなりません。この例では、キャッシュ・サイズが変更されたことを確認するメッセージのみが出力されますが、println()を呼び出す操作のかわりに、より複雑な操作を定義できます。

Hello MBeanとそのインタフェースを定義すると、次のセクションに示すように、Hello MBeanとインタフェースで表されるリソースを、Hello MBeanとインタフェースを使用して管理できます。

リソースの管理

Java Management Extensions Technology User's Guideに説明されているように、MBeanによってリソースが計測された後は、そのリソースの管理はJMXエージェントにより実行されます。

JMXエージェントのコア・コンポーネントはMBeanサーバーです。MBeanサーバーは、MBeanが登録されている管理オブジェクト・サーバーのことです。MBeanサーバー実装の詳細は、MBeanServerインタフェースのAPIドキュメントを参照してください。JMXエージェントには、MBeanを管理するための一連のサービスも含まれます。コード例2-3 JMXエージェントの作成では、Mainという基本的なJMXエージェントを示しています。

コード例2-3 JMXエージェントの作成

package com.example.mbeans;

import java.lang.management.*;
import javax.management.*;

public class Main {

public static void main(String[] args) throws Exception {

MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

ObjectName name = new ObjectName("com.example.mbeans:type=Hello");

Hello mbean = new Hello();

mbs.registerMBean(mbean, name);

System.out.println("Waiting forever...");
Thread.sleep(Long.MAX_VALUE);
}
}

例2-3では、JMXエージェントMainは、まずjava.lang.management.ManagementFactoryクラスのgetPlatformMBeanServer()メソッドを呼び出して、プラットフォーム上で稼動する任意のMBeanサーバーを取得します。プラットフォーム上で稼動中のMBeanが存在しない場合、getPlatformMBeanServer()によりJMXメソッドMBeanServerFactory.createMBeanServer()が呼び出され、自動的に稼動中のMBeanが作成されます。Mainで取得されるMBeanServerインスタンスは、mbsの名前が付けられます。

次に、Mainは作成するMBeanインスタンスのために、オブジェクト名を定義します。すべてのJMX MBeanにオブジェクト名が定義される必要があります。オブジェクト名はJMXクラスObjectNameのインスタンスであり、ドメインとキー・プロパティのリストを必ず含めるなど、JMX仕様で定義される構文に従う必要があります。この構文の詳細は、ObjectNameクラスのAPIドキュメントを参照してください。Mainで定義されるオブジェクト名、nameでは、ドメインはcom.example.mbeans (MBeanの例が格納されたパッケージ)です。また、キー・プロパティはこのオブジェクトがHello型であることを宣言します。

Helloオブジェクトのインスタンス、mbeanが作成されます。このHelloオブジェクトは、MBeanの実装で定義されたMBean Helloのインスタンスです。

Helloオブジェクトmbeanは、オブジェクト名nameを使用してMBean server mbsにMBeanとして登録されます。このために、オブジェクトとオブジェクト名を渡してJMXメソッドMBeanServer.registerMBean()を呼び出します。

Hello MBeanをMBeanサーバーに登録したあと、Mainは管理操作がHelloで実行されるのを待機します。この例の範囲では、これらの管理操作はsayHello()とadd()を呼び出し、属性値を取得および設定しています。

標準MBeanの例題の実行

例題のクラスを検証した後、例題を実行できます。Java Platform, Standard EditionにはJConsoleという管理およびモニタリング・コンソールが含まれており、この例ではMBeanとの対話に使用されています。JConsoleはJavaSE_HOME/bin/jconsoleにあります。JavaSE_HOMEはJava Platform, Standard Edition (Java SEプラットフォーム)がインストールされたディレクトリです。

例題を実行するには、次の手順を実行します。

1. JMXの基本要素にあるソース・コードをwork_dir/jmx_examples/Essentialにコピーします。

2. Javaクラスの例をコンパイルします。
$ javac com/example/mbeans/*.java

3. Mainアプリケーションを起動します。
$ java com.example.mbeans.Main

何かの発生を待機中のMainに関する確認が表示されます。

4. 同じマシンの別の端末ウィンドウで、JConsoleを起動します。
$ jconsole

JConsoleツールが開き、接続可能な稼動中のJMXエージェントのリストが表示されます。

5. 「新規接続」ウィンドウのリストからcom.example.mbeans.Mainを選択し、「接続」をクリックします。
プラットフォームの現在のアクティビティのサマリーが表示されます。

6. 「MBean」タブをクリックします。
このパネルに、現在MBeanサーバーに登録されているすべてのMBeanが表示されます。

7. 左フレームにあるMBeanツリーのcom.example.mbeansノードを展開します。
Mainで作成され、登録されたMBean Helloの例が表示されます。Helloをクリックすると、関連するAttributesおよびOperationsノードがMBeanツリーに表示されます。

8. MBeanツリー内のHello MBeanノードをクリックしてHello MBeanのメタデータとそれに関連する記述子を表示します。

9. MBeanツリーにあるHello MBeanのAttributesノードをクリックします。
Helloクラスで定義されたMBean属性が表示されます。

10. CacheSize属性の値を150に変更します。
Mainを起動した端末ウィンドウで、この属性の変更を確認が表示されます。

11. MBeanツリーにあるHello MBeanのOperationsノードをクリックします。
ここで、Hello MBeanで宣言された2つの操作、sayHello()とadd()が表示されます。

12. 「sayHello」ボタンをクリックして、sayHello()操作を起動します。
メソッドが正常に呼び出されたことがJConsoleのダイアログ・ボックスに通知され、Mainが起動している端末のウィンドウに「hello, world」というメッセージが表示されます。

13. add()操作で加算する2つの整数を指定し、「add」ボタンをクリックします。
「JConsole」ダイアログ・ボックスに解答が通知されます。

14. 「接続」をクリックし、次に「終了」をクリックして、JConsoleを終了します。

通知の送信

MBeanは状態の変化、検出されたイベント、または問題などを知らせる通知を生成します。

MBeanが通知を生成するためには、インタフェースNotificationBroadcasterか、またはそのサブインタフェースNotificationEmitterを実装している必要があります。通知の送信に必要な操作は、クラスjavax.management.Notificationまたはサブクラス(AttributeChangedNotificationなど)のインスタンスを構築し、それをNotificationBroadcasterSupport.sendNotificationに渡すだけです。

すべての通知に発行元があります。発行元は通知を発行したMBeanのオブジェクト名です。

すべての通知にはシーケンス番号が割り振られています。順序が重要な意味を持つ場合、および通知が間違った順序で処理される危険性がある場合、この番号を使用して同じソースから到着した通知を並べることができます。シーケンス番号をゼロにしてもかまいませんが、特定のMBeanから通知が到着するたびにインクリメントする方が適切です。

標準MBeanがディレクトリwork_dir/jmx_examples/Notification/com/example/mbeansで通知を発行する例を考えてみます。この例は、標準MBeanで示した例題と基本的には同じですが、Hello MBeanがNotificationBroadcasterインタフェースを実装している点で異なっています。

NotificationBroadcasterインタフェース

前述のように、この例題と標準MBeanで示した例題の唯一の違いは、MBeanの実装により通知の送信ができるという点です。コード例2-4 MBeanの通知の実装に示したように、通知はNotificationBroadcasterインタフェースを実装することで起動します。

コード例2-4 MBeanの通知の実装

package com.example.mbeans;

import javax.management.*;

public class Hello
extends NotificationBroadcasterSupport implements HelloMBean {

public void sayHello() {
System.out.println("hello, world");
}

public int add(int x, int y) {
return x + y;
}

public String getName() {
return this.name;
}

public int getCacheSize() {
return this.cacheSize;
}

public synchronized void setCacheSize(int size) {
int oldSize = this.cacheSize;
this.cacheSize = size;

System.out.println("Cache size now " + this.cacheSize);

Notification n =
new AttributeChangeNotification(this,
sequenceNumber++,
System.currentTimeMillis(),
"CacheSize changed",
"CacheSize",
"int",
oldSize,
this.cacheSize);

sendNotification(n);
}

@Override
public MBeanNotificationInfo[] getNotificationInfo() {
String[] types = new String[] {
AttributeChangeNotification.ATTRIBUTE_CHANGE
};
String name = AttributeChangeNotification.class.getName();
String description = "An attribute of this MBean has changed";
MBeanNotificationInfo info =
new MBeanNotificationInfo(types, name, description);
return new MBeanNotificationInfo[] {info};
}

private final String name = "Reginald";
private int cacheSize = DEFAULT_CACHE_SIZE;
private static final int DEFAULT_CACHE_SIZE = 200;

private long sequenceNumber = 1;
}

コード例2-4 MBeanの通知の実装に示したように、このHello MBeanの実装によりNotificationBroadcasterSupportクラスが拡張され、このクラス自体にNotificationEmitterインタフェースが実装されます。

操作と属性の設定方法は以前と同様ですが、唯一変わったのはcacheSize属性の設定メソッドがoldSizeという新しい値を定義する点です。この値は設定操作の前にcacheSize属性の値を記録します。

通知は、javax.management.Notificationを拡張するJMXクラスAttributeChangeNotificationのインスタンスnから構築されます。この通知はAttributeChangeNotificationにパラメータとして渡される次の情報に基づいて、setCacheSize()メソッドの定義内で構築されます。

- Hello MBeanなどの通知の発行元のオブジェクト名。簡単にthisと表される

- シーケンス番号。この例では、ロング名sequenceNumberが使われ、1に設定されたあと、1つずつインクリメントする

- タイムスタンプ

- 通知メッセージの内容

- 変更された属性の名前。この場合はcacheSize

- 変更された属性の型

- 古い属性値。この場合はoldSize

- 新しい属性値。この場合はthis.cacheSize

この後、通知nがNotificationBroadcasterSupport.sendNotification()メソッドに渡されます。

最後に、MBeanNotificationが定義され、特定のJavaクラスの通知、この場合はAttributeChangeNotificationに対してMBeanが発行した別の通知インスタンスの特性が説明されます。

MBeanインタフェースHelloMBeanとJMXエージェントMainは、前出の例で使用されたものと同じです。

MBeanの通知の例題の実行

クラスの例題を検証したあと、今度は例題を実行します。この例では、JConsoleを使用してHello MBeanと対話します。この例題を実行するには、次の手順を実行します。

1. JMX MBeanの通知からwork_dir/jmx_examples/Notificationにソース・コードをコピーします。

2. Javaクラスの例をコンパイルします。

$ javac com/example/mbeans/*.java

3. Mainアプリケーションを起動します。

$ java com.example.mbeans.Main

何かの発生を待機中のMainに関する確認が表示されます。

4. 同じマシンの別の端末ウィンドウで、JConsoleを起動します。

$ jconsole

JConsoleツールが開き、接続可能な稼動中のJMXエージェントのリストが表示されます。

5. 「新規接続」ウィンドウのリストからcom.example.mbeans.Mainを選択し、「接続」をクリックします。
プラットフォームの現在のアクティビティのサマリーが表示されます。

6. 「MBean」タブをクリックします。
このパネルに、現在MBeanサーバーに登録されているすべてのMBeanが表示されます。

7. 左フレームにあるMBeanツリーのcom.example.mbeansノードを展開します。
Mainで作成され、登録されたMBean Helloの例が表示されます。Helloをクリックすると、関連するAttributes、Operations、およびNotificationsノードがMBeanツリーに表示されます。

8. MBeanツリーにあるHello MBeanノードをクリックします。
これによって、MBeanのメタデータと関連する記述子が表示されます。

9. MBeanツリーにあるHello MBeanのNotificationsノードをクリックします。
空のパネルが表示されます。

10. 「Subscribe」ボタンをクリックします。
現在の受領通知数(0)が、Notificationsノード・ラベルに表示されます。

11. MBeanツリーにあるHello MBeanのAttributesノードをクリックし、CacheSize属性を150に変更します。
Mainを起動した端末ウィンドウで、この属性の変更を確認が表示されます。また、Notificationsノードに表示される受領通知数が1に変更されています。

12. MBeanツリーにあるHello MBeanのNotificationsノードをふたたびクリックします。
送信された通知の詳細が表示されます。

13. 「接続」をクリックし、次に「終了」をクリックして、JConsoleを終了します。

MXBeanの導入

MXBeanは新しいタイプのMBeanで、定義済みの型セットだけを参照するMBeanのコーディングが簡単にできます。この方法なら、リモート・クライアントを含むクライアントは、MBeanの型を示すモデル固有のクラスにアクセスしなくても、MBeanを利用できます。MXBeanは、クライアントに特にバンドル操作の構成を要求することなく、関連する値をバンドルする便利な手法を提供します。

標準MBeanの場合と同様、MXBeanを定義するには、SomethingMXBeanというJavaインタフェースとそのインタフェースを実装するJavaクラスを記述します。ただし、標準MBeanとは異なり、MXBeanではそのJavaクラスをSomethingと呼ぶ必要はありません。このインタフェース内の各メソッドは、MXBeanの属性と操作のいずれかを定義します。そのほか、@MXBean注釈を使用する場合は、インタフェース名にMXBean拡張子を付ける代わりに、Javaインタフェースに注釈を付けることもできます。

MXBeanは、クライアントに特にバンドル操作の構成を要求することなく、MBeanと対話しながら関連する値をMBeanにバンドルする便利な手法を提供します。MXBeanはJava 2 Platform, Standard Edition (J2SE) 5.0のjava.lang.managementパッケージに入っています。Java SE 6プラットフォームでは、java.lang.managementで定義された標準セットだけでなく、ユーザー自身のMXBeanを定義できます。

MXBeanの主な意図は、MXBeanインタフェースで参照されるjava.lang.management.MemoryUsageなどの型(この場合はjava.lang.management.MemoryMXBean)を標準型セットにマップすることにあります。その標準型セットはOpen Typeと呼ばれ、javax.management.openmbeanパッケージで定義されます。厳密なマッピングの規則は「MXBeanの仕様」に記載されていますが、大ざっぱにいえば、intやStringのような単純な型に変更はなく、MemoryUsageのような複雑な型はCompositeDataSupport標準型にマップされます。

jmx_examples.zipファイルをダウンロードして解凍すると、MXBeanの操作を説明したサンプル・プログラムがwork_dir/jmx_examples/MXBean/com/example/mxbeansディレクトリに作成されます。MXBeanのサンプルには、次のファイルが含まれています。

- QueueSamplerMXBeanインタフェース。

- MXBeanインタフェースを実装するQueueSamplerクラス。

- QueueSample Javaの型で、MXBeanインタフェース内のgetQueueSample()メソッドによって返されます。

- Main、サンプルを設定して実行するプログラム。

MXBeanのサンプルには、次のアクションが含まれています。

- type Queue<String>のリソースを管理する、単純なMXBeanを定義する。

- 呼び出されるとキューのスナップショットを作成するMXBeanの取得メソッドgetQueueSampleを宣言し、次の値をバンドルするJavaクラスQueueSampleを返す。

- スナップショットが作成された時間。

- キューのサイズ。

- 指定された時間のキューの先頭。

- MBeanサーバーにMXBeanを登録する。

QueueSamplerMXBeanインタフェース

コード例2-5 QueueSamplerMXBeanインタフェースは、QueueSamplerMXBeanインタフェースのサンプル・コードを示しています。

コード例2-5 QueueSamplerMXBeanインタフェース

package com.example.mxbeans;

public interface QueueSamplerMXBean {
public QueueSample getQueueSample();
public void clearQueue();
}

この例からわかるように、MXBeanインタフェースの宣言は標準MBeanの宣言とまったく同じです。QueueSamplerMXBeanインタフェースでは、getQueueSampleとclearQueueという2つの操作を宣言しています。

QueueSamplerクラス

QueueSamplerクラスは、コード例2-6 QueueSamplerクラスに示すように、QueueSamplerMXBeanインタフェースを実装しています。

コード例2-6 QueueSamplerクラス

package com.example.mxbeans;

import java.util.Date;
import java.util.Queue;

public class QueueSampler implements QueueSamplerMXBean {

private Queue<String> queue;

public QueueSampler(Queue<String> queue) {
this.queue = queue;
}

public QueueSample getQueueSample() {
synchronized (queue) {
return new QueueSample(new Date(), queue.size(), queue.peek());
}
}

public void clearQueue() {
synchronized (queue) {
queue.clear();
}
}
}

MXBeanインタフェースで宣言されたMXBean操作のgetQueueSample()およびclearQueue()は、QueueSamplerで定義されます。getQueueSample()操作は単純に、QueueSample Java型(java.util.Queueメソッドのpeek()およびsize()によって返された値を使用して作成)のインスタンスとjava.util.Dateのインスタンスを返します。

QueueSampleクラス

QueueSamplerによって返されたQueueSampleインスタンスは、コード例2-7 QueueSamplerクラスに示したQueueSampleクラスで定義されます。

コード例2-7 QueueSampleクラス

package com.example.mxbeans;

import java.beans.ConstructorProperties;
import java.util.Date;

public class QueueSample {

private final Date date;
private final int size;
private final String head;

@ConstructorProperties({"date", "size", "head"})
public QueueSample(Date date, int size, String head) {
this.date = date;
this.size = size;
this.head = head;
}

public Date getDate() {
return date;
}

public int getSize() {
return size;
}

public String getHead() {
return head;
}
}

QueueSampleクラスでは、MXBeanフレームワークがQueueSampleの取得メソッドをすべて呼び出して、指定されたインスタンスをCompositeDataに変換し、@ConstructorProperties注釈を使用して、CompositeDataからQueueSampleインスタンスを再構築します。

MXBeanの作成とMBeanサーバーへの登録

MXBeanインタフェースとこれを実装するクラス、および返されるJava型を定義したら、次はMXBeanを作成してMBeanサーバーに登録する必要があります。これらのアクションは、サンプル・クラスMainによって行われます。

コード例2-8 MXBeanのMainクラスの例

package com.example.mxbeans;

import java.lang.management.ManagementFactory;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import javax.management.MBeanServer;
import javax.management.ObjectName;

public class Main {

public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

ObjectName name =
new ObjectName("com.example.mxbeans:type=QueueSampler");

Queue<String> queue = new ArrayBlockingQueue<String>(10);
queue.add("Request-1");
queue.add("Request-2");
queue.add("Request-3");
QueueSampler mxbean = new QueueSampler(queue);

mbs.registerMBean(mxbean, name);

System.out.println("Waiting...");
Thread.sleep(Long.MAX_VALUE);
}
}

Mainクラスは、プラットフォームMBeanサーバーを取得して、MXBean QueueSamplerのオブジェクト名を作成し、QueueSampler MXBeanのQueueインスタンスを作成して処理します。次に、このQueueインスタンスを、新規作成されたQueueSampler MXBeanに送ります。これで標準MBeanとまったく同じように、MXBeanがMBeanサーバーに登録されます。

MXBeanの例題の実行

MXBeanの例題を実行するには、次の手順を実行します。

1. MXBeansからwork_dir/jmx_examples/MXBeanにソース・コードをコピーします。

2. Javaクラスの例をコンパイルします。

$ javac com/example/mxbeans/*.java

3. Mainアプリケーションを起動します。

$ java com.example.mxbeans.Main

何かの発生を待機中のMainに関する確認が表示されます。

4. 同じマシンの別の端末ウィンドウで、JConsoleを起動します。

$ jconsole

JConsoleツールが開き、接続可能な稼動中のJMXエージェントのリストが表示されます。

5. 「新規接続」ウィンドウのリストからcom.example.mxbeans.Mainを選択し、「接続」をクリックします。
プラットフォームの現在のアクティビティのサマリーが表示されます。

6. 「MBean」タブをクリックします。
このパネルに、現在MBeanサーバーに登録されているすべてのMBeanが表示されます。

7. 左フレームにあるMBeanツリーのcom.example.mxbeansノードを展開します。
Mainで作成され、登録されたMBean QueueSamplerの例が表示されます。QueueSamplerをクリックすると、関連するAttributesおよびOperationsノードがMBeanツリーに表示されます。

8. Attributesノードを選択します。
右ペインにQueueSample属性とそのjavax.management.openmbean.CompositeDataSupportの値が表示されます。

9. CompositeDataSupport値をダブルクリックします。
MXBeanフレームワークがQueueSampleインスタンスをCompositeDataに変換したため、QueueSampleの値であるdate、head、およびsizeが表示されます。QueueSamplerをMXBeanではなく標準MBeanとして定義した場合、QueueSampleクラスはそのクラス・パスには存在しないのでJConsoleからは見つかりません。QueueSamplerが標準MBeanの場合、QueueSample属性値を抽出するとClassNotFoundExceptionが返されます。このように、JConsoleのように汎用的なJMXクライアントでJMXエージェントに接続するときにMXBeanを使用すると便利です。

10. Operationsノードを選択します。
clearQueue操作を呼び出すボタンが表示されます。

11. 「clearQueue」ボタンをクリックします。
メソッドの呼出しに成功したことが通知されます。

12. Attributesノードをもう一度選択し、CompositeDataSupport値をダブルクリックします。
これでキューがリセットされます。

13. 「接続」をクリックし、次に「終了」をクリックして、JConsoleを終了します。

この例では、JConsoleがJMXクライアントとして使用されましたが、JMXクライアントの自作プログラムからMXBeanにアクセスする場合は次の2つの方法のどちらかで行います。

- 一般的には次のコードを使用します。

MBeanServer mbs = ...whatever...;
ObjectName name = new ObjectName("com.example.mxbeans:type=QueueSampler");
CompositeData queueSample = (CompositeData) mbs.getAttribute(name,
"QueueSample");
int size = (Integer) queueSample.get("size");

- プロキシ経由では次のコードを使用します。

MBeanServer mbs = ...whatever...;
ObjectName name = new ObjectName("com.example.mxbeans:type=QueueSampler");
QueueSamplerMXBean proxy = JMX.newMXBeanProxy(mbs, name,
QueueSamplerMXBean.class);
QueueSample queueSample = proxy.getQueueSample();
int size = queueSample.getSize();

このコードでは、newMXBeanProxyメソッドを使用してMXBeanプロキシを作成しています。newMBeanProxyという等価のメソッドがあるのは、ほかの型のMBeanで使用するプロキシを作成するためです。newMBeanProxyおよびnewMXBeanProxyメソッドの使用法はまったく同じです。

MBean記述子

記述子によって、MBeanに関する追加情報を管理クライアントに提供できます。たとえば、MBean属性に関する記述子で計測単位や最大値と最小値を示す場合もあります。Java SE 6の時点で、記述子はJMX APIに含まれており、どのMBeanでも使用可能です。

記述子は、任意のメタデータをMBeanに追加する場合に便利です。記述子はJMX APIに必ずありますが、Java SE 6まではModel MBeanと別に使用することはできません。

MBean*Infoクラス(MBeanInfo、MBeanAttributeInfoなど)のほとんどのコンストラクタの場合、それぞれに共通するパラメータと追加パラメータjavax.management.Descriptorを持つ並列コンストラクタが存在します。OpenMBean*InfoSupportの場合も同様です。MBean*InfoおよびOpenMBean*InfoSupportクラスには、getDescriptor()メソッドが含まれています。

Open MBeansは、OpenMBeanParameterInfoおよびOpenMBeanAttributeInfoのメソッドgetDefaultValue()、getLegalValues()、getMaxValue()、getMinValue()から、デフォルトに関する情報と有効な値を返します。今回、この情報が対応する記述子にも含まれるようになりました。また、他のMBean型も自身の記述子にこの情報を返すことができます。

jmx_examples.zipファイルをダウンロードして解凍すると、MBean記述子を説明したサンプル・プログラムがwork_dir/jmx_examples/Descriptors/com/example/mxbeansディレクトリに作成されます。MBean記述子のサンプルには、次のファイルが含まれています。

- Author。MBeanインタフェースの著者名を示す注釈。

- DisplayName。MBeanインタフェースのメソッドの表示名を示す注釈。

- Main、サンプルを設定して実行するプログラム。

- QueueSamplerMXBeanインタフェース。

- MXBeanインタフェースを実装するQueueSamplerクラス。

- QueueSample Javaの型で、MXBeanインタフェース内のgetQueueSample()メソッドによって返されます。

- Version。MBeanインタフェースの現在のバージョンを示す注釈。

この例に示すQueueSampler MXBeanは、MXBeanの導入に示したMXBeanの例と基本的に同じアクションを実行していますが、MBean記述子が追加されている点が異なります。この例は、DescriptorKeyメタ注釈を使用することで、標準MBean (またはMXBean)インタフェース内の注釈によって標準MBean (またはMXBean)の記述子に新しい記述子を追加する方法を示しています。

DescriptorKey注釈

新しい注釈、DescriptorKey、を使用することで、標準MBeanまたはMXBeanインタフェース内の注釈によって標準MBeanまたはMXBeanの記述子に情報を追加できます。これによって、ツールで既存の管理モデルから標準MBeanを生成し、そのモデルからの情報を別のファイルではなく生成されたMBeanインタフェースに含めることができます。コード例2-9 Author注釈は、Author注釈の定義を示しています。

コード例2-9 Author注釈

package com.example.mxbeans;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.management.DescriptorKey;

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
@DescriptorKey("author")
String value();
}

この注釈は、MBeanインタフェースの作成者の名前を提供します。新しいフィールドauthorは、@Author注釈によって定義された値を持つMBeanInfo記述子に追加されます。ファイルVersionおよびDisplayNameは、これらの名前の注釈を、前述のAuthorの場合とまったく同様に定義します。VersionおよびDisplayNameの@DescriptorKey値は、それぞれ“version”および“displayname”です。

Versionの場合、新しいフィールドversionは@Version注釈によって定義された値を持つMBeanInfo記述子に追加されます。

DisplayNameの場合、新しいフィールドdisplayNameは、注釈を付けられたメソッドが取得メソッド/設定メソッドと操作のどちらであるかに応じて、それぞれ@DisplayName注釈によって定義された値を持つMBeanAttributeInfo記述子またはMBeanOperationInfo記述子に追加されます。

MBean記述子の使用

次の例で使用されているQueueSamplerMXBeanインタフェースは、MBean記述子を実装してその情報の一部を公開する範囲にかぎり、MXBeanの例で使用されているインタフェースとはわずかに異なります。

コード例2-10 記述子を使用したQueueSamplerMXBean

package com.example.mxbeans;

@Author("Mr Bean")
@Version("1.0")
public interface QueueSamplerMXBean {
@DisplayName("GETTER: QueueSample")
public QueueSample getQueueSample();
@DisplayName("OPERATION: clearQueue")
public void clearQueue();
}

これで@Author注釈はMr. Bean、@Version注釈は1.0、@DisplayNameは属性QueueSampleと操作clearQueueのどちらかの名前に設定されます。

MBean記述子の例題の実行

例題を実行するには、次の手順を実行します。

1. MBean記述子にあるソース・コードをwork_dir/jmx_examples/Descriptorsにコピーします。

2. Javaクラスの例をコンパイルします。

$ javac com/example/mxbeans/*.java

3. Mainアプリケーションを起動します。

$ java com.example.mxbeans.Main

何かの発生を待機中のMainに関する確認が表示されます。

4. 同じマシンの別の端末ウィンドウで、JConsoleを起動します。

$ jconsole

JConsoleツールが開き、接続可能な稼動中のJMXエージェントのリストが表示されます。

5. 「新規接続」ウィンドウのリストからcom.example.mxbeans.Mainを選択し、「接続」をクリックします。
プラットフォームの現在のアクティビティのサマリーが表示されます。

6. 「MBean」タブをクリックします。
このパネルに、現在MBeanサーバーに登録されているすべてのMBeanが表示されます。

7. 左フレームにあるMBeanツリーのcom.example.mxbeansノードを展開します。
Mainで作成され、登録されたMBean QueueSamplerの例が表示されます。QueueSamplerをクリックすると、関連するAttributesおよびOperationsノードがMBeanツリーに表示されます。フィールドauthorおよびversionもMBeanInfo記述子表に表示されます。

8. QueueSampler MBeanノードの下にあるAttributesおよびOperationsノードを展開します。
AttributesとOperationsが個別に表示されます。

9. QueueSampleノードを選択します。
MBeanAttributeInfo記述子表にdisplayNameフィールドが表示されます。

10. clearQueueノードを選択します。
MBeanOperationInfo記述子表にdisplayNameフィールドが表示されます。

11. 「接続」をクリックし、次に「終了」をクリックして、JConsoleを終了します。

11 JMXコネクタ

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

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

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

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

JMXテクノロジは、Remote Method Invocation (RMI)を基にしたコネクタを定義します。RMIコネクタは、Java Remote Method Protocol (JRMP)トランスポートをサポートします。このコネクタを使用すると、MBeanサーバーのMBeanにリモート接続し、ローカルで操作を実行するのとまったく同じように、そのMBeanで操作を実行できます。

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

この例を実行する場合

- サーバー側:

- MBeanサーバーを作成

- ローカルMBeanサーバーにSimpleStandardとSimpleDynamicのMBeanを登録

- 両MBean上でローカル操作を実行

- RMIコネクタ・サーバーを作成

- クライアント側:

- RMIコネクタを作成

- リモートMBeanサーバーにSimpleStandardとSimpleDynamicのMBeanを登録

- 両MBeanでリモート操作を実行

基本MBeanの例で使用したクラスの分析

1. JMXコネクタからwork_dir/jmx_examples/Basicディレクトリにソース・コードをコピーします。このディレクトリ内に次のコピーが作成されます。

- Server.java

- SimpleStandardMBean.java

- SimpleStandard.java

- SimpleDynamic.java

- ClientListener.java

- Client.java

- README

2. 各*.javaファイルをIDEまたはテキスト・エディタで開きます。

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

MBeanの例題のServer.java

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

- コード例3-1 MBeanの例クラスServer.java (抜粋1)

- コード例3-2 MBeanの例クラスServer.java (抜粋2)

- コード例3-3 MBeanの例クラスServer.java (抜粋3)

- コード例3-4 MBeanの例クラスServer.java (抜粋4)

- コード例3-5 MBeanの例クラスServer.java (抜粋5)

コード例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 MBeanの例題クラスServer.java (抜粋4)とコード例3-5 MBeanの例題クラスServer.java (抜粋5)で示されます。

このコードには記述されていませんが、SimpleDynamic型の2番目のMBeanが、SimpleStandard MBeanとまったく同じ方法で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 MBeanの例題クラスServer.java (抜粋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 url、null環境マップ、およびMBeanサーバーmbsを使用して、コンストラクタJMXConnectorServerFactoryを呼び出して作成されます。コネクタ・サーバーcsは、JMXConnectorServerのstart()メソッドを呼び出し、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 MBeanの例題クラスServer.java (抜粋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 MBeanの例題クラスServer.java (抜粋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の例題クラスServer.java (抜粋5)は、簡単なMBeanを管理するためのメソッドを示しています。

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

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

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

MBeanの例題のSimpleStandardMBean.java

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

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

MBeanの例題のSimpleStandard.java

SimpleStandard.javaクラスを、コード例3-7 MBeanの例題クラスSimpleStandard.javaに示します。

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

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

- 状態を定義する

- 現在の状態を更新する

- 状態の更新回数をカウントする

- 状態の値と、変更回数を元の値であるゼロにリセットする

- リセットが呼び出された場合に常に通知を送信する

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

MBeanの例題のSimpleDynamic.java

SimpleDynamicクラスを、コード例3-8 MBeanの例題クラスSimpleDynamic.javaに示します。

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

MBeanの例題のClientListener.java

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

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

MBeanの例題のClient.java

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

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

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

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

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

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

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

例題のクラスを検証した後、例題を実行できます。例題を実行するには、次の手順を実行します。

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が作成されてその操作が実行された後、RMIコネクタ・サーバーが作成され、リモートのClientからMBeanでの操作が可能になります。

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

$ java -classpath . Client

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

12 検索サービス

検索サービスを使用すると、JMXテクノロジのクライアントは、検索サービスに登録されているコネクタ・サーバーを検索し、接続することができます。

Java Management Extensions (JMX)仕様では、次のセクションで説明する既存の検索テクノロジを使用した、検索サービスの3つのバインディングを定義しています。

- 初期設定では、3つのタイプのすべての検索サービスに適用される設定情報を提供します。

- Service Location Protocol (SLP)検索サービスでは、SLP検索の例を示します。

- Jini検索サービスでは、Jini検索の例を示します。

- Java Naming and Directory Interface (JNDI)/LDAP検索サービスでは、JNDI/LDAP検索の例を示します。

初期設定

RMIコネクタを使用した標準および動的MBeanへのアクセスで示したように、リモート・メソッド呼出し(RMI)コネクタを使用している場合、検索するコネクタ・サーバー・スタブの登録に外部ディレクトリを使用できます。RMIコネクタに関連した検索サービスの例の中で、次のケースを示します。

- 次の外部ディレクトリのいずれかを使用したRMIコネクタ

- RMIレジストリ。デフォルトのJava Remote Method Protocol (JRMP)トランスポートを実装するRMIコネクタ向け

- Lightweight Directory Access Protocol (LDAP)。JRMPトランスポート向け

- 外部ディレクトリを使用しないRMIコネクタ

RMIコネクタ・スタブを外部ディレクトリに登録する場合は、いくつか初期設定が必要です。RMIレジストリまたはLDAPサーバーを設定する必要があります。外部ディレクトリを使用しない場合、RMIコネクタ・スタブはJMXサービスURLにエンコードされます。

次のセクションでは、RMIコネクタを使用する検索サービスの例に使用できる外部ディレクトリについて説明します。これらの外部ディレクトリは、この章の以降のセクションで示す検索サービスの3つの例を実行する場合に参照されます。

外部RMIレジストリ

JRMPトランスポートを実装するコネクタで使用するために、外部RMIレジストリにRMIコネクタ・サーバー・スタブを登録するには、次の手順を実行します。

1. ローカル・ホストのポート9999でRMIレジストリを起動します。
JMXコネクタで説明されているように、RMIレジストリはJRMPトランスポートを実装するRMIコネクタ用のRMIコネクタ・スタブを格納するために使用されます。

$ rmiregistry 9999 &

2. コマンドを入力する場合、RMIレジストリのアドレスに環境変数を作成すると便利です。
例を実行するときに入力するコマンドを短くするために、RMIレジストリのサービスURLを環境変数jndirmiとして設定します。次の例では、サービスURLはJNDI形式で指定されています。JNDI形式の詳細は、javax.management.remote.rmiパッケージのAPIドキュメントを参照してください。ローカル・マシン以外のマシンで外部ディレクトリを実行する場合は、ローカル・ホストの代わりに、そのマシンのホスト名を指定する必要があります。

$ jndirmi="rmi://localhost:9999"

外部LDAPレジストリ

JRMPトランスポートを実装するコネクタで使用するために、外部LDAPレジストリにRMIコネクタ・サーバー・スタブを登録するには、次の手順を実行します。

1. LDAPサーバーを起動します。
使用するLDAPサーバーは選択できますが、LDAPディレクトリでJavaオブジェクトを表すためのスキーマがサーバーに認識されている必要があります。詳細は、関連するRequest For Comments (RFC)ドキュメントを参照してください。

http://www.ietf.org/rfc/rfc2713.txt

2. ドメイン・コンポーネントのサフィックスを作成します。
次の例では、次のドメイン・コンポーネントのサフィックスの作成が必要になります。

dc=Test

サーバーの構成方法と、このサフィックスの作成方法の詳細は、使用しているLDAPサーバーに付属のドキュメントを参照してください。

3. 便宜上、環境変数に次のLDAPパラメータを設定します。
これらの変数は、外部LDAPサーバーにRMIコネクタ・スタブを登録する検索サービスの例で、ServerクラスとClientクラスを起動するときに、入力するコマンドを短縮するために使用します。

- LDAPサーバーを実行するマシンの名前(ldap_host)

$ ldaphost=ldap_host

- LDAPサーバーが実行されているポート(ldap_port)

$ ldapport=ldap_port

- LDAPコマンド名属性。次の例では「Directory Manager」

$ principal=”cn=Directory Manager”

- LDAPサーバーで要求されるパスワードLDAPサーバーのパスワードを指定します。

$ credentials=your_ldap_password

- LDAPサーバーのアドレス。この例では、LDAPサーバーのサービスURLはJNDI形式で指定され、変数jndildapで識別されます。

$ jndildap="ldap://$ldaphost:$ldapport"

これで、各種の検索サービスの例を実行する準備ができました。

Service Location Protocol (SLP)検索サービス

JMXテクノロジの仕様では、SLP検索サービスにRMIコネクタを登録する方法が指定されています。

この例は、JMX Remote APIコネクタ・クライアントで、SLP検索サービスに登録されたコネクタ・サーバーを検索し、接続する方法を示します。この例では、次の操作を実行します。

- エージェント側:

- MBeanサーバーを作成

- SLP検索サービスのポインタを取得

- コネクタ・サーバーを作成

- SLP検索サービスにコネクタ・アドレスを登録

- クライアント側:

- SLP検索サービスのポインタを取得

- SLP検索サービスに登録されたすべてのコネクタ・サーバーを検索

- JMX Remote APIコネクタを作成

- MBeanサーバーのMBeanに関する情報を取得

この例は、ユーザーがSLPテクノロジに習熟していることを前提に記載されています。この例に示すコードは、RFC 2614 (http://www.ietf.org/rfc/rfc2614.txtを参照)で定義されているOracleのSLPの実装に準拠しています。OracleのSLPの実装は、ディレクトリ/usr/share/lib/slpのSolarisオペレーティング環境で使用できます。Solarisオペレーティング環境を実行していない場合は、「RFC 2614、Section 5」に準拠したバージョンのSLPを入手する必要があります。OpenSLP Java実装は、http://www.openslp.org/からダウンロードできます。

SLP検索例題クラスの分析

1. Service Location Protocol (SLP)検索サービスからwork_dir/jmx_examples/Lookup/slpにソース・コードをコピーします。このディレクトリ内のファイルは、次のとおりです。

- README

- Server.java

- Client.java

2. *.javaファイルをIDEまたはテキスト・エディタで開きます。

次のセクションでは、各クラスを分析し、例題で説明した操作をどのように実行するかについて説明します。

SLP検索の例題のServer.java

SLP検索サービスのServer.javaクラスは、その大きさにより、次のコード(抜粋)で示されます。

- 例4-1 SLP検索サービスの例題クラスServer.java (抜粋1)

- 例4-2 SLP検索サービスの例題クラスServer.java (抜粋2)

- 例4-3 SLP検索サービスの例題クラスServer.java (抜粋3)

- 例4-4 SLP検索サービスの例題クラスServer.java (抜粋4)

この例で使用されるSLPコードの詳細は、RFC 2614とSLPのAPIドキュメントを参照してください。

例4-1 SLP検索サービスの例題クラスServer.java (抜粋1)

public class Server {
public final static int JMX_DEFAULT_LEASE = 300;
public final static String JMX_SCOPE = "DEFAULT";

private final MBeanServer mbs;
public Server() {
mbs = MBeanServerFactory.createMBeanServer();
}

[...]

例4-1では、デフォルトのSLPリースJMX_DEFAULT_LEASEを、URLの登録期間に対応するデフォルト・リース300秒に設定し、MBeanサーバーmbsの初期作成を示しています。

例には示されていないコードでは、次にSLPアドバタイザslpAdvertiserとSLPサービスURL urlを定義します。slpAdvertiserは、SLP検索サービスにサービスURLを登録する場合に使用します。SCOPEとagentNameは、SLPに検索属性として登録されます。

例4-2 SLP検索サービスの例題クラスServer.java (抜粋2)

[...]

public static void register(JMXServiceURL jmxUrl, String name)
throws ServiceLocationException {
ServiceURL serviceURL =
new ServiceURL(jmxUrl.toString(),
JMX_DEFAULT_LEASE);
debug("ServiceType is: " + serviceURL.getServiceType());
Vector attributes = new Vector();
Vector attrValues = new Vector();
attrValues.add(JMX_SCOPE);
ServiceLocationAttribute attr1 =
new ServiceLocationAttribute("SCOPE", attrValues);
attributes.add(attr1);
attrValues.removeAllElements();
attrValues.add(name);
ServiceLocationAttribute attr2 =
new ServiceLocationAttribute("AgentName", attrValues);
attributes.add(attr2);
final Advertiser slpAdvertiser =
ServiceLocationManager.getAdvertiser(Locale.US);
slpAdvertiser.register(serviceURL, attributes);

}

[...]

例4-2に、JMXコネクタ・サーバーのURLのSLP検索サービスへの登録を示します。

JMXサービスURL、jmxUrlは、コネクタ・サーバーのアドレスであり、コネクタ・サーバーの起動時にJMXConnectorServerのgetAddress()メソッドを呼び出して取得します。

このとき、スコープやコネクタ・サーバー・アドレスが登録される際のエージェント名(name)などのSLP検索の属性は、SLPクラスServiceLocationAttributeにより指定されます。AgentName属性は必須ですが、ProtocolType、AgentHost、およびPropertyなどのほかのオプション属性もSLP検索サービスに登録できます。

最後に、JMXコネクタ・サーバー・アドレスはAdvertiserインタフェースのregister()メソッドの呼出しによりSLPサービスに登録され、パラメータとしてserviceURLとattributesが渡されます。

例4-3 SLP検索サービスの例題クラスServer.java (抜粋3)

[...]

public JMXConnectorServer rmi(String url) throws
IOException,
JMException,
NamingException,
ClassNotFoundException,
ServiceLocationException {
JMXServiceURL jurl = new JMXServiceURL(url);
final HashMap env = new HashMap();
// Environment map attributes
[...]

JMXConnectorServer rmis =
JMXConnectorServerFactory.newJMXConnectorServer(jurl, env, mbs);
final String agentName = System.getProperty("agent.name",
"DefaultAgent");
start(rmis, agentName);

return rmis;
}
[...]

例4-3に、RMIコネクタ・サーバーの作成を示します。JMXサービスURL jurlは、コマンド行でServerを起動するためのコマンドに含まれる文字列urlから構築されます。RMIコネクタ・サーバー、rmisは、環境マップとアドレスjurlで定義されるシステム・プロパティから作成されます。

次にコネクタ・サーバーが起動し、RMIコネクタ・サーバー・アドレスがagentNameの名前でSLP検索サービスに登録されます。

例4-4 SLP検索サービスの例題クラスServer.java (抜粋4)

[...]

public void start(JMXConnectorServer server, String agentName)
throws IOException, ServiceLocationException {
server.start();
final JMXServiceURL address = server.getAddress();
register(address,agentName);
}

[...]

例4-4に、コネクタ・サーバーserverの起動と、指定されたアドレスaddressを使用したserverのSLP検索サービスへの登録を示します。

SLP検索の例題のClient.java

SLP検索サービスのClient.javaクラスは、次の一連のコード(抜粋)で分析されます。

- 例4-5 SLP検索サービスの例題クラスClient.java (抜粋1)

- 例4-6 SLP検索サービスの例題クラスClient.java (抜粋2)

- 例4-7 SLP検索サービスの例題クラスClient.java (抜粋3)

例4-5 SLP検索サービスの例題クラスClient.java (抜粋1)

public class Client {

public final static String JMX_SCOPE = "DEFAULT";

public static Locator getLocator() throws ServiceLocationException {
final Locator slpLocator =
ServiceLocationManager.getLocator(Locale.US);
return slpLocator;
}

public static List lookup(Locator slpLocator, String name)
throws IOException, ServiceLocationException {

final ArrayList list = new ArrayList();
Vector scopes = new Vector();

scopes.add(JMX_SCOPE);
String query =
"(&(AgentName=" + ((name!=null)?name:"*") + "))";

ServiceLocationEnumeration result =
slpLocator.findServices(new ServiceType("service:jmx"),
scopes, query);

while(result.hasMoreElements()) {
final ServiceURL surl = (ServiceURL) result.next();

JMXServiceURL jmxUrl = new JMXServiceURL(surl.toString());
try {
JMXConnector client =
JMXConnectorFactory.newJMXConnector(jmxUrl,null);
if (client != null) list.add(client);
} catch (IOException x ) {
[...]
}
}
}
return list;
}

例4-5では、SLPクラスServiceLocationManagerのgetLocatorメソッドを呼び出して、SLPサービスLocatorを取得します。次にClientは、特定のエージェント名または特定のパターンに一致するエージェント名でSLPサービスに登録された、すべてのコネクタ・サーバーを取得します。Clientの起動時にエージェント名が指定されていない場合、すべてのエージェント名が考慮されます。

JMXテクノロジ・サービスURL、jmxUrlは、SLPで取得されたエージェントごとに生成されます。各エージェントのSLPサービスURL、surlはパラメータとしてJMXServiceURLインスタンスに渡されます。URL ,jmxUrl,は、JMXConnectorFactoryのnewJMXConnector()メソッドに渡され、SLPサービスに登録される各エージェントに新しいコネクタ・クライアントclientが作成されます。

取得されたコネクタ・クライアントは、配列リストlistに保存されます。

例4-6 SLP検索サービスの例題クラスClient.java (抜粋2)

public static void listMBeans(MBeanServerConnection server)
throws IOException {

final Set names = server.queryNames(null,null);
for (final Iterator i=names.iterator(); i.hasNext(); ) {
ObjectName name = (ObjectName)i.next();
System.out.println("Got MBean: "+name);
try {
MBeanInfo info =
server.getMBeanInfo((ObjectName)name);
MBeanAttributeInfo[] attrs = info.getAttributes();
if (attrs == null) continue;
for (int j=0; j<attrs.length; j++) {
try {
Object o =
server.getAttribute(name,attrs[j].getName());
System.out.println("\t\t" + attrs[j].getName() +
" = "+o);
} catch (Exception x) {
System.err.println("JmxClient failed to get " +
attrs[j].getName() + x);
x.printStackTrace(System.err);
}
}
}

例4-6では、SLPサービスに保存されたコネクタ・サーバー・アドレスを使用して作成されたすべてのコネクタ・クライアントに、MBeanServerConnectionの参照が取得されています。すべてのMBeanとその属性のリストが取得されます。

例4-7 SLP検索サービスの例題クラスClient.java (抜粋3)

public static void main(String[] args) {
try {
final String agentName = System.getProperty("agent.name");
final Locator slpLocator = getLocator();
List l = lookup(slpLocator,agentName);
int j = 1;
for (Iterator i=l.iterator();i.hasNext();j++) {
JMXConnector c1 = (JMXConnector) i.next();
if (c1 != null) {
try {
c1.connect(env);
} catch (IOException x) {
System.err.println ("Connection failed: " + x);
x.printStackTrace(System.err);
continue;
}

MBeanServerConnection conn =
c1.getMBeanServerConnection();

try {
listMBeans(conn);
} catch (IOException x) {
x.printStackTrace(System.err);
}
try {
c1.close();
} catch (IOException x) {
x.printStackTrace(System.err);
}
}
}
} catch (Exception x) {
x.printStackTrace(System.err);
}
}

例4-7では、agent.nameプロパティはSystemクラスのgetProperty()メソッドを呼び出して取得され、SLP検索サービスはLocatorのgetLocator()メソッドを呼び出して検索されます。

agentNameの名前を持つすべてのエージェントが検索され、検出されたエージェントへの接続が設定されます。エージェントが指定されていない場合、すべてのエージェントが検索されます。Serverで作成されたMBeanサーバーへの接続が設定され、接続が切断される前に、接続内のすべてのMBeanがリストされます。

SLP検索サービスの例題の実行

この例では、SLP検索サービスを使用して、RMIのデフォルトのトランスポートであるJRMPを使用するRMIコネクタ・サーバーを検索する方法を示します。初期設定で説明したように、RMIコネクタ・スタブの登録には別の外部ディレクトリが使用されています。

トランスポートと外部ディレクトリの組合せは次のとおりです。

- 次のものを使用した、JRMPトランスポート上のRMIコネクタ

- 外部ディレクトリなし

- RMIレジストリ

- LDAPレジストリ

初期設定で実行した操作以外に、SLPを使用する例題を実行する前にこの例に固有の追加操作を実行する必要があります。この作業後、SLPをJMXテクノロジでサポートされる2つのコネクタとともに使用してコネクタの検索を開始できます。

注意:

例題を実行する場合、作成されたエージェントの種類と、エージェントの作成に使用されたトランスポートを追跡するために、対応するセクションの文字列に等しい文字サフィックスがエージェント名に含まれています。たとえば、サーバーの起動のサブステップaからのエージェントです。外部ディレクトリを使用しないJRMP上のRMIコネクタは、example-server-aと呼ばれます。

例題を実行するには、次に説明する一連の手順を実行します。

- SLP検索サービスの例題の設定

- サーバーの起動

- クライアントの起動

SLP検索サービスの例題の設定

次の手順は、この例題で実行できる様々なトランスポートのすべてで要求されます。

1. クラスのコンパイルおよび実行が容易になるように、追加で環境変数を定義します。初期設定で設定された共通の環境変数の他に、SLPサービスのパスを追加する必要があります。
Solarisオペレーティング環境を使用している場合は、次の変数を追加します。

$ SLPLIB=/usr/share/lib/slp

別のプラットフォームを使用している場合は、使用しているプラットフォームに合わせてSLPLIBを設定します。

2. classp環境変数を定義し、エクスポートします。この例では、SLPのJavaアーカイブ(JAR)ファイルを含むクラス・パスが必要です:

$ classp=$SLPLIB/slp.jar

3. 次のコマンドを入力して、例題のClientおよびServerクラスをコンパイルします。

$ javac -d . -classpath $classp Server.java Client.java

4. SLPデーモンを起動します。
Solarisオペレーティング環境を使用している場合、次のコマンドを入力しますが、これにはスーパー・ユーザー・パスワードが必要です。

$ su root -c "java -cp $SLPLIB/slpd.jar com.sun.slp.slpd &"
Password:[type superuser password]

Solarisシステムを実行していない場合、使用しているSLPの実装に従ってSLPデーモンを起動します。

サーバーの起動

Serverの起動に使用するコマンドは、使用している外部ディレクトリによって異なります。Clientを起動する前に、Serverの次のインスタンスの1つ以上を起動します。Serverのインスタンスを、各種のトランスポートおよび外部レジストリを使用して、起動できます。

- 外部ディレクトリを使用しないJRMP上のRMIコネクタ: 次のコマンドを入力してServerを起動します。

$ java -classpath .:$classp -Ddebug=true \
-Dagent.name=example-server-a \
-Durl ="service:jmx:rmi://" \
slp.Server &

コマンドの説明は次のとおりです。

- debugの値はtrueに設定され、Serverの実行時の画面出力をより詳細なものにします。

- エージェントの名前はexample-server-aです。

- サービスURLにより、RMIのデフォルト・トランスポートJRMP上で動作するRMIコネクタの選択が指定されます。

Serverが起動すると、RMIコネクタの作成、およびそのURLのSLPサービスへの登録を確認するメッセージが表示されます。

- RMIレジストリを外部ディレクトリとして使用するJRMP上のRMIコネクタ: 次のコマンドを入力してServerを起動します。

$ java -classpath .:$classp -Ddebug=true \
-Dagent.name=example-server-b \
-Durl="service:jmx:rmi:///jndi/${jndirmi}/server" \
slp.Server &

コマンドの説明は次のとおりです。

- 作成されるエージェントの名前はexample-server-bです。

- サービスURLは、JRMP上のRMIとして選択されるコネクタを指定し、RMIコネクタ・スタブserverが保存される外部ディレクトリは、初期設定でjndirmiと特定したRMIレジストリです。

Serverが起動すると、RMIコネクタの作成、およびそのURLのSLPサービスへの登録を確認するメッセージが表示されます。

- LDAPを外部ディレクトリとして使用するJRMP上のRMIコネクタ: 次のコマンドを入力してServerを起動します。

$ java -classpath .:$classp -Ddebug=true \
-Dagent.name=example-server-c \
-Durl="service:jmx:rmi:///jndi/${jndildap}/cn=x,dc=Test" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
slp.Server &

コマンドの説明は次のとおりです。

- 作成されるエージェントの名前はexample-server-cです。

- サービスURLは、JRMP上のRMIとして選択されるコネクタを指定し、RMIコネクタ・スタブが保存される外部ディレクトリは、初期設定でjndildapと特定したLDAPサーバーです。

- スタブはLDAPサーバーのTestドメイン・コンポーネントに登録されます。

- LDAPサーバーにアクセスするため、共通名の属性principalとパスワードcredentialsが与えられます。

Serverが起動すると、RMIコネクタの作成、およびそのURLがエージェント名example-server-cでSLPサービスに登録されることの確認が表示されます。

クライアントの起動

選択したトランスポートおよび外部ディレクトリを使用してServerを起動した後、Clientを起動します。

$ java -classpath .:$classp -Ddebug=true \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
slp.Client

Serverで作成され検索サービスに登録されたエージェントの検出を確認する出力が表示されます。また、エージェントに設定された接続の接続名と、接続の確認が表示されます。

特定のエージェントを検索するには、次のコマンドを入力します。

$ java -classpath .:$classp -Ddebug=true \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
-Dagent.name="agentName" \
slp.Client

上に示したこのコマンドで、agentNameは検索するエージェントの名前です。*を使用してエージェント名を部分的に指定することもできます。たとえば、文字xで始まるすべてのエージェント名を検索する場合は、x*と指定します。

Jini検索サービス

この例は、JMXテクノロジのコネクタ・クライアントで、Jini検索サービスに登録されたコネクタ・サーバーを検索し、接続する方法を示します。この例では、次の操作を実行します。

- エージェント側:

- MBeanサーバーを作成

- コネクタ・サーバーを作成

- Jini検索サービスにコネクタ・アドレスを登録

- クライアント側:

- Jini検索サービスのポインタを取得

- Jini検索サービスに登録されたすべてのコネクタ・サーバーを検索

- JMX Remote APIコネクタを作成

- MBeanサーバーのMBeanに関する情報を取得

例題クラスの分析

1. Jini検索サービスからwork_dir/jmx_examples/Lookup/jiniディレクトリにソース・コードをコピーします。このディレクトリ内のファイルは、次のとおりです。

- README

- Server.java

- Client.java

- java.policy

- jini.properties.template

2. *.javaファイルをIDEまたはテキスト・エディタで開きます。

次のセクションでは、Jini検索サービスの例題で使用される各クラスを分析し、各クラスが上記で説明した操作をどのように実行するかについて説明します。

Jini検索サービスの例題のServer.java

Jini検索サービスのServer.javaクラスは、その大きさにより、次のコード(抜粋)で示されます。

- 例4-8 Jini検索サービスの例題クラスServer.java (抜粋1)

- 例4-9 Jini検索サービスの例題クラスServer.java (抜粋2)

- 例4-10 Jini検索サービスの例題クラスServer.java (抜粋3)

例4-8 Jini検索サービスの例題クラスServer.java (抜粋1)

public class Server {
private final MBeanServer mbs;
private static boolean debug = false;
public Server() {
mbs = MBeanServerFactory.createMBeanServer();
}

[...]

例4-8に、MBeanサーバーmbsの作成を示します。SLPの例題の場合と同様に、Serverをコマンド行で起動する場合、JMXサービスのURLとエージェント名がサーバーに渡されます。

例4-9 Jini検索サービスの例題クラスServer.java (抜粋2)

[...]

public JMXConnectorServer rmi(String url)
throws IOException, JMException, ClassNotFoundException {
JMXServiceURL jurl = new JMXServiceURL(url);
final HashMap env = new HashMap();
// Environment map attributes
[...]
JMXConnectorServer rmis =
JMXConnectorServerFactory.newJMXConnectorServer(jurl, env, mbs);

final String agentName = System.getProperty("agent.name",
"DefaultAgent");

start(rmis,env,agentName);

return rmis;
}

[...]

例4-9に、環境マップenvとアドレスjurlで定義されるシステム・プロパティを使用した、RMIコネクタ・サーバーrmisの作成を示します。

RMIコネクタ・サーバーrmisが起動します。RMIコネクタ・サーバーのアドレスは、agentNameの名前でJini検索サービスに登録されます。

例4-10 Jini検索サービスの例題クラスServer.java (抜粋3)

[...]

public void start(JMXConnectorServer server, Map env, String agentName)
throws IOException, ClassNotFoundException {
server.start();
final ServiceRegistrar registrar=getRegistrar();
final JMXConnector proxy = server.toJMXConnector(env);
register(registrar,proxy,agentName);
}

public static ServiceRegistrar getRegistrar()
throws IOException, ClassNotFoundException,
MalformedURLException {
final String jurl =
System.getProperty("jini.lookup.url","jini://localhost");
final LookupLocator lookup = new LookupLocator(jurl);
final ServiceRegistrar registrar = lookup.getRegistrar();
if (registrar instanceof Administrable)
debug("Registry is administrable.");
return registrar;
}

public static ServiceRegistration register(ServiceRegistrar registrar,
JMXConnector proxy, String name)
throws IOException {
Entry[] serviceAttrs = new Entry[] {
new net.jini.lookup.entry.Name(name)
};

System.out.println("Registering proxy: AgentName=" + name );
debug("" + proxy);
ServiceItem srvcItem = new ServiceItem(null, proxy, serviceAttrs);
ServiceRegistration srvcRegistration =
registrar.register(srvcItem, Lease.ANY);
debug("Registered ServiceID: " +
srvcRegistration.getServiceID().toString());
return srvcRegistration;
}

[...]

例4-10に、環境マップenvとサービスURL、jurlを使用した、コネクタ・サーバーserverの作成を示します。コネクタ・サーバーのインスタンス・サーバーは、Jini検索サービス・メソッドLookupLocator.getRegistrar()を呼び出してJini検索サービスのポインタを取得します。

コネクタ・サーバーは、Jini検索サービス・ロケータregistrarと、コネクタ・サーバーが登録される際のエージェント名を使用して、プロキシ形式でJini検索サービスに登録されます。プロキシは実際には、コネクタ・サーバーのクライアント・スタブになり、JMXConnectorServerのtoJMXConnector()メソッドの呼出しにより取得されます。

登録自体は、サービス項目の配列を使用し、Jini検索サービス・クラスServiceRegistrarのregister()メソッドを呼び出して実行されます。

Jini検索サービスの例題のClient.java

Jini検索サービスの例題クラスClient.javaをコード例4-11に示します。

例4-11 Jini検索サービスの例題クラスClient.java

public class Client {

private static boolean debug = false;
public static ServiceRegistrar getRegistrar()
throws IOException, ClassNotFoundException, MalformedURLException {
final String jurl =
System.getProperty("jini.lookup.url","jini://localhost");
final LookupLocator lookup = new LookupLocator(jurl);
final ServiceRegistrar registrar = lookup.getRegistrar();
if (registrar instanceof Administrable)
debug("Registry is administrable.");
return registrar;
}

public static List lookup(ServiceRegistrar registrar,
String name) throws IOException {
final ArrayList list = new ArrayList();
final Class[] classes = new Class[] {JMXConnector.class};
final Entry[] serviceAttrs = new Entry[] {
new net.jini.lookup.entry.Name(name)
};

ServiceTemplate template =
new ServiceTemplate(null,classes,serviceAttrs);
ServiceMatches matches =
registrar.lookup(template, Integer.MAX_VALUE);
for(int i = 0; i < matches.totalMatches; i++) {
debug("Found Service: " + matches.items[i].serviceID);
if (debug) {
if (matches.items[i].attributeSets != null) {
final Entry[] attrs = matches.items[i].attributeSets;
for (int j = 0; j < attrs.length ; j++) {
debug("Attribute["+j+"]=" + attrs[j]);
}
}
}

if(matches.items[i].service != null) {
JMXConnector c = (JMXConnector)(matches.items[i].service);
debug("Found a JMXConnector: " + c);
list.add(c);
}
}
return list;
}

[...]

例4-11に、コネクタ・クライアントがlookup.getRegistrar()の呼出しによりJini検索サービスのポインタを取得する方法を示します。クライアントは、次にエージェント名nameを使ってJini検索サービスにエントリとして登録されたコネクタのリストを取得します。SLPの例と異なり、起動時にユーザーがClientに渡したエージェント名は、既存のエージェント名と完全に一致するか、Nullでなければならず、いずれの場合も、Jini検索サービスはすべてのエージェントを検索します。

ここにコードは示されていませんが、コネクタのリストが取得されると、クライアントはServerによって起動したMBeanサーバーに接続し、このサーバーに登録されたすべてのMBeanを示したリストを取得します。

Jini検索サービスの例題のjava.policy

java.policyファイルは、この例のために構成されたJavaテクノロジのセキュリティ・ポリシー・ファイルです。

jini.properties.template

jini.properties.templateファイルは、テンプレート形式のJiniネットワーキング・テクノロジ・プロパティ・ファイルです。この例題用に構成する必要があります。このファイルを使用するには、@INSTALL_HOME_FOR_JINI@を変更し、ファイル名をjini.properties.に変更します。

Jini検索サービスの例題の実行

この例では、Jini検索サービスを使用して、RMIのデフォルトのトランスポートであるJRMPを使用するRMIコネクタ・サーバーを検索する方法を示します。

トランスポートと外部ディレクトリの組合せは次のとおりです。

- 次のものを使用した、JRMPトランスポート上のRMIコネクタ

- 外部ディレクトリなし

- RMIレジストリ

- LDAPレジストリ

Jini検索サービスを使用する例題を実行する前に、初期設定の項の操作と、この例に固有の操作を完了する必要があります。

注意:

例題を実行する場合、作成されたエージェントの種類と、エージェントの作成に使用されたトランスポートを追跡するために、対応するセクションの文字列に等しい文字サフィックスがエージェント名に含まれています。たとえば、サーバーの起動のサブステップaからのエージェントです。外部ディレクトリを使用しないJRMP上のRMIコネクタは、example-server-aと呼ばれます。

例題を実行するには、次に説明する一連の手順を実行します。

- Jini検索サービスの例題の設定

- サーバーの起動

- クライアントの起動

Jini検索サービスの例題の設定

次の手順は、この例題で実行できるすべてのトランスポートで要求されます。

1. 例題クラスのコンパイルおよび実行が容易になるように、追加の環境変数をいくつか定義できます。初期設定で設定した共通の環境変数の他に、Jini検索サービスのパスを追加できます。
Jiniネットワーキング・テクノロジをインストールしたディレクトリは、jini_dirとして参照されます。

$ JINI_HOME=jini_dir

$ JINILIB=$JINI_HOME/lib

2. classp環境変数を定義します。この例では、Jini検索サービスのコアと拡張機能に使用するJARファイルが必要になります。

$ classp=$JINILIB/jini-core.jar:$JINILIB/jini-ext.jar

3. jini.propertiesファイルを作成します。Solaris、Linux、またはMac OS Xプラットフォーム用のプロパティ・ファイルは、この例のクラスと同じディレクトリ内にあります。Solaris、Linux、またはMac OS Xプラットフォームを実行していない場合、使用しているプラットフォームのプロパティ・ファイルは次のディレクトリで入手できます。

$JINI_HOME/example/launcher/jini12_platform.properties

4. jini.propertiesファイルを更新して、システムに必要なすべてのパス、ホスト名およびポート番号を含める必要があります。Solaris、Linux、またはMac OS Xプラットフォームを実行していない場合でも、参照としてテンプレートを使用できます。

5. 次のように入力してJiniネットワーキング・テクノロジStartServiceを起動します。

$ java -cp $JINILIB/jini-examples.jar com.sun.jini.example.launcher.StartService &

StartServiceグラフィカル・ユーザー・インタフェースが開きます。

6. 「ファイル」、「プロパティ・ファイルを開く」をクリックし、次のディレクトリからプロパティ・ファイルを選択して、jini.propertiesファイルをStartServiceにロードします。

work_dir/jmx_examples/Lookup/jini.

7. Jini検索サービスを開始するには、「実行」タブをクリックし、次の項目のそれぞれについて「開始」ボタンを押します。

- RMID

- WebServer

- Reggie

- LookupBrowser

サービスの実行を確認するメッセージが表示されます。

8. 次のコマンドを入力して、ClientおよびServerクラスをコンパイルします。

$ javac -d . -classpath $classp Server.java Client.java

サーバーの起動

Serverの起動に使用するコマンドは、使用している外部ディレクトリによって異なります。Clientを起動する前に、各種のトランスポートおよび外部レジストリを使用して、Serverの次のインスタンスの1つ以上を起動できます。

- 外部ディレクトリを使用しないJRMP上のRMIコネクタ: 次のコマンドを入力してServerを起動します。

$ java -classpath .:$classp -Ddebug=true \
-Dagent.name=example-server-a \
-Durl="service:jmx:rmi://" \
-Djava.security.policy=java.policy \
jini.Server &

コマンドの説明は次のとおりです。

- debugの値はtrueに設定され、Serverの実行時の画面出力をより詳細なものにします。

- Jini検索サービスへのアクセスを可能にする、セキュリティ・ポリシーが指定されています。

- 作成されるエージェントの名前はexample-server-aです。

- サービスURLにより、RMIのデフォルト・トランスポートJRMP上で動作するRMIコネクタの選択が指定されます。

Serverが起動すると、RMIコネクタの作成、およびそのURLがJini検索サービスに登録されることの確認が表示されます。

- RMIレジストリを外部ディレクトリとして使用するJRMP上のRMIコネクタ: 次のコマンドを入力してServerを起動します。

$ java -classpath .:$classp -Ddebug=true \
-Dagent.name=example-server-b \
-Durl="service:jmx:rmi:///jndi/${jndirmi}/server" \
-Djava.security.policy=java.policy \
jini.Server &

コマンドの説明は次のとおりです。

- Jini検索サービスへのアクセスを可能にする、セキュリティ・ポリシーが指定されています。

- 作成されるエージェントの名前はexample-server-bです。

- サービスURLは、JRMP上のRMIとして選択されるコネクタを指定し、RMIコネクタ・スタブserverが保存される外部ディレクトリは、初期設定でjndirmiと特定したRMIレジストリです。

Serverが起動すると、RMIコネクタの作成、およびそのURLがJini検索サービスに登録されることの確認が表示されます。

- LDAPを外部ディレクトリとして使用するJRMP上のRMIコネクタ: 次のコマンドを入力してServerを起動します。

$ java -classpath .:$classp -Ddebug=true \
-Dagent.name=example-server-c \
-Durl="service:jmx:rmi:///jndi/${jndildap}/cn=x,dc=Test" \
-Djava.security.policy=java.policy \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jini.Server &

コマンドの説明は次のとおりです。

- Jini検索サービスへのアクセスを可能にする、セキュリティ・ポリシーが指定されています。

- 作成されるエージェントの名前はexample-server-cです。サービスURLは、JRMP上のRMIとして選択されるコネクタを指定し、RMIコネクタ・スタブが保存される外部ディレクトリは、初期設定でjndildapと特定したLDAPサーバーです。

- スタブはLDAPサーバーのTestドメイン・コンポーネントに登録されます。

- LDAPサーバーにアクセスするため、共通名の属性principalとパスワードcredentialsが与えられます。

Serverが起動すると、RMIコネクタの作成、およびそのURLがエージェント名example-server-cでJini検索サービスに登録されることの確認が表示されます。

Serverが起動すると、RMIコネクタの作成、およびそのURLがエージェント名example-server-fでJini検索サービスに登録されることの確認が表示されます。

クライアントの起動

選択したトランスポートおよび外部ディレクトリを使用してServerを起動した後、次のように入力してClientを起動します。

$ java -classpath .:$classp -Ddebug=true \
-Djava.security.policy=java.policy \
jini.Client

Serverで作成され検索サービスに登録されたエージェントの検出を確認する出力が表示されます。また、エージェントに設定された接続の接続名と、接続の確認が表示されます。

次のコマンドを入力すると、特定のエージェントを検索できます。

$ java -classpath .:$classp -Ddebug=true \
-Djava.security.policy=java.policy \
-Dagent.name=agentName \
jini.Client

前述のコマンドで、agentNameは検索するエージェントの名前です。また、*を使用してエージェント名を部分的に指定することもできます。たとえば、文字xで始まるすべてのエージェント名を検索する場合は、x*と指定します。

Java Naming and Directory Interface (JNDI)/LDAP検索サービス

JMXテクノロジでは、LDAPレジストリをバックエンドとして使用して、JNDI検索サービスにRMIコネクタを登録できます。この例では、次の操作を実行します。

- エージェント側:

- MBeanサーバーを作成

- コネクタ・サーバーを作成

- LDAPサーバーにコネクタ・アドレスを登録

- クライアント側:

- JNDI/LDAP検索サービスのポインタを取得

- JNDI/LDAP検索サービスに登録されたすべてのコネクタ・サーバーを検索

- JMX Remote APIコネクタを作成

- MBeanサーバーのMBeanに関する情報を取得

例題クラスの分析

1. Java Naming and Directory Interface (JNDI)/LDAP検索サービスからwork_dir/jmx_examples/Lookup/ldapディレクトリにソース・コードをコピーします。このディレクトリ内のファイルは、次のとおりです。

- README

- Server.java

- Client.java

- jmx-schema.txt

- 60jmx-schema.ldif

2. *.javaファイルをIDEまたはテキスト・エディタで開きます。

次のセクションでは、JNDI/LDAP検索サービスの例題で使用される各クラスを分析し、各クラスが上記で説明した操作をどのように実行するかについて説明します。

JNDI/LDAP検索サービスの例題のServer.java

JNDI/LDAP検索サービスのServer.javaクラスは、その大きさにより、次のコード(抜粋)で示されます。

- 例4-12 JNDI/LDAP検索サービスの例題のServer.java (抜粋1)

- 例4-13 JNDI/LDAP検索サービスの例題クラスServer.java (抜粋2)

- 例4-14 JNDI/LDAP検索サービスの例題クラスServer.java (抜粋3)

- 例4-15 JNDI/LDAP検索サービスの例題クラスServer.java (抜粋4)

例4-12 JNDI/LDAP検索サービスの例題のServer.java (抜粋1)

[...]

public class Server {
public final static int JMX_DEFAULT_LEASE = 60;
private static boolean debug = false;
private final MBeanServer mbs;
public Server() {
mbs = MBeanServerFactory.createMBeanServer();
}

public static DirContext getRootContext() throws NamingException {
final Hashtable env = new Hashtable();

final String factory =
System.getProperty(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
final String ldapServerUrl =
System.getProperty(Context.PROVIDER_URL);
final String ldapUser =
System.getProperty(Context.SECURITY_PRINCIPAL,
"cn=Directory Manager");
final String ldapPasswd =
System.getProperty(Context.SECURITY_CREDENTIALS);
debug(Context.PROVIDER_URL + "=" + ldapServerUrl);
debug(Context.SECURITY_PRINCIPAL + "=" + ldapUser);
if (debug) {
System.out.print(Context.SECURITY_CREDENTIALS + "=");
final int len = (ldapPasswd==null)?0:ldapPasswd.length();
for (int i=0;i<len;i++) System.out.print("*");
System.out.println();
}
env.put(Context.INITIAL_CONTEXT_FACTORY,factory);
env.put(Context.SECURITY_PRINCIPAL, ldapUser);
if (ldapServerUrl != null)
env.put(Context.PROVIDER_URL, ldapServerUrl);
if (ldapPasswd != null)
env.put(Context.SECURITY_CREDENTIALS, ldapPasswd);
InitialContext root = new InitialLdapContext(env,null);
return (DirContext)(root.lookup(""));
}
[...]

例4-12では、MBeanサーバーmbsの初期作成を示し、コネクタ・サーバーのアドレスが登録されるLDAPディレクトリ・ツリーのルート・コンテキストのポインタを取得します。プロバイダURL、LDAPユーザー名、セキュリティ資格などの関連するLDAPアクセス変数はすべてここに指定され、環境マップenvに渡されます。環境マップenvは、この後、InitialLdapContextの呼出しにパラメータとして渡され、これによって初期LDAPコンテキストが取得されます。

例4-13 JNDI/LDAP検索サービスの例題クラスServer.java (抜粋2)

[...]

public static void register(DirContext root,
JMXServiceURL jmxUrl,
String name)
throws NamingException, IOException {

final String mydn = System.getProperty("dn","cn="+name);

debug("dn: " + mydn );

Object o = null;
try {
o = root.lookup(mydn);
} catch (NameNotFoundException n) {
Attributes attrs = new BasicAttributes();
Attribute objclass = new BasicAttribute("objectClass");
objclass.add("top");
objclass.add("javaContainer");
objclass.add("jmxConnector");
attrs.put(objclass);
attrs.put("jmxAgentName", name);
o = root.createSubcontext(mydn,attrs);
}
if (o == null) throw new NameNotFoundException();
final Attributes attrs = root.getAttributes(mydn);
final Attribute oc = attrs.get("objectClass");
if (!oc.contains("jmxConnector")) {
final String msg = "The supplied node [" + mydn +
"] does not contain the jmxConnector objectclass";
throw new NamingException(msg);
}
final Attributes newattrs = new BasicAttributes();
newattrs.put("jmxAgentName",name);
newattrs.put("jmxServiceURL",jmxUrl.toString());
newattrs.put("jmxAgentHost",InetAddress.getLocalHost().getHostName());
newattrs.put("jmxProtocolType",jmxUrl.getProtocol());
newattrs.put("jmxExpirationDate",
getExpirationDate(JMX_DEFAULT_LEASE));
root.modifyAttributes(mydn,DirContext.REPLACE_ATTRIBUTE,newattrs);
}

[...]

例4-13に、JMXコネクタ・サーバーのサービスURLのLDAPディレクトリへの登録を示します。URLが登録されるDNは、コマンド行でdnシステム・プロパティ(-Ddn=mydn)を使用して渡すことができます。説明は、サーバーの起動に使用されるコマンドを参照してください。dnシステム・プロパティが指定されない場合、DN: cn=nameを使用できます。ここで、nameはagentNameです。ただし、これは必須ではありません。URLが登録される場所は問題ではありません。クライアント・コードで直接そのDNが使用されることはないためです。そのかわり、LDAP検索を実行して、補助的なjmxConnector ObjectClassを含むノードが検索されます。重要なのは、各URLが個々のLDAPノードに登録されるという点です。これらのノードの命名方式は、LDAP管理者、この場合は各ユーザーに委ねられます。この例では、ノードcn=nameの作成が可能なルート・コンテキストを作成することでLDAPサーバーを構成し、このrootコンテキストをContext.PROVIDER_URLプロパティを通じてLDAPの初期コンテキストに渡しているものと仮定しています。例4-12 JNDI/LDAP検索サービスの例題のServer.java (抜粋1)を参照してください。

例4-13のコードでは、サーバーURLを登録するノードが存在するかどうかをチェックしています。存在しない場合は作成を試してください。親ノードが存在しない場合は失敗します。jmxConnector ObjectClassは簡単な補助クラスであり、新しいコンテキストを作成する必要がある場合は、構造化クラスとしてjavaContainer ObjectClassを使用します。これは完全なオプションです。jmxConnector補助クラスを追加できる構造化クラスは何でもかまいません。コードは次にサーバーを登録するノードに、jmxConnector補助クラスがすでに使用されているかどうかをチェックします。使用されていない場合は、例外がスローされます。

この時点で、URLを登録するノードが存在し、適切なjmxConnector補助クラスが指定されていることが確実になります。必要なのは、LDAP検索のためのJMX Remote APIで定義された属性の値を置き換えることのみです。jmx-schema.txtを参照してください。

- jmxServiceUrl: サーバーの起動後にserver.getAddress()により取得されたString形式のサーバーURLが含まれる

- jmxAgentName: JMXエージェント名が含まれる

- jmxProtocolType: jmxUrl.getProtocolType()で返されるJMXプロトコル型が含まれる

- jmxAgentHost: エージェント・ホストの名前が含まれる

- jmxExpirationDate: URLの有効期日が含まれる

例4-14 JNDI/LDAP検索サービスの例題クラスServer.java (抜粋3)

[...]

public JMXConnectorServer rmi(String url)
throws IOException, JMException,
NamingException, ClassNotFoundException {

JMXServiceURL jurl = new JMXServiceURL(url);
final HashMap env = new HashMap();
// Prepare the environment Map
[...]

JMXConnectorServer rmis =
JMXConnectorServerFactory.newJMXConnectorServer(jurl, env, mbs)

final String agentName = System.getProperty("agent.name",
"DefaultAgent");
start(rmis,env,agentName);
return rmis;
}
[...]

例4-14では、JMXサービスURL jurlと適切なLDAPプロパティが環境マップenvに渡され、rmisという新しいRMIコネクタ・サーバーが作成されています。コネクタ・サーバーrmisが、JMXConnectorServer.start()の呼出しにより起動し、LDAPサーバーに登録されます。

例4-15 JNDI/LDAP検索サービスの例題クラスServer.java (抜粋4)

[...]

public void start(JMXConnectorServer server, Map env, String agentName)
throws IOException, NamingException {server.start()
final DirContext root=getRootContext();
final JMXServiceURL address = server.getAddress();register(root,address,agentName)
}
[...]

例4-15では、JMXコネクタ・サーバーserverを作成し、LDAPサーバーのルート・ディレクトリrootへのポインタを取得し、addressという名前のサーバーのURLを作成します。ルート・ディレクトリ、URL、およびエージェント名は、パラメータとしてregister()に渡され、LDAPサーバーに登録されます。

JNDI/LDAP検索サービスの例題のClient.java

JNDI/LDAP検索サービスの例題クラスClient.javaをコード例4-16に示します。

コード例4-16 JNDI/LDAP検索サービスの例題クラスClient.java

[...]

public class Client {

private static boolean debug = false;

public static void listAttributes(DirContext root, String dn)
throws NamingException {
final Attributes attrs = root.getAttributes(dn);
System.out.println("dn: " + dn);
System.out.println("attributes: " + attrs);
}
public static DirContext getRootContext() throws NamingException {
final Hashtable env = new Hashtable();
// Prepare environment map
[...]
InitialContext root = new InitialLdapContext(env,null);
return (DirContext)(root.lookup(""));
}
// Confirm URL has not expired
[...]

public static List lookup(DirContext root, String protocolType,
String name)
throws IOException, NamingException {
final ArrayList list = new ArrayList();
String queryProtocol =
(protocolType==null)?"":"(jmxProtocolType="+protocolType+")";
String query =
"(&" + "(objectClass=jmxConnector) " +
"(jmxServiceURL=*) " +
queryProtocol +
"(jmxAgentName=" + ((name!=null)?name:"*") + "))";

SearchControls ctrls = new SearchControls();
ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
final NamingEnumeration results = root.search("", query, ctrls);
while (results.hasMore()) {
final SearchResult r = (SearchResult) results.nextElement();
debug("Found node: " + r.getName());
final Attributes attrs = r.getAttributes();
final Attribute attr = attrs.get("jmxServiceURL");
if (attr == null) continue;
final Attribute exp = attrs.get("jmxExpirationDate");
if ((exp != null) && hasExpired((String)exp.get())) {
System.out.print(r.getName() + ": ");
System.out.println("URL expired since: " + exp.get());
continue;}
final String urlStr = (String)attr.get();
if (urlStr.length() == 0) continue;

debug("Found URL: "+ urlStr);

final JMXServiceURL url = new JMXServiceURL(urlStr);
final JMXConnector conn =
JMXConnectorFactory.newJMXConnector(url,null);
list.add(conn);
if (debug) listAttributes(root,r.getName());
}

return list;
}
}

コード例4-16では、ClientはまずLDAPディレクトリDirContextのポインタrootを返し、次にこのディレクトリでjmxConnector型のオブジェクト・クラスを検索します。jmxConnectorオブジェクト・クラスのサービスURLと有効期日属性、attrとexpが取得され、expのチェックによりURLが有効期限内であることが確認され、JMXConnectorFactoryの呼出しにより新しいコネクタconnが作成されます。コネクタconnがコネクタのリストに追加され、MBeanサーバー内のServerで作成されたMBeanへのアクセスに使用されます。

jmx-schema.txt

jmx-schema.txtファイルは、JMX Remote API用のLDAPスキーマ・ファイルです。

60jmx-schema.ldif

60jmx-schema.ldifファイルは、JMXテクノロジのLDAPスキーマ・ファイルjmx-schema.txtに対応するldifファイルです。

JNDI/LDAP検索サービスの例題の実行

この例では、JNDI/LDAP検索サービスを使用して、デフォルトのJRMPトランスポートおよびIIOPトランスポートを実装するRMIコネクタ・サーバーを検索する方法を示します。その他、初期設定で説明したように、RMIコネクタ・スタブの登録には別の外部ディレクトリが使用されています。

ここに示すトランスポートと外部ディレクトリの組合せは次のとおりです。

- 次のものを使用した、JRMPトランスポート上のRMIコネクタ

- 外部ディレクトリなし

- RMIレジストリ

- LDAPレジストリ

JNDI/LDAP検索サービスを使用する例題を実行する前に、初期設定の項の操作と、この例に固有の操作を完了する必要があります。JNDI/LDAPネットワーク・テクノロジを、JMXテクノロジでサポートされる2つのコネクタとともに使用してコネクタの検索を開始できます

注意:

例題を実行する場合、作成されたエージェントの種類と、エージェントの作成に使用されたトランスポートを追跡するために、対応するセクションの文字列に等しい文字サフィックスがエージェント名に含まれています。たとえば、「サーバーの起動」のサブステップaからのエージェントです。外部ディレクトリを使用しないJRMP上のRMIコネクタは、example-server-aと呼ばれます。

例題を実行するには、次に説明する一連の手順を実行します。

- JNDI/LDAP検索サービスの例題の設定

- サーバーの起動

- クライアントの起動

JNDI/LDAP検索サービスの例題の設定

次の手順は、この例題で実行できる各種のコネクタ/トランスポートのすべての組合せで要求されます。

注意:

使用しているLDAPサーバーのタイプに応じて次の手順を完了します。

1. 初期設定で起動したLDAPサーバーを停止します。

2. JMXテクノロジのスキーマを、使用しているLDAPサーバーのschemaディレクトリにコピーします。

3. LDAPサーバーを再起動します

4. ServerがそのサービスURLを登録するルートを定義します。初期設定で作成したドメイン・コンポーネント・サフィックスdc=TestへのパスをServerに指定する必要があります。

$ provider="ldap://$ldaphost:$ldapport/dc=Test"

5. 次のコマンドを入力して、例題のClientおよびServerクラスをコンパイルします。

$ javac -d . -classpath $classp Server.java Client.java

サーバーの起動

Serverの起動に使用するコマンドは、使用している外部ディレクトリによって異なります。Clientを起動する前に、各種のトランスポートおよび外部レジストリを使用して、Serverの次のインスタンスの1つまたは複数を起動できます。

ここに示すトランスポートと外部ディレクトリの組合せは次のとおりです。

- 外部ディレクトリを使用しないJRMP上のRMIコネクタ: 次のコマンドを入力してServerを起動します。

$ java -classpath . -Ddebug=true \
-Dagent.name=example-server-a \
-Durl="service:jmx:rmi://" \
-Djava.naming.provider.url="$provider" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jndi.Server &

コマンドの説明は次のとおりです。

- debug,はtrueに設定され、Serverの実行時の画面出力をより詳細なものにします。

- 作成されるエージェントの名前はexample-server-aです。

- エージェントが登録されるドメイン・コンポーネントのサフィックスを示すURL、providerが与えられます。

- LDAPサーバーにアクセスするため、共通名の属性principalとパスワードcredentialsが与えられます。

- サービスURLにより、RMIのデフォルトのJRMPトランスポート上で動作するRMIコネクタの選択が指定されます

Serverが起動すると、RMIコネクタの作成、およびそのURLのJNDI/LDAP検索サービスへの登録を確認するメッセージが表示されます。

- RMIレジストリを外部ディレクトリとして使用するJRMP上のRMIコネクタ: 次のコマンドを入力してServerを起動します。

$ java -classpath . -Ddebug=true \
-Dagent.name=example-server-b \
-Durl="service:jmx:rmi:///jndi/${jndirmi}/server" \
-Djava.naming.provider.url="$provider" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jndi.Server &

コマンドの説明は次のとおりです。

- 作成されるエージェントの名前はexample-server-bです。

- エージェントが登録されるドメイン・コンポーネントのサフィックスを示すURL、providerが与えられます。

- LDAPサーバーにアクセスするため、共通名の属性principalとパスワードcredentialsが与えられます。

- サービスURLは、JRMP上のRMIとして選択されるコネクタを指定し、RMIコネクタ・スタブserverが保存される外部ディレクトリは、初期設定でjndirmiと特定したRMIレジストリです。

Serverが起動すると、RMIコネクタの作成、およびそのURLのJNDI/LDAP検索サービスへの登録を確認するメッセージが表示されます。

- LDAPを外部ディレクトリとして使用するJRMP上のRMIコネクタ: 次のコマンドを入力してServerを起動します。

$ java -classpath . -Ddebug=true \
-Dagent.name=example-server-c \
-Durl="service:jmx:rmi:///jndi/${jndildap}/cn=x,dc=Test" \
-Djava.naming.provider.url="$provider" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jndi.Server &

コマンドの説明は次のとおりです。

- 作成されるエージェントの名前はexample-server-cです。

- エージェントが登録されるドメイン・コンポーネントのサフィックスを示すURL、providerが与えられます。

- LDAPサーバーにアクセスするため、共通名の属性principalとパスワードcredentialsが与えられます。

- サービスURLは、RMI over JRMPとして選択されるコネクタを指定し、RMIコネクタ・スタブserverが保存される外部ディレクトリは、初期設定でjndildap と特定したRMIレジストリです。

Serverが起動すると、RMIコネクタの作成、およびそのURLがエージェント名example-server-cでJNDI/LDAP検索サービスに登録されることの確認が表示されます。

クライアントの起動

選択したトランスポートおよび外部ディレクトリを使用してServerを起動した後、次のコマンドを入力してClientを起動します。

$ java -classpath . -Ddebug=true \
-Djava.naming.provider.url="$provider" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jndi.Client

Serverで作成され検索サービスに登録されたエージェントの検出を確認する出力が表示されます。また、エージェントに設定された接続の接続名と、接続の確認が表示されます。

特定のエージェントを検索するには、次のコマンドを入力します。

$ java -classpath . -Ddebug=true \
-Djava.naming.provider.url="$provider" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
-Dagent.name=agentName \
jndi.Client

前述のコマンドで、agentNameは検索するエージェントの名前です。また、*;を使用してエージェント名を部分的に指定することもできます。たとえば、文字xで始まるすべてのエージェント名を検索する場合は、 x*と指定します。

13 セキュリティ

この章では、JMXテクノロジのセキュリティ機能の設定方法の例を、次のセクション内で説明します。

- 簡単なセキュリティでは、パスワード認証とファイル・アクセス制御に基づいた簡単なセキュリティを実装するコネクタの例を示します。

- 主体委譲では、特定の認証された接続で操作を実行する場合に、複数の異なるIDのかわりに主体委譲モデルを使用するコネクタの例を示します。

- 詳細なセキュリティでは、個々の操作を実行する権限が制御される、より高度なセキュリティ・メカニズムを実装するコネクタの例を示します。

注意:

- アプリケーションでは、ユーザーがパスワードをコマンド行に入力するのではなく、パスワードの入力をユーザーに求めるようにする必要があります。

- 実稼動システムではセキュアな認証メカニズムを使用してください。特に、クライアント・ホストを認証するSSLクライアント証明書とユーザー管理用のパスワード認証の両方を使用します。Java Platform, Standard Edition Management Developer's GuideのSSLの使用およびLDAP認証の使用を参照してください。

簡単なセキュリティ

JMXテクノロジを使用して実装できるもっとも簡単なセキュリティは、暗号化、ユーザー名とユーザー・パスワードの認証、およびファイル・アクセス制御に基づくものです。

簡単なセキュリティの例題クラスを使用したRMIコネクタの分析

1. 簡単なセキュリティから次のwork_dir/jmx_examples/Security/simpleのサブディレクトリおよびファイルにソース・コードをコピーします。

- /server/Server.java

- /config/access.properties

- /config/keystore

- /config/password.properties

- /config/truststore

- /mbeans/SimpleStandardMBean.java

- /mbeans/SimpleStandard.java

- /client/Client.java

- /client/ClientListener.java

2. *.javaおよび*.propertiesファイルをIDEまたはテキスト・エディタで開きます。

次のセクションでは、これらのファイルを分析し、前述したセキュリティ操作をどのように実行するかについて説明します。

簡単なセキュリティの例題のServer.java

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

コード例5-1 RMIコネクタの例題(簡単なセキュリティ)クラスServer.java

public class Server {

public static void main(String[] args) {
try {
MBeanServer mbs = MBeanServerFactory.createMBeanServer();

HashMap env = new HashMap();

SslRMIClientSocketFactory csf =
new SslRMIClientSocketFactory();
SslRMIServerSocketFactory ssf =
new SslRMIServerSocketFactory();
env.put(RMIConnectorServer.
RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,csf);
env.put(RMIConnectorServer.
RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,ssf);

env.put("jmx.remote.x.password.file",
"config" + File.separator + "password.properties");
env.put("jmx.remote.x.access.file",
"config" + File.separator + "access.properties");

JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url,
env,
mbs);
cs.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}

コード例5-1に示すServerクラスは、MBeanサーバーmbsを作成し、環境マップenvにセキュリティ保護されたRMIクライアント・ソケット・ファクトリcsf、セキュリティ保護されたRMIサーバー・ソケット・ファクトリssf、およびプロパティ・ファイルpassword.propertiesとaccess.propertiesを渡します。

プロパティ・ファイルpassword.propertiesには、ユーザー名とパスワードが含まれ、JMXリモートAPIインタフェースJMXAuthenticatorを使用してアクセスします。プロパティjmx.remote.x.password.fileを使用することは、パスワードベースのJMXAuthenticatorを作成し、これをjmx.remote.authenticatorプロパティを通じて環境マップに渡すのと同じ意味を持ちます。

プロパティ・ファイルaccess.propertiesには、ユーザー名と一定レベルのアクセス権、readwriteとreadonlyのいずれかが含まれます。これはアクティブなユーザーが、MBeanサーバー操作にどのレベルでアクセスできるかを表します。このファイルベースのアクセス制御は、アクセス・コントローラMBeanサーバー内に実際のMBeanサーバーをラップする、JMXテクノロジのインタフェースMBeanServerForwarderを使用して実装されます。アクセス・コントローラMBeanサーバーは、適切なチェックを実行したあとに、実際のMBeanサーバーに要求を転送します。

ServerはRMIコネクタ用にJMXサービスURL、urlを作成します。このRMIコネクタはデフォルトのJRMPトランスポート上で動作し、ローカル・ホストのポート9999のRMIレジストリにRMIコネクタ・スタブを登録します。

MBeanサーバーmbs、環境マップenv、およびサービスURL urlはすべてJMXConnectorServerに渡され、セキュアなJMXコネクタ・サーバーcsが新規に作成されます。

簡単なセキュリティの例題のSimpleStandardMBean.java

SimpleStandardMBeanクラスは、MBeanの例題のSimpleStandardMBean.javaで使用されたのと同じ簡単なMBeanインタフェースを定義します。

簡単なセキュリティの例題のSimpleStandard.java

SimpleStandardクラスは、MBeanの例題のSimpleStandard.javaで使用されたのと同じ簡単なMBeanを定義します。

簡単なセキュリティの例題のClientListener.java

ClientListenerクラスは、MBeanの例題のClientListener.javaで使用されたのと同じ簡単な通知リスナーを定義します。

簡単なセキュリティの例題のClient.java

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

コード例5-2 RMIコネクタの例題(簡単なセキュリティ)クラスClient.java

public class Client {

public static void main(String[] args) {
try {
HashMap env = new HashMap();

String[] credentials = new String[] { "username" , "password" };
env.put("jmx.remote.credentials", credentials);
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnector jmxc = JMXConnectorFactory.connect(url, env);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
String domains[] = mbsc.getDomains();
for (int i = 0; i < domains.length; i++) {
System.out.println("Domain[" + i + "] = " + domains[i]);
}

ObjectName mbeanName =
new ObjectName("MBeans:type=SimpleStandard");
mbsc.createMBean("SimpleStandard", mbeanName, null, null);
// Perform MBean operations
[...]

mbsc.removeNotificationListener(mbeanName, listener);
mbsc.unregisterMBean(mbeanName);
jmxc.close();
}  catch (Exception e) {
e.printStackTrace();
}
}
}

コード例5-2に示すClientクラスは、環境マップenvにServerが求める資格セット、つまりusernameやpasswordを渡します。これらの資格は、コネクタ・スタブのサービスURLと環境マップがJMXConnectorFactory.connect()に渡されるときに、JMXConnectorのインスタンスjmxcに付与されます。Clientはjmxcを通じて、Server側で起動されたMBeanに接続し、MBeanの操作を実行します。

接続が確立すると、環境マップenvで付与された資格はサーバーに送信されます。サーバーは次に、JMXAuthenticatorインタフェースのauthenticate()メソッドを呼び出し、クライアント資格をパラメータとして渡します。authenticate()メソッドは、クライアントを認証し、アクセス制御の確認に使用されるプリンシパルのセットを含む被認証者を返します。

簡単なセキュリティを使用したRMIコネクタの例題の実行

簡単なセキュリティを使用したRMIコネクタの例題を実行するには、次の手順を実行します。

1. RMIコネクタの例題を実行します:

$ javac
mbeans/SimpleStandard.java \
mbeans/SimpleStandardMBean.java \
server/Server.java \
client/Client.java \
client/ClientListener.java

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

$ export CLASSPATH=server ; rmiregistry 9999 &

3. Serverを起動します。

$ java -classpath server:mbeans \
-Djavax.net.ssl.keyStore=config/keystore \
-Djavax.net.ssl.keyStorePassword=password \
Server &

MBeanサーバーとRMIコネクタの作成の確認が表示されます。

4. Clientを起動します。

$java -classpath client:server:mbeans \
-Djavax.net.ssl.trustStore=config/truststore \
-Djavax.net.ssl.trustStorePassword=trustword \
Client

コネクタ・クライアントと各種のMBean操作の作成、および作成後の接続の終了の確認が表示されます。

この例からわかるように、すべての処理が、JMXコネクタで説明した基本的なRMIコネクタの例とまったく同じ方法で進められているように見えます。ただし、password.propertiesを開きパスワードを変更する場合、Clientを起動するとjava.lang.SecurityExceptionが表示され、接続に失敗します。

主体委譲

実装において接続のクライアント側が、簡単なセキュリティで示したセキュリティ・メカニズムを使用して、複数のユーザーまたはアプリケーションにかわって異なる操作を実行する場合、各ユーザーが操作を実行するたびにセキュアな接続を確立する必要があります。コネクタ・クライアントが多くのユーザーと対話することが予測される場合、主体委譲を実装してシステムの負荷を減らすことができます。主体委譲は、ユーザーに対する単一のセキュアな接続を確立します。この接続は、関連する操作を何人ものユーザーにかわって実行するために使用できます。接続自体は認証されたユーザーによって設定されます。別のユーザーに代わって動作することを許可するSubjectDelegationPermissionが認証ユーザーに付与されている場合、そのユーザーにかわって、接続を使った操作を実行できます。

主体委譲の例題クラスを使用したセキュアなRMIコネクタの分析

1. 主体委譲を使用したセキュリティから次のwork_dir/jmx_examples/Security/subject_delegationのサブディレクトリおよびファイルにソース・コードをコピーします。

- /server/Server.java:

- /config/access.properties

- /config/java.policy

- /config/password.properties

- /mbeans/SimpleStandardMBean.java

- /mbeans/SimpleStandard.java

- /client/Client.java

- /client/ClientListener.java

2. すべての*.javaおよび*.propertiesファイルをIDEまたはテキスト・エディタで開きます。

次の各項で、これらのファイルの分析を説明します。

主体委譲の例題のServer.java

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

コード例5-3 セキュアなRMIコネクタ(主体委譲)例題クラスServer.java

public class Server {

public static void main(String[] args) {
try {
MBeanServer mbs = MBeanServerFactory.createMBeanServer();
HashMap env = new HashMap();
env.put("jmx.remote.x.password.file",
"config" + File.separator + "password.properties");
env.put("jmx.remote.x.access.file",
"config" + File.separator + "access.properties");

JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
cs.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}

コード例5-3は、MBeanサーバーmbsの作成から始まります。環境マップenvには、password.propertiesというパスワード・ファイルとaccess.propertiesというアクセス・ファイルが格納されます。

- パスワード・ファイルには、ユーザー名とパスワードの組み合わせが収められ、接続を試みるユーザーの認証に使用される。

- アクセス・ファイルには、ユーザー名とアクセス・レベルの組み合わせが含まれ、MBeanサーバーのMBeanへのアクセスの認証に使用される。アクセス・レベルは、読書き可能か読込み専用のいずれか。

次にServerはコネクタ・サーバーcsを作成し、前述のRMIコネクタの例題とまったく同じ方法でコネクタ・サーバーを起動します。

主体委譲の例題のjava.policy

java.policyファイルはusernameにSubjectDelegationPermissionを付与し、このユーザーがClientで作成されたJMXPrincipalのインスタンスである、ユーザーdelegateの代わりに操作を実行することを許可します。java.policyファイルが要求されるのは、Serverクラスの起動時です。

主体委譲の例題のSimpleStandardMBean.java

SimpleStandardMBeanクラスは、前出の例で使用されたのと同じ簡単なMBeanインタフェースを定義します。

主体委譲の例題のSimpleStandard.java

SimpleStandardクラスは、前出の例で使用されたのと同じ簡単なMBeanを定義します。

主体委譲の例題のClientListener.java

ClientListenerクラスは、前出の例題で使用されたのと同じ簡単な通知リスナーを定義します。

主体委譲の例題のClient.java

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

コード例5-4 セキュアなRMIコネクタ(主体委譲)例題クラスClient.java

public class Client {

public static void main(String[] args) {
try {
HashMap env = new HashMap();
String[] credentials = new String[] { "username" , "password" };
env.put("jmx.remote.credentials", credentials);
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnector jmxc = JMXConnectorFactory.connect(url, env);
Subject delegationSubject =
new Subject(true,
Collections.singleton(new JMXPrincipal("delegate")),
Collections.EMPTY_SET,
Collections.EMPTY_SET);

MBeanServerConnection mbsc =
jmxc.getMBeanServerConnection(delegationSubject);
String domains[] = mbsc.getDomains();
ObjectName mbeanName =
new ObjectName("MBeans:type=SimpleStandard");
mbsc.createMBean("SimpleStandard", mbeanName, null, null);
// Perform MBean operations
//

[...]
mbsc.removeNotificationListener(mbeanName, listener);
mbsc.unregisterMBean(mbeanName);
jmxc.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

コード例5-4は、ユーザー名usernameとパスワードpasswordが格納された環境マップenvの作成から始まります。これらの文字列は、Serverがコネクタ・サーバーにアクセスするユーザーを認証するために保持するpassword.propertiesファイルに保存されたユーザー名とパスワードに一致します。

JMXテクノロジのコネクタ・クライアントjmxcは、前述のRMIコネクタの例題と同じ方法で作成され、ユーザー名とパスワードは環境マップenvに渡されます。

次に、Clientは、JMXPrincipalのインスタンスであるdelegateという名前のPrincipalを使用して、SubjectのインスタンスdelegationSubjectを作成します。

MBeanサーバー接続mbscは、JMXConnectorのgetMBeanServerConnection()メソッドを呼び出し、パラメータとしてdelegationSubjectを渡して作成されます。したがって、このMBeanサーバー接続を使用すると、delegationSubjectに保存されたプリンシパル、この例ではdelegateという名前のJMXPrincipalに代わって、リモートMBeanサーバー上で操作を実行できます。

この例題ではさらに、これまでの例とまったく同じ方法で、MBeanサーバーでSimpleStandard MBeanが作成および登録され、このMBean上で操作が実行されます。

主体委譲を使用したセキュアなRMIコネクタの例題の実行

主体委譲を使用したセキュアなRMIコネクタの例題を実行するには、次の手順を実行します。

1. セキュアなRMIコネクタの例題を実行します:

$ javac  mbeans/SimpleStandard.java \
mbeans/SimpleStandardMBean.java \
server/Server.java \
client/Client.java \
client/ClientListener.java

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

$ export CLASSPATH=server ; rmiregistry 9999 &

3. Serverを起動します。

$ java -classpath server:mbeans \
-Djava.security.policy=config/java.policy Server &

MBeanサーバーの作成、環境マップの初期化、RMIコネクタの作成、およびコネクタのMBeanサーバーへの登録の確認が表示されます。

4. Clientを起動します。

$java -classpath client:server:mbeans Client

コネクタ・クライアントの作成、主体委譲の作成、MBeanサーバーへの接続、およびさまざまなMBean操作、その後の接続の終了の確認が表示されます。

詳細なセキュリティ

Java Authentication and Authorization Service (JAAS)とJava platform Standard Edition (Java SE)セキュリティ・アーキテクチャによってユーザー・アクセスを管理することで、より詳細なレベルのセキュリティをコネクタに実装できます。JAASとJava SEセキュリティの基本は、セキュリティ・マネージャとポリシー・ファイルを使用して、ユーザーごとに異なるアクセス・レベルを指定することです。どのユーザーにどの操作の実行を許可するかを指定できます。

このセクションの2つの例題は、簡単なセキュリティに示す例題と非常に似ていますが、異なる点として、簡単なファイルベースのアクセス制御が、ポリシー・ベースのアクセス制御に置き換えられています。

詳細なセキュリティの例題クラスを使用したセキュアなRMIコネクタの分析

1. 詳細なセキュリティからwork_dir/jmx_examples/Security/fine_grainedのサブディレクトリおよびファイルにソース・コードをコピーします。

- /server/Server.java

- /config/java.policy

- /config/keystore

- /config/password.properties

- /config/truststore

- /mbeans/SimpleStandard.java

- /mbeans/SimpleStandardMBean.java

- /client/ClientListener.java

- /client/Client.java

2. *.javaおよび*.propertiesファイルのすべてをIDEまたはテキスト・エディタで開きます。

次の各項で、これらのファイルの分析を説明します。

詳細なセキュリティの例題のServer.java

この例題のServer.javaクラスは、主体委譲の例題のServer.javaで使用されるクラスに非常に似ています。ただし、詳細なセキュリティの例題では、環境マップにマップされるaccess.propertiesファイルがありません。それ以外は、両クラスは同一です。

詳細なセキュリティの例題のjava.policy

java.policyファイルは、次の権限を付与します。

- serverコード・ベースのすべての権限。これがあることで、コネクタ・サーバーはコネクタを作成し、リモート・ユーザーの呼出しで要求される操作を実行できる

- mbeansコード・ベースに対するMBeanTrustPermission。これによって、信頼されたMBeanをMBeanサーバーに登録できる

- JMXPrincipalで表されるユーザー、username.に対する、各種のMBean操作およびMBeanサーバー操作を実行する権限

詳細なセキュリティの例題のSimpleStandardMBean.java

SimpleStandardMBeanクラスは、前出の例で使用されたのと同じ簡単なMBeanインタフェースを定義します。

詳細なセキュリティの例題のSimpleStandard.java

SimpleStandardクラスは、前出の例で使用されたのと同じ簡単なMBeanを定義します。

詳細なセキュリティの例題のClientListener.java

ClientListenerクラスは、前出の例題で使用されたのと同じ簡単な通知リスナーを定義します。

詳細なセキュリティの例題のClient.java

Client.javaクラスは、主体委譲の例題のClient.javaで使用されるクラスとまったく同じです。

詳細なセキュリティを使用したRMIコネクタの例題の実行

詳細なセキュリティを使用したRMIコネクタの例題を実行するには、次の手順を実行します。

1. RMIコネクタの例題を実行します:

$ javac
mbeans/SimpleStandard.java \
mbeans/SimpleStandardMBean.java \
server/Server.java \
client/Client.java \
client/ClientListener.java

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

$ export CLASSPATH=server ; rmiregistry 9999 &

3. Serverを起動します。

$ java -classpath server:mbeans \
-Djavax.net.ssl.keyStore=config/keystore \
-Djavax.net.ssl.keyStorePassword=password \
-Djava.security.manager \
-Djava.security.policy=config/java.policy \
Server &

環境マップの初期化、MBeanサーバーとRMIコネクタの作成の確認が表示されます。

4. Clientを起動します。

$ java -classpath client:server:mbeans \
-Djavax.net.ssl.trustStore=config/truststore \
-Djavax.net.ssl.trustStorePassword=trustword \
Client

コネクタ・クライアントの作成、RMIサーバーへの接続、各種のMBean操作、および接続の終了の確認が表示されます。

パートIII Java Management Extensionsの例

このセクションのファイルは、JMXテクノロジの主要な機能のいくつかを示すコード例です。これらの例を使用して、より複雑なMBeansおよび完全な機能を備えたJMXエージェントを、管理ソリューションに合わせて開発することができます。

それぞれの例は、Javaソース・ファイルとREADMEファイルから構成されています。READMEファイルは、例で扱われるトピックと、クラスのコンパイルと実行の手順を説明します。例の実行方法の詳細は、Java Management Extensions (JMX)テクノロジのチュートリアルを参照してください。

JMXの基本要素: 管理対象Bean (MBean)などのJMX APIの基本的な概念について説明します。

JMX MBeanの通知: MBeanの通知を実装します。

MXBeans: MXBeanの使用例を示します。

MBean記述子: MBean記述子の使用例を示します。

JMXコネクタ: MBeanに接続し、MBean上でリモートから操作を実行する方法に関する実装サンプルを示します。

検索サービス: JMX APIでは、既存の検索テクノロジを使用した、検索サービスの3つのバインディングを定義しています。

- Service Location Protocol (SLP)検索サービス

- Jini検索サービス

- Java Naming and Directory Interface (JNDI)/LDAP検索サービス

セキュリティ: JMX APIは、接続を保護するために既存のセキュリティ・プロトコルを実装します。

- 簡単なセキュリティ

- 主体委譲を使用したセキュリティ

- 詳細なセキュリティ

14 JMXの基本要素

この例では、管理対象Bean (MBean)などのJMX APIの基本的な概念について説明します。

- README file

- Main

- Hello

- HelloMBean

examples/Essential/README

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#   - Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#
#   - Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
#   - Neither the name of Oracle or the names of its
#     contributors may be used to endorse or promote products derived
#     from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#

# ==============================================================================
#
#  JMX Tutorial Introductory Example : Instrumenting Your Own Applications.
#
#  The aim of this introductory example is to show the basic features of
#  the JMX technology first by instrumenting a simple resource and second
#  by performing operations on it using the jconsole tool. This example
#  shows the implementation of a standard MBean, how to register it in the
#  platform's MBean Server and how to perform remote operations on it by
#  connecting to the RMI connector server using the jconsole tool. Besides
#  monitoring the application, jconsole will also allow you to observe the
#  built-in JVM instrumentation as the JVM's MBeans are also registered in
#  the platform's MBean Server. This examples also shows how the existing
#  platform's MBean Server can be shared between the JVM and the application
#  itself to register the application MBeans, thus avoiding the creation of
#  multiple MBean Server instances on the same JVM.
#
# ==============================================================================
#
# In order to compile and run the example, make a copy of this README file, and
# then simply cut and paste all the commands as needed into a terminal window.
#
# This README makes the assumption that you are running under Java SE 6 on Unix,
# you are familiar with the JMX technology, and with the bourne shell or korn
# shell syntax.
#
# All the commands below are defined using Unix korn shell syntax.
#
# If you are not running Unix and korn shell you are expected to be able to
# adapt these commands to your favorite OS and shell environment.
#

# Compile Java classes
#
# The Java classes used in this example are contained in the com.example.mbeans
# Java package.
#
# * Main.java: gets the Platform MBean Server, and creates
#              and registers the Hello World MBean on it.
#
# * Hello.java: implements the Hello World standard MBean.
#
# * HelloMBean.java: the management interface exposed by
#                    the Hello World standard MBean.
#

javac com/example/mbeans/*.java

# Start the Main application
#

java com.example.mbeans.Main

# Start jconsole on a different shell window on the same machine
#
# JConsole is located in $(J2SE_HOME)/bin/jconsole
#

jconsole

# ==============================================================================

examples/Essential/com/example/mbeans/Main.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/* Main.java - main class for Hello World example.  Create the
HelloWorld MBean, register it, then wait forever (or until the
program is interrupted).  */

package com.example.mbeans;

import java.lang.management.*;
import javax.management.*;

public class Main {
/* For simplicity, we declare "throws Exception".  Real programs
will usually want finer-grained exception handling.  */
public static void main(String[] args) throws Exception {
// Get the Platform MBean Server
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

// Construct the ObjectName for the MBean we will register
ObjectName name = new ObjectName("com.example.mbeans:type=Hello");

// Create the Hello World MBean
Hello mbean = new Hello();

// Register the Hello World MBean
mbs.registerMBean(mbean, name);

// Wait forever
System.out.println("Waiting forever...");
Thread.sleep(Long.MAX_VALUE);
}
}

examples/Essential/com/example/mbeans/Hello.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/* Hello.java - MBean implementation for the Hello World MBean.
This class must implement all the Java methods declared in the
HelloMBean interface, with the appropriate behavior for each one.  */

package com.example.mbeans;

public class Hello implements HelloMBean {
public void sayHello() {
System.out.println("hello, world");
}

public int add(int x, int y) {
return x + y;
}

/* Getter for the Name attribute.  The pattern shown here is
frequent: the getter returns a private field representing the
attribute value.  In our case, the attribute value never
changes, but for other attributes it might change as the
application runs.  Consider an attribute representing
statistics such as uptime or memory usage, for example.  Being
read-only just means that it can't be changed through the
management interface.  */
public String getName() {
return this.name;
}

/* Getter for the CacheSize attribute.  The pattern shown here is
frequent: the getter returns a private field representing the
attribute value, and the setter changes that field.  */
public int getCacheSize() {
return this.cacheSize;
}

/* Setter for the CacheSize attribute.  To avoid problems with
stale values in multithreaded situations, it is a good idea
for setters to be synchronized.  */
public synchronized void setCacheSize(int size) {
this.cacheSize = size;

/* In a real application, changing the attribute would
typically have effects beyond just modifying the cacheSize
field.  For example, resizing the cache might mean
discarding entries or allocating new ones.  The logic for
these effects would be here.  */
System.out.println("Cache size now " + this.cacheSize);
}

private final String name = "Reginald";
private int cacheSize = DEFAULT_CACHE_SIZE;
private static final int DEFAULT_CACHE_SIZE = 200;
}

examples/Essential/com/example/mbeans/HelloMBean.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/* HelloMBean.java - MBean interface describing the management
operations and attributes for the Hello World MBean.  In this case
there are two operations, "sayHello" and "add", and two attributes,
"Name" and "CacheSize". */

package com.example.mbeans;

public interface HelloMBean {
// operations

public void sayHello();
public int add(int x, int y);

// attributes

// a read-only attribute called Name of type String
public String getName();

// a read-write attribute called CacheSize of type int
public int getCacheSize();
public void setCacheSize(int size);
}

15 JMX MBeanの通知

この例では、次を含む、MBeanの通知を実装します。

- README file

- Main

- Hello

- HelloMBean

examples/Notification/README

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#   - Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#
#   - Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
#   - Neither the name of Oracle or the names of its
#     contributors may be used to endorse or promote products derived
#     from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#

# ==============================================================================
#
#  JMX Tutorial Introductory Example : Instrumenting Your Own Applications.
#                                      Using Notifications.
#
#  This example is the same as the previous essential example with the
#  only difference that the Hello World MBean has been modified to send
#  notifications.
#
#  The Hello World MBean implements the NotificationBroadcaster interface
#  by extending the NotificationBroadcasterSupport class and emits
#  AttributeChangeNotifications every time the CacheSize attribute
#  is changed.
#
# ==============================================================================
#
# In order to compile and run the example, make a copy of this README file, and
# then simply cut and paste all the commands as needed into a terminal window.
#
# This README makes the assumption that you are running under Java SE 6 on Unix,
# you are familiar with the JMX technology, and with the bourne shell or korn
# shell syntax.
#
# All the commands below are defined using Unix korn shell syntax.
#
# If you are not running Unix and korn shell you are expected to be able to
# adapt these commands to your favorite OS and shell environment.
#

# Compile Java classes
#
# The Java classes used in this example are contained in the com.example.mbeans
# Java package.
#
# * Main.java: gets the Platform MBean Server, and creates
#              and registers the Hello World MBean on it.
#
# * Hello.java: implements the Hello World standard MBean.
#               This MBean emits notifications every time
#               the CacheSize attribute is changed.
#
# * HelloMBean.java: the management interface exposed by
#                    the Hello World standard MBean.
#

javac com/example/mbeans/*.java

# Start the Main application
#

java com.example.mbeans.Main

# Start jconsole on a different shell window on the same machine
#
# JConsole is located in $(J2SE_HOME)/bin/jconsole
#

jconsole

# ==============================================================================

examples/Notification/com/example/mbeans/Main.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/* Main.java - main class for Hello World example.  Create the
HelloWorld MBean, register it, then wait forever (or until the
program is interrupted).  */

package com.example.mbeans;

import java.lang.management.*;
import javax.management.*;

public class Main {
/* For simplicity, we declare "throws Exception".  Real programs
will usually want finer-grained exception handling.  */
public static void main(String[] args) throws Exception {
// Get the Platform MBean Server
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

// Construct the ObjectName for the MBean we will register
ObjectName name = new ObjectName("com.example.mbeans:type=Hello");

// Create the Hello World MBean
Hello mbean = new Hello();

// Register the Hello World MBean
mbs.registerMBean(mbean, name);

// Wait forever
System.out.println("Waiting forever...");
Thread.sleep(Long.MAX_VALUE);
}
}

examples/Notification/com/example/mbeans/Hello.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/* Hello.java - MBean implementation for the Hello World MBean.
This class must implement all the Java methods declared in the
HelloMBean interface, with the appropriate behavior for each one.  */

package com.example.mbeans;

import javax.management.*;

public class Hello
extends NotificationBroadcasterSupport implements HelloMBean {

public void sayHello() {
System.out.println("hello, world");
}

public int add(int x, int y) {
return x + y;
}

/* Getter for the Name attribute.  The pattern shown here is
frequent: the getter returns a private field representing the
attribute value.  In our case, the attribute value never
changes, but for other attributes it might change as the
application runs.  Consider an attribute representing
statistics such as uptime or memory usage, for example.  Being
read-only just means that it can't be changed through the
management interface.  */
public String getName() {
return this.name;
}

/* Getter for the CacheSize attribute.  The pattern shown here is
frequent: the getter returns a private field representing the
attribute value, and the setter changes that field.  */
public int getCacheSize() {
return this.cacheSize;
}

/* Setter for the CacheSize attribute.  To avoid problems with
stale values in multithreaded situations, it is a good idea
for setters to be synchronized.  */
public synchronized void setCacheSize(int size) {
int oldSize = this.cacheSize;
this.cacheSize = size;

/* In a real application, changing the attribute would
typically have effects beyond just modifying the cacheSize
field.  For example, resizing the cache might mean
discarding entries or allocating new ones.  The logic for
these effects would be here.  */
System.out.println("Cache size now " + this.cacheSize);

/* Construct a notification that describes the change.  The
"source" of a notification is the ObjectName of the MBean
that emitted it.  But an MBean can put a reference to
itself ("this") in the source, and the MBean server will
replace this with the ObjectName before sending the
notification on to its clients.

For good measure, we maintain a sequence number for each
notification emitted by this MBean.

The oldValue and newValue parameters to the constructor are
of type Object, so we are relying on Tiger's autoboxing
here.  */
Notification n =
new AttributeChangeNotification(this,
sequenceNumber++,
System.currentTimeMillis(),
"CacheSize changed",
"CacheSize",
"int",
oldSize,
this.cacheSize);

/* Now send the notification using the sendNotification method
inherited from the parent class
NotificationBroadcasterSupport.  */
sendNotification(n);
}

@Override
public MBeanNotificationInfo[] getNotificationInfo() {
String[] types = new String[] {
AttributeChangeNotification.ATTRIBUTE_CHANGE
};
String name = AttributeChangeNotification.class.getName();
String description = "An attribute of this MBean has changed";
MBeanNotificationInfo info =
new MBeanNotificationInfo(types, name, description);
return new MBeanNotificationInfo[] {info};
}

private final String name = "Reginald";
private int cacheSize = DEFAULT_CACHE_SIZE;
private static final int DEFAULT_CACHE_SIZE = 200;

private long sequenceNumber = 1;
}

examples/Notification/com/example/mbeans/HelloMBean.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/* HelloMBean.java - MBean interface describing the management
operations and attributes for the Hello World MBean.  In this case
there are two operations, "sayHello" and "add", and two attributes,
"Name" and "CacheSize". */

package com.example.mbeans;

public interface HelloMBean {
// operations

public void sayHello();
public int add(int x, int y);

// attributes

// a read-only attribute called Name of type String
public String getName();

// a read-write attribute called CacheSize of type int
public int getCacheSize();
public void setCacheSize(int size);
}

16 MXBean

この例では、次を含む、MXBeanの使用例を示します。

- README file

- Main

- QueueSample

- QueueSampler

- QueueSamplerMXBean

examples/MXBean/README

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#   - Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#
#   - Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
#   - Neither the name of Oracle or the names of its
#     contributors may be used to endorse or promote products derived
#     from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#

# ==============================================================================
#
#  JMX Tutorial Introductory Example : Instrumenting Your Own Applications.
#                                      Using MXBeans.
#
#  The aim of this introductory example is to show the basic features of
#  the JMX technology first by instrumenting a simple resource using the new
#  type of MBean, i.e. MXBeans, and second by performing operations on it using
#  the jconsole tool. This example shows the implementation of an MXBean, how to
#  register it in the Platform MBean Server and how to perform remote operations
#  on it by connecting to the RMI connector server using the jconsole tool. The
#  goal of this example is to show a simple MXBean that manages a resource of
#  type Queue<String>. The MXBean declares a getter getQueueSample that takes
#  a snapshot of the queue when invoked and returns a Java class QueueSample
#  that bundles the following values together: the time the snapshot was taken,
#  the queue size and the head of the queue at that given time. The MXBean also
#  declares an operation clearQueue that clears all the elements in the queue
#  being managed. The example also shows how to register this MXBean in the
#  Platform MBean Server alongside the MBeans you can already see in jconsole.
#  This examples also shows how the existing Platform MBean Server can be
#  shared between the JVM and the application itself to register the application
#  MBeans, thus avoiding the creation of multiple MBean Server instances on the
#  same JVM.
#
# ==============================================================================
#
# In order to compile and run the example, make a copy of this README file, and
# then simply cut and paste all the commands as needed into a terminal window.
#
# This README makes the assumption that you are running under Java SE 6 on Unix,
# you are familiar with the JMX technology, and with the bourne shell or korn
# shell syntax.
#
# All the commands below are defined using Unix korn shell syntax.
#
# If you are not running Unix and korn shell you are expected to be able to
# adapt these commands to your favorite OS and shell environment.
#

# Compile Java classes
#
# The Java classes used in this example are contained in the com.example.mxbeans
# Java package.
#
# * Main.java: gets the Platform MBean Server, and creates
#              and registers the QueueSampler MXBean on it.
#
# * QueueSampler.java: implements the QueueSampler MXBean.
#
# * QueueSamplerMXBean.java: the management interface exposed
#                            by the QueueSampler MXBean.
#
# * QueueSample.java: the Java type returned by the getQueueSample()
#                     method in the QueueSampler MXBean interface.
#

javac com/example/mxbeans/*.java

# Start the Main application
#

java com.example.mxbeans.Main

# Start jconsole on a different shell window on the same machine
#
# JConsole is located in $(J2SE_HOME)/bin/jconsole
#

jconsole

# ==============================================================================

examples/MXBean/com/example/mxbeans/Main.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* Main.java - main class for QueueSampler example. Create the Queue Sampler
* MXBean, register it, then wait forever (or until the program is interrupted).
*/

package com.example.mxbeans;

import java.lang.management.ManagementFactory;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import javax.management.MBeanServer;
import javax.management.ObjectName;

public class Main {
/* For simplicity, we declare "throws Exception".  Real programs
will usually want finer-grained exception handling.  */
public static void main(String[] args) throws Exception {
// Get the Platform MBean Server
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

// Construct the ObjectName for the MBean we will register
ObjectName name =
new ObjectName("com.example.mxbeans:type=QueueSampler");

// Create the Queue Sampler MXBean
Queue<String> queue = new ArrayBlockingQueue<String>(10);
queue.add("Request-1");
queue.add("Request-2");
queue.add("Request-3");
QueueSampler mxbean = new QueueSampler(queue);

// Register the Queue Sampler MXBean
mbs.registerMBean(mxbean, name);

// Wait forever
System.out.println("Waiting...");
Thread.sleep(Long.MAX_VALUE);
}
}

examples/MXBean/com/example/mxbeans/QueueSamplerMXBean.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* QueueSamplerMXBean.java - MXBean interface describing the management
* operations and attributes for the QueueSampler MXBean. In this case
* there is a read-only attribute "QueueSample" and an operation "clearQueue".
*/

package com.example.mxbeans;

public interface QueueSamplerMXBean {
public QueueSample getQueueSample();
public void clearQueue();
}

examples/MXBean/com/example/mxbeans/QueueSampler.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* QueueSampler.java - MXBean implementation for the QueueSampler MXBean.
* This class must implement all the Java methods declared in the
* QueueSamplerMXBean interface, with the appropriate behavior for each one.
*/

package com.example.mxbeans;

import java.util.Date;
import java.util.Queue;

public class QueueSampler implements QueueSamplerMXBean {

private Queue<String> queue;

public QueueSampler(Queue<String> queue) {
this.queue = queue;
}

public QueueSample getQueueSample() {
synchronized (queue) {
return new QueueSample(new Date(), queue.size(), queue.peek());
}
}

public void clearQueue() {
synchronized (queue) {
queue.clear();
}
}
}

examples/MXBean/com/example/mxbeans/QueueSample.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* QueueSample.java - Java type representing a snapshot of a given queue.
* It bundles together the instant time the snapshot was taken, the queue
* size and the queue head.
*/

package com.example.mxbeans;

import java.beans.ConstructorProperties;
import java.util.Date;

public class QueueSample {

private final Date date;
private final int size;
private final String head;

@ConstructorProperties({"date", "size", "head"})
public QueueSample(Date date, int size, String head) {
this.date = date;
this.size = size;
this.head = head;
}

public Date getDate() {
return date;
}

public int getSize() {
return size;
}

public String getHead() {
return head;
}
}

17 MBean記述子

この例では、次を含む、MBean記述子の使用例を示します。

- README file

- Author

- DisplayName

- Main

- QueueSample

- QueueSampler

- QueueSamplerMXBean

- Version

examples/Descriptors/README

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
#

# ==============================================================================
#
#  JMX Tutorial Introductory Example : Instrumenting Your Own Applications.
#                                      Using Descriptors and the DescriptorKey
#                                      meta-annotation.
#
#  The aim of this example is to show how the new DescriptorKey meta-annotation
#  can be used in order to add new descriptor items to the Descriptors for a
#  Standard MBean (or MXBean) via annotations in the Standard MBean (or MXBean)
#  interface. The MXBeans example will be the starting point for this example.
#
# ==============================================================================
#
# In order to compile and run the example, make a copy of this README file, and
# then simply cut and paste all the commands as needed into a terminal window.
#
# This README makes the assumption that you are running under Java SE 6 on Unix,
# you are familiar with the JMX technology, and with the bourne shell or korn
# shell syntax.
#
# All the commands below are defined using Unix korn shell syntax.
#
# If you are not running Unix and korn shell you are expected to be able to
# adapt these commands to your favorite OS and shell environment.
#

# Compile Java classes
#
# The Java classes used in this example are contained in the com.example.mxbeans
# Java package.
#
# * Main.java: gets the Platform MBean Server, and creates
#              and registers the QueueSampler MXBean on it.
#
# * QueueSampler.java: implements the QueueSampler MXBean.
#
# * QueueSamplerMXBean.java: the management interface exposed
#                            by the QueueSampler MXBean.
#
# * QueueSample.java: the Java type returned by the getQueueSample()
#                     method in the QueueSampler MXBean interface.
#
# * DisplayName.java: This annotation is used in QueueSamplerMXBean to supply
#                     a display name for a method in the MBean interface.
#
# * Author.java: This annotation is used in QueueSamplerMXBean to supply
#                the name of the creator of the MBean interface.
#
# * Version.java: This annotation is used in QueueSamplerMXBean to supply
#                 the current version of the MBean interface.
#

javac com/example/mxbeans/*.java

# Start the Main application
#

java com.example.mxbeans.Main

# Start jconsole on a different shell window on the same machine
#
# JConsole is located in $(J2SE_HOME)/bin/jconsole
#

jconsole

# ==============================================================================

examples/Descriptors/com/example/mxbeans/Author.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/

/**
* Author.java - This annotation allows to supply
* the name of the creator of the MBean interface.
*/

package com.example.mxbeans;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.management.DescriptorKey;

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
@DescriptorKey("author")
String value();
}

examples/Descriptors/com/example/mxbeans/DisplayName.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/

/**
* DisplayName.java - This annotation allows to supply
* a display name for a method in the MBean interface.
*/

package com.example.mxbeans;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.management.DescriptorKey;

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DisplayName {
@DescriptorKey("displayName")
String value();
}

examples/Descriptors/com/example/mxbeans/Main.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/

/**
* Main.java - main class for QueueSampler example. Create the Queue Sampler
* MXBean, register it, then wait forever (or until the program is interrupted).
*/

package com.example.mxbeans;

import java.lang.management.ManagementFactory;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import javax.management.MBeanServer;
import javax.management.ObjectName;

public class Main {
/* For simplicity, we declare "throws Exception".  Real programs
will usually want finer-grained exception handling.  */
public static void main(String[] args) throws Exception {
// Get the Platform MBean Server
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

// Construct the ObjectName for the MBean we will register
ObjectName name =
new ObjectName("com.example.mxbeans:type=QueueSampler");

// Create the Queue Sampler MXBean
Queue<String> queue = new ArrayBlockingQueue<String>(10);
queue.add("Request-1");
queue.add("Request-2");
queue.add("Request-3");
QueueSampler mxbean = new QueueSampler(queue);

// Register the Queue Sampler MXBean
mbs.registerMBean(mxbean, name);

// Wait forever
System.out.println("Waiting...");
Thread.sleep(Long.MAX_VALUE);
}
}

examples/Descriptors/com/example/mxbeans/QueueSample.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/

/**
* QueueSample.java - Java type representing a snapshot of a given queue.
* It bundles together the instant time the snapshot was taken, the queue
* size and the queue head.
*/

package com.example.mxbeans;

import java.beans.ConstructorProperties;
import java.util.Date;

public class QueueSample {

private final Date date;
private final int size;
private final String head;

@ConstructorProperties({"date", "size", "head"})
public QueueSample(Date date, int size, String head) {
this.date = date;
this.size = size;
this.head = head;
}

public Date getDate() {
return date;
}

public int getSize() {
return size;
}

public String getHead() {
return head;
}
}

examples/Descriptors/com/example/mxbeans/QueueSampler.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/

/**
* QueueSampler.java - MXBean implementation for the QueueSampler MXBean.
* This class must implement all the Java methods declared in the
* QueueSamplerMXBean interface, with the appropriate behavior for each one.
*/

package com.example.mxbeans;

import java.util.Date;
import java.util.Queue;

public class QueueSampler implements QueueSamplerMXBean {

private Queue<String> queue;

public QueueSampler(Queue<String> queue) {
this.queue = queue;
}

public QueueSample getQueueSample() {
synchronized (queue) {
return new QueueSample(new Date(), queue.size(), queue.peek());
}
}

public void clearQueue() {
synchronized (queue) {
queue.clear();
}
}
}

examples/Descriptors/com/example/mxbeans/QueueSamplerMXBean.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/

/**
* QueueSamplerMXBean.java - MXBean interface describing the management
* operations and attributes for the QueueSampler MXBean. In this case
* there is a read-only attribute "QueueSample" and an operation "clearQueue".
*/

package com.example.mxbeans;

@Author("Mr Bean")
@Version("1.0")
public interface QueueSamplerMXBean {
@DisplayName("GETTER: QueueSample")
public QueueSample getQueueSample();
@DisplayName("OPERATION: clearQueue")
public void clearQueue();
}

examples/Descriptors/com/example/mxbeans/Version.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/

/**
* Version.java - This annotation allows to supply
* the current version of the MBean interface.
*/

package com.example.mxbeans;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.management.DescriptorKey;

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Version {
@DescriptorKey("version")
String value();
}

18 JMXコネクタ

この例では、MBeanに接続し、MBean上でリモートから操作を実行する方法に関する実装サンプルを示します。内容は次のとおりです。

- README file

- Server

- SimpleStandardMBean

- SimpleStandard

- SimpleDynamic

- ClientListener

- Client

examples/Basic/README

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
#

# ==============================================================================
#
#  JMX Tutorial Example
#
#  The aim of this example is to show the basic use of the JMX technology. It
#  shows the use of standard and dynamic MBeans, and how to perform operations
#  locally and remotely, through the RMI connector. In this example both the
#  SimpleStandard MBean and the SimpleDynamic MBean expose the same management
#  interface.
#
# ==============================================================================
#
# In order to compile and run the example, make a copy of this README file, and
# then simply cut and paste all the commands as needed into a terminal window.
#
# This README makes the assumption that you are running under Java SE 6 on Unix,
# you are familiar with the JMX technology, and with the bourne shell or korn
# shell syntax.
#
# All the commands below are defined using Unix korn shell syntax.
#
# If you are not running Unix and korn shell you are expected to be able to
# adapt these commands to your favorite OS and shell environment.
#

# Compile Java classes
#
# * Server.java: creates an MBeanServer,
#                registers a SimpleStandard MBean on the local MBeanServer,
#                registers a SimpleDynamic MBean on the local MBeanServer,
#                performs local operations on both MBeans,
#                creates and starts an RMI connector server (JRMP).
#
# * Client.java: creates an RMI connector (JRMP),
#                registers a SimpleStandard MBean on the remote MBeanServer,
#                registers a SimpleDynamic MBean on the remote MBeanServer,
#                performs remote operations on both MBeans,
#                closes the RMI connector.
#
# * ClientListener.java: implements a generic notification listener.
#
# * SimpleStandard.java: implements the Simple standard MBean.
#
# * SimpleStandardMBean.java: the management interface exposed
#                             by the Simple standard MBean.
#
# * SimpleDynamic.java: implements the Simple dynamic MBean.
#

javac *.java

# Start the RMI registry:
#

rmiregistry 9999 &

# Start the Server (follow the server's execution steps
#                   until it prompts you to start the
#                   client on a different shell window)
#

java -classpath . Server

# Start the Client (on a different shell window)
#

java -classpath . Client

# ==============================================================================

examples/Basic/Server.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import java.io.IOException;
import javax.management.Attribute;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

public class Server {

public static void main(String[] args) {
try {
// Instantiate the MBean server
//
echo("\n>>> Create the MBean server");
MBeanServer mbs = MBeanServerFactory.createMBeanServer();
waitForEnterPressed();

// Get default domain
//
echo("\n>>> Get the MBean server's default domain");
String domain = mbs.getDefaultDomain();
echo("\tDefault Domain = " + domain);
waitForEnterPressed();

// Create and register the SimpleStandard MBean
//
String mbeanClassName = "SimpleStandard";
String mbeanObjectNameStr =
domain + ":type=" + mbeanClassName + ",name=1";
ObjectName mbeanObjectName =
createSimpleMBean(mbs, mbeanClassName, mbeanObjectNameStr);
waitForEnterPressed();

// Get and display the management information exposed by the
// SimpleStandard MBean
//
printMBeanInfo(mbs, mbeanObjectName, mbeanClassName);
waitForEnterPressed();

// Manage the SimpleStandard MBean
//
manageSimpleMBean(mbs, mbeanObjectName, mbeanClassName);
waitForEnterPressed();

// Create and register the SimpleDynamic MBean
//
mbeanClassName = "SimpleDynamic";
mbeanObjectNameStr =
domain + ":type=" + mbeanClassName + ",name=1";
mbeanObjectName =
createSimpleMBean(mbs, mbeanClassName, mbeanObjectNameStr);
waitForEnterPressed();

// Get and display the management information exposed by the
// SimpleDynamic MBean
//
printMBeanInfo(mbs, mbeanObjectName, mbeanClassName);
waitForEnterPressed();

// Manage the SimpleDynamic MBean
//
manageSimpleMBean(mbs, mbeanObjectName, mbeanClassName);
waitForEnterPressed();

// Create an RMI connector server
//
echo("\nCreate an RMI connector server");
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);

// Start the RMI connector server
//
echo("\nStart the RMI connector server");
cs.start();
echo("\nThe RMI connector server successfully started");
echo("and is ready to handle incoming connections");
echo("\nStart the client on a different window and");
echo("press <Enter> once the client has finished");
waitForEnterPressed();

// Stop the RMI connector server
//
echo("\nStop the RMI connector server");
cs.stop();
System.out.println("\nBye! Bye!");
} catch (Exception e) {
e.printStackTrace();
}
}

private static ObjectName createSimpleMBean(MBeanServer mbs,
String mbeanClassName,
String mbeanObjectNameStr) {
echo("\n>>> Create the " + mbeanClassName +
" MBean within the MBeanServer");
echo("\tObjectName = " + mbeanObjectNameStr);
try {
ObjectName mbeanObjectName =
ObjectName.getInstance(mbeanObjectNameStr);
mbs.createMBean(mbeanClassName, mbeanObjectName);
return mbeanObjectName;
} catch (Exception e) {
echo("\t!!! Could not create the " + mbeanClassName + " MBean !!!");
e.printStackTrace();
echo("\nEXITING...\n");
System.exit(1);
}
return null;
}

private static void printMBeanInfo(MBeanServer mbs,
ObjectName mbeanObjectName,
String mbeanClassName) {
echo("\n>>> Retrieve the management information for the " +
mbeanClassName);
echo("    MBean using the getMBeanInfo() method of the MBeanServer");
MBeanInfo info = null;
try {
info = mbs.getMBeanInfo(mbeanObjectName);
} catch (Exception e) {
echo("\t!!! Could not get MBeanInfo object for " +
mbeanClassName +" !!!");
e.printStackTrace();
return;
}
echo("\nCLASSNAME: \t" + info.getClassName());
echo("\nDESCRIPTION: \t" + info.getDescription());
echo("\nATTRIBUTES");
MBeanAttributeInfo[] attrInfo = info.getAttributes();
if (attrInfo.length > 0) {
for (int i = 0; i < attrInfo.length; i++) {
echo(" ** NAME: \t" + attrInfo[i].getName());
echo("    DESCR: \t" + attrInfo[i].getDescription());
echo("    TYPE: \t" + attrInfo[i].getType() +
"\tREAD: "+ attrInfo[i].isReadable() +
"\tWRITE: "+ attrInfo[i].isWritable());
}
} else echo(" ** No attributes **");
echo("\nCONSTRUCTORS");
MBeanConstructorInfo[] constrInfo = info.getConstructors();
for (int i=0; i<constrInfo.length; i++) {
echo(" ** NAME: \t" + constrInfo[i].getName());
echo("    DESCR: \t" + constrInfo[i].getDescription());
echo("    PARAM: \t" + constrInfo[i].getSignature().length +
" parameter(s)");
}
echo("\nOPERATIONS");
MBeanOperationInfo[] opInfo = info.getOperations();
if (opInfo.length > 0) {
for (int i = 0; i < opInfo.length; i++) {
echo(" ** NAME: \t" + opInfo[i].getName());
echo("    DESCR: \t" + opInfo[i].getDescription());
echo("    PARAM: \t" + opInfo[i].getSignature().length +
" parameter(s)");
}
} else echo(" ** No operations ** ");
echo("\nNOTIFICATIONS");
MBeanNotificationInfo[] notifInfo = info.getNotifications();
if (notifInfo.length > 0) {
for (int i = 0; i < notifInfo.length; i++) {
echo(" ** NAME: \t" + notifInfo[i].getName());
echo("    DESCR: \t" + notifInfo[i].getDescription());
String notifTypes[] = notifInfo[i].getNotifTypes();
for (int j = 0; j < notifTypes.length; j++) {
echo("    TYPE: \t" + notifTypes[j]);
}
}
} else echo(" ** No notifications **");
}

private static void manageSimpleMBean(MBeanServer mbs,
ObjectName mbeanObjectName,
String mbeanClassName) {

echo("\n>>> Manage the " + mbeanClassName +
" MBean using its attributes ");
echo("    and operations exposed for management");

try {
// Get attribute values
printSimpleAttributes(mbs, mbeanObjectName);

// Change State attribute
echo("\n    Setting State attribute to value \"new state\"...");
Attribute stateAttribute = new Attribute("State","new state");
mbs.setAttribute(mbeanObjectName, stateAttribute);

// Get attribute values
printSimpleAttributes(mbs, mbeanObjectName);

// Invoking reset operation
echo("\n    Invoking reset operation...");
mbs.invoke(mbeanObjectName, "reset", null, null);

// Get attribute values
printSimpleAttributes(mbs, mbeanObjectName);
} catch (Exception e) {
e.printStackTrace();
}
}

private static void printSimpleAttributes(MBeanServer mbs,
ObjectName mbeanObjectName) {
try {
echo("\n    Getting attribute values:");
String State = (String) mbs.getAttribute(mbeanObjectName, "State");
Integer NbChanges =
(Integer) mbs.getAttribute(mbeanObjectName,"NbChanges");
echo("\tState     = \"" + State + "\"");
echo("\tNbChanges = " + NbChanges);
} catch (Exception e) {
echo("\t!!! Could not read attributes !!!");
e.printStackTrace();
}
}

private static void echo(String msg) {
System.out.println(msg);
}

private static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

private static void waitForEnterPressed() {
try {
echo("\nPress <Enter> to continue...");
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}

examples/Basic/SimpleStandardMBean.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* This is the management interface explicitly defined for the
* "SimpleStandard" standard MBean.
*
* The "SimpleStandard" standard MBean implements this interface
* in order to be manageable through a JMX agent.
*
* The "SimpleStandardMBean" interface shows how to expose for management:
* - a read/write attribute (named "State") through its getter and setter
*   methods,
* - a read-only attribute (named "NbChanges") through its getter method,
* - an operation (named "reset").
*/
public interface SimpleStandardMBean {

/**
* Getter: set the "State" attribute of the "SimpleStandard" standard
* MBean.
*
* @return the current value of the "State" attribute.
*/
public String getState();

/**
* Setter: set the "State" attribute of the "SimpleStandard" standard
* MBean.
*
* @param <VAR>s</VAR> the new value of the "State" attribute.
*/
public void setState(String s);

/**
* Getter: get the "NbChanges" attribute of the "SimpleStandard" standard
* MBean.
*
* @return the current value of the "NbChanges" attribute.
*/
public int getNbChanges();

/**
* Operation: reset to their initial values the "State" and "NbChanges"
* attributes of the "SimpleStandard" standard MBean.
*/
public void reset();
}

examples/Basic/SimpleStandard.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* Simple definition of a standard MBean, named "SimpleStandard".
*
* The "SimpleStandard" standard MBean shows how to expose attributes
* and operations for management by implementing its corresponding
* "SimpleStandardMBean" management interface.
*
* This MBean has two attributes and one operation exposed
* for management by a JMX agent:
*      - the read/write "State" attribute,
*      - the read only "NbChanges" attribute,
*      - the "reset()" operation.
*
* This object also has one property and one method not exposed
* for management by a JMX agent:
*      - the "NbResets" property,
*      - the "getNbResets()" method.
*/

import javax.management.AttributeChangeNotification;
import javax.management.MBeanNotificationInfo;
import javax.management.NotificationBroadcasterSupport;

public class SimpleStandard
extends NotificationBroadcasterSupport
implements SimpleStandardMBean {

/*
* -----------------------------------------------------
* CONSTRUCTORS
* -----------------------------------------------------
*/

/* "SimpleStandard" does not provide any specific constructors.
* However, "SimpleStandard" is JMX compliant with regards to
* contructors because the default contructor SimpleStandard()
* provided by the Java compiler is public.
*/

/*
* -----------------------------------------------------
* IMPLEMENTATION OF THE SimpleStandardMBean INTERFACE
* -----------------------------------------------------
*/

/**
* Getter: get the "State" attribute of the "SimpleStandard" standard MBean.
*
* @return the current value of the "State" attribute.
*/
public String getState() {
return state;
}

/**
* Setter: set the "State" attribute of the "SimpleStandard" standard MBean.
*
* @param <VAR>s</VAR> the new value of the "State" attribute.
*/
public void setState(String s) {
state = s;
nbChanges++;
}

/**
* Getter: get the "NbChanges" attribute of the "SimpleStandard" standard
* MBean.
*
* @return the current value of the "NbChanges" attribute.
*/
public int getNbChanges() {
return nbChanges;
}

/**
* Operation: reset to their initial values the "State" and "NbChanges"
* attributes of the "SimpleStandard" standard MBean.
*/
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);
}

/*
* -----------------------------------------------------
* METHOD NOT EXPOSED FOR MANAGEMENT BY A JMX AGENT
* -----------------------------------------------------
*/

/**
* Return the "NbResets" property.
* This method is not a Getter in the JMX sense because it
* is not exposed in the "SimpleStandardMBean" interface.
*
* @return the current value of the "NbResets" property.
*/
public int getNbResets() {
return nbResets;
}

/**
* Returns an array indicating, for each notification this MBean
* may send, the name of the Java class of the notification and
* the notification type.</p>
*
* @return the array of possible notifications.
*/
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.")
};
}

/*
* -----------------------------------------------------
* ATTRIBUTES ACCESSIBLE FOR MANAGEMENT BY A JMX AGENT
* -----------------------------------------------------
*/

private String state = "initial state";
private int nbChanges = 0;

/*
* -----------------------------------------------------
* PROPERTY NOT ACCESSIBLE FOR MANAGEMENT BY A JMX AGENT
* -----------------------------------------------------
*/

private int nbResets = 0;
}

examples/Basic/SimpleDynamic.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* Simple definition of a dynamic MBean, named "SimpleDynamic".
*
* The "SimpleDynamic" dynamic MBean shows how to expose for management
* attributes and operations, at runtime,  by implementing the
* "javax.management.DynamicMBean" interface.
*
* This MBean exposes for management two attributes and one operation:
*      - the read/write "State" attribute,
*      - the read only "NbChanges" attribute,
*      - the "reset()" operation.
* It does so by putting this information in an MBeanInfo object that
* is returned by the getMBeanInfo() method of the DynamicMBean interface.
*
* It implements the access to its attributes through the getAttribute(),
* getAttributes(), setAttribute(), and setAttributes() methods of the
* DynamicMBean interface.
*
* It implements the invocation of its reset() operation through the
* invoke() method of the DynamicMBean interface.
*
* Note that as "SimpleDynamic" explicitly defines one constructor,
* this constructor must be public and exposed for management through
* the MBeanInfo object.
*/

import java.lang.reflect.Constructor;
import java.util.Iterator;
import javax.management.*;

public class SimpleDynamic
extends NotificationBroadcasterSupport
implements DynamicMBean {

/*
* -----------------------------------------------------
* CONSTRUCTORS
* -----------------------------------------------------
*/

public SimpleDynamic() {
// Build the management information to be exposed by the dynamic MBean
//
buildDynamicMBeanInfo();
}

/*
* -----------------------------------------------------
* IMPLEMENTATION OF THE DynamicMBean INTERFACE
* -----------------------------------------------------
*/

/**
* Allows the value of the specified attribute of the Dynamic MBean to be
* obtained.
*/
public Object getAttribute(String attribute_name)
throws AttributeNotFoundException,
MBeanException,
ReflectionException {

// Check attribute_name is not null to avoid NullPointerException
// later on
//
if (attribute_name == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Attribute name cannot be null"),
"Cannot invoke a getter of " + dClassName +
" with null attribute name");
}
// Check for a recognized attribute_name and call the corresponding
// getter
//
if (attribute_name.equals("State")) {
return getState();
}
if (attribute_name.equals("NbChanges")) {
return getNbChanges();
}
// If attribute_name has not been recognized throw an
// AttributeNotFoundException
//
throw new AttributeNotFoundException("Cannot find " +
attribute_name +
" attribute in " +
dClassName);
}

/**
* Sets the value of the specified attribute of the Dynamic MBean.
*/
public void setAttribute(Attribute attribute)
throws AttributeNotFoundException,
InvalidAttributeValueException,
MBeanException,
ReflectionException {

// Check attribute is not null to avoid NullPointerException later on
//
if (attribute == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Attribute cannot be null"),
"Cannot invoke a setter of " + dClassName +
" with null attribute");
}
String name = attribute.getName();
Object value = attribute.getValue();
if (name == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Attribute name cannot be null"),
"Cannot invoke the setter of " + dClassName +
" with null attribute name");
}
// Check for a recognized attribute name and call the corresponding
// setter
//
if (name.equals("State")) {
// if null value, try and see if the setter returns any exception
if (value == null) {
try {
setState( null );
} catch (Exception e) {
throw new InvalidAttributeValueException(
"Cannot set attribute " + name + " to null");
}
}
// if non null value, make sure it is assignable to the attribute
else {
try {
if (Class.forName("java.lang.String").isAssignableFrom(
value.getClass())) {
setState((String) value);
} else {
throw new InvalidAttributeValueException(
"Cannot set attribute " + name + " to a " +
value.getClass().getName() +
" object, String expected");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
// recognize an attempt to set "NbChanges" attribute (read-only):
else if (name.equals("NbChanges")) {
throw new AttributeNotFoundException(
"Cannot set attribute " + name + " because it is read-only");
}
// unrecognized attribute name:
else {
throw new AttributeNotFoundException("Attribute " + name +
" not found in " +
this.getClass().getName());
}
}

/**
* Enables the to get the values of several attributes of the Dynamic MBean.
*/
public AttributeList getAttributes(String[] attributeNames) {

// Check attributeNames is not null to avoid NullPointerException
// later on
//
if (attributeNames == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("attributeNames[] cannot be null"),
"Cannot invoke a getter of " + dClassName);
}
AttributeList resultList = new AttributeList();

// If attributeNames is empty, return an empty result list
//
if (attributeNames.length == 0)
return resultList;

// Build the result attribute list
//
for (int i = 0 ; i < attributeNames.length ; i++) {
try {
Object value = getAttribute((String) attributeNames[i]);
resultList.add(new Attribute(attributeNames[i],value));
} catch (Exception e) {
e.printStackTrace();
}
}
return resultList;
}

/**
* Sets the values of several attributes of the Dynamic MBean, and returns
* the list of attributes that have been set.
*/
public AttributeList setAttributes(AttributeList attributes) {

// Check attributes is not null to avoid NullPointerException later on
//
if (attributes == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException(
"AttributeList attributes cannot be null"),
"Cannot invoke a setter of " + dClassName);
}
AttributeList resultList = new AttributeList();

// If attributeNames is empty, nothing more to do
//
if (attributes.isEmpty())
return resultList;

// For each attribute, try to set it and add to the result list if
// successfull
//
for (Iterator i = attributes.iterator(); i.hasNext();) {
Attribute attr = (Attribute) i.next();
try {
setAttribute(attr);
String name = attr.getName();
Object value = getAttribute(name);
resultList.add(new Attribute(name,value));
} catch(Exception e) {
e.printStackTrace();
}
}
return resultList;
}

/**
* Allows an operation to be invoked on the Dynamic MBean.
*/
public Object invoke(String operationName,
Object params[],
String signature[])
throws MBeanException, ReflectionException {

// Check operationName is not null to avoid NullPointerException
// later on
//
if (operationName == null) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Operation name cannot be null"),
"Cannot invoke a null operation in " + dClassName);
}
// Check for a recognized operation name and call the corresponding
// operation
//
if (operationName.equals("reset")) {
reset();
return null;
} else {
// Unrecognized operation name
//
throw new ReflectionException(
new NoSuchMethodException(operationName),
"Cannot find the operation " + operationName +
" in " + dClassName);
}
}

/**
* This method provides the exposed attributes and operations of the
* Dynamic MBean. It provides this information using an MBeanInfo object.
*/
public MBeanInfo getMBeanInfo() {

// Return the information we want to expose for management:
// the dMBeanInfo private field has been built at instanciation time
//
return dMBeanInfo;
}

/*
* -----------------------------------------------------
* OTHER PUBLIC METHODS
* -----------------------------------------------------
*/

/**
* Getter: get the "State" attribute of the "SimpleDynamic" dynamic MBean.
*/
public String getState() {
return state;
}

/**
* Setter: set the "State" attribute of the "SimpleDynamic" dynamic MBean.
*/
public void setState(String s) {
state = s;
nbChanges++;
}

/**
* Getter: get the "NbChanges" attribute of the "SimpleDynamic" dynamic
* MBean.
*/
public Integer getNbChanges() {
return new Integer(nbChanges);
}

/**
* Operation: reset to their initial values the "State" and "NbChanges"
* attributes of the "SimpleDynamic" dynamic MBean.
*/
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);
}

/**
* Return the "NbResets" property.
* This method is not a Getter in the JMX sense because
* it is not returned by the getMBeanInfo() method.
*/
public Integer getNbResets() {
return new Integer(nbResets);
}

/*
* -----------------------------------------------------
* PRIVATE METHODS
* -----------------------------------------------------
*/

/**
* Build the private dMBeanInfo field,
* which represents the management interface exposed by the MBean,
* that is, the set of attributes, constructors, operations and
* notifications which are available for management.
*
* A reference to the dMBeanInfo object is returned by the getMBeanInfo()
* method of the DynamicMBean interface. Note that, once constructed, an
* MBeanInfo object is immutable.
*/
private void buildDynamicMBeanInfo() {

dAttributes[0] =
new MBeanAttributeInfo("State",
"java.lang.String",
"State string.",
true,
true,
false);
dAttributes[1] =
new MBeanAttributeInfo("NbChanges",
"java.lang.Integer",
"Number of times the " +
"State string has been changed.",
true,
false,
false);

Constructor[] constructors = this.getClass().getConstructors();
dConstructors[0] =
new MBeanConstructorInfo("Constructs a " +
"SimpleDynamic object",
constructors[0]);

MBeanParameterInfo[] params = null;
dOperations[0] =
new MBeanOperationInfo("reset",
"reset State and NbChanges " +
"attributes to their initial values",
params ,
"void",
MBeanOperationInfo.ACTION);

dNotifications[0] =
new MBeanNotificationInfo(
new String[] { AttributeChangeNotification.ATTRIBUTE_CHANGE },
AttributeChangeNotification.class.getName(),
"This notification is emitted when the reset() method is called.");

dMBeanInfo = new MBeanInfo(dClassName,
dDescription,
dAttributes,
dConstructors,
dOperations,
dNotifications);
}

/*
* -----------------------------------------------------
* PRIVATE VARIABLES
* -----------------------------------------------------
*/

private String state = "initial state";
private int nbChanges = 0;
private int nbResets = 0;

private String dClassName = this.getClass().getName();
private String dDescription = "Simple implementation of a dynamic MBean.";

private MBeanAttributeInfo[] dAttributes =
new MBeanAttributeInfo[2];
private MBeanConstructorInfo[] dConstructors =
new MBeanConstructorInfo[1];
private MBeanNotificationInfo[] dNotifications =
new MBeanNotificationInfo[1];
private MBeanOperationInfo[] dOperations =
new MBeanOperationInfo[1];
private MBeanInfo dMBeanInfo = null;
}

examples/Basic/ClientListener.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import javax.management.Notification;
import javax.management.NotificationListener;

public class ClientListener implements NotificationListener {
public void handleNotification(Notification notification, Object handback) {
System.out.println("\nReceived notification: " + notification);
}
}

examples/Basic/Client.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import java.io.IOException;
import java.util.Iterator;
import java.util.Set;
import javax.management.Attribute;
import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

public class Client {

public static void main(String[] args) {
try {
// Create an RMI connector client and
// connect it to the RMI connector server
//
echo("\nCreate an RMI connector client and " +
"connect it to the RMI connector server");
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);

// Create listener
//
ClientListener listener = new ClientListener();

// Get an MBeanServerConnection
//
echo("\nGet an MBeanServerConnection");
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
waitForEnterPressed();

// Get domains from MBeanServer
//
echo("\nDomains:");
String domains[] = mbsc.getDomains();
for (int i = 0; i < domains.length; i++) {
echo("\tDomain[" + i + "] = " + domains[i]);
}
waitForEnterPressed();

// Get MBeanServer's default domain
//
String domain = mbsc.getDefaultDomain();

// Create SimpleStandard MBean
//
ObjectName stdMBeanName =
new ObjectName(domain +":type=SimpleStandard,name=2");
echo("\nCreate SimpleStandard MBean...");
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("\tObjectName = " + (ObjectName) i.next());
}
waitForEnterPressed();

// -------------------------------
// Manage the SimpleStandard MBean
// -------------------------------
echo("\n>>> Perform operations on SimpleStandard MBean <<<");

// Get State attribute in SimpleStandard MBean
//
echo("\nState = " + mbsc.getAttribute(stdMBeanName, "State"));

// Set State attribute in SimpleStandard MBean
//
mbsc.setAttribute(stdMBeanName,
new Attribute("State", "changed state"));

// Get State attribute in SimpleStandard MBean
//
// Another way of interacting with a given MBean is through a
// dedicated proxy instead of going directly through the MBean
// server connection
//
SimpleStandardMBean proxy = JMX.newMBeanProxy(
mbsc, stdMBeanName, SimpleStandardMBean.class, true);
echo("\nState = " + proxy.getState());

// Add notification listener on SimpleStandard MBean
//
echo("\nAdd notification listener...");
mbsc.addNotificationListener(stdMBeanName, listener, null, null);

// Invoke "reset" in SimpleStandard MBean
//
// Calling "reset" makes the SimpleStandard MBean emit a
// notification that will be received by the registered
// ClientListener.
//
echo("\nInvoke reset() in SimpleStandard MBean...");
mbsc.invoke(stdMBeanName, "reset", null, null);

// Sleep for 2 seconds in order to have time to receive the
// notification before removing the notification listener.
//
echo("\nWaiting for notification...");
sleep(2000);

// Remove notification listener on SimpleStandard MBean
//
echo("\nRemove notification listener...");
mbsc.removeNotificationListener(stdMBeanName, listener);

// Unregister SimpleStandard MBean
//
echo("\nUnregister SimpleStandard MBean...");
mbsc.unregisterMBean(stdMBeanName);
waitForEnterPressed();

// ------------------------------
// Manage the SimpleDynamic MBean
// ------------------------------
echo("\n>>> Perform operations on SimpleDynamic MBean <<<");

// Get State attribute in SimpleDynamic MBean
//
echo("\nState = " + mbsc.getAttribute(dynMBeanName, "State"));

// Set State attribute in SimpleDynamic MBean
//
mbsc.setAttribute(dynMBeanName,
new Attribute("State", "changed state"));

// Get State attribute in SimpleDynamic MBean
//
echo("\nState = " +
mbsc.getAttribute(dynMBeanName, "State"));

// Add notification listener on SimpleDynamic MBean
//
echo("\nAdd notification listener...");
mbsc.addNotificationListener(dynMBeanName, listener, null, null);

// Invoke "reset" in SimpleDynamic MBean
//
// Calling "reset" makes the SimpleDynamic MBean emit a
// notification that will be received by the registered
// ClientListener.
//
echo("\nInvoke reset() in SimpleDynamic MBean...");
mbsc.invoke(dynMBeanName, "reset", null, null);

// Sleep for 2 seconds in order to have time to receive the
// notification before removing the notification listener.
//
echo("\nWaiting for notification...");
sleep(2000);

// Remove notification listener on SimpleDynamic MBean
//
echo("\nRemove notification listener...");
mbsc.removeNotificationListener(dynMBeanName, listener);

// Unregister SimpleDynamic MBean
//
echo("\nUnregister SimpleDynamic MBean...");
mbsc.unregisterMBean(dynMBeanName);
waitForEnterPressed();

// Close MBeanServer connection
//
echo("\nClose the connection to the server");
jmxc.close();
echo("\nBye! Bye!");
} catch (Exception e) {
e.printStackTrace();
}
}

private static void echo(String msg) {
System.out.println(msg);
}

private static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

private static void waitForEnterPressed() {
try {
echo("\nPress <Enter> to continue...");
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}

19 Service Location Protocol (SLP)検索サービス

JMX APIは既存の検索テクノロジを使用した、検索サービスの3つのバインディングを定義しています。この例では、Service Location Protocol (SLP)検索サービスの次のような実装例が用意されています。

- README file

- Server

- Client

examples/Lookup/slp/README

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
#

# ==============================================================================
#
# Example of using SLP as Lookup service - registering and looking up
# an RMI Connector (IIOP/JRMP)
#
# ==============================================================================
#
# Requirements:
#
# The code provided in this example is build against Sun's Java
# implementation of SLP - compliant to RFC 2614 see
# [http://www.ietf.org/rfc/rfc2614.txt]. Sun's Java implementation
# of SLP is available on Solaris systems under /usr/share/lib/slp
#
#
# Before running this example you will have to:
# ---------------------------------------------
#
# If you are not running Solaris:
#
#     You will have to get a Java implementation of SLP compliant to
#     RFC 2614, section 5. You can download the OpenSLP Java implementation
#     from http://www.openslp.org/. Then you may have to modify Client.java
#     and Server.java in order to use <my-slp-impl>.slp instead of
#     com.sun.slp. If your SLP implementation is RFC 2614 compliant
#     the changes should be limited to replacing 'com.sun.slp' in the
#     import clauses by '<my-slp-impl>.slp'.
#
# If you wish to use an external directory for the RMI JMX Connectors
# (URLs of the form jmx:service:[rmi|iiop]:/host:port/jndi/jndi-url)
# then:
#
#   o If you wish to use rmiregistry in conjunction with the RMI/JRMP
#     JMX Connector you will have to start a rmiregistry (see below).
#
#   o If you wish to use CORBA Naming Service in conjunction with the RMI/IIOP
#     JMX Connector you will have to start an ORB daemon (see below).
#
#   o If you wish to use LDAP in conjunction with the RMI JMX Connectors
#     you will have to install/setup a directory server
#
# In order to compile and run the example, make a copy of this README file, and
# then simply cut and paste all the commands as needed into a terminal window.
#
# This README makes the assumption that you are running under Java SE 6 on Unix,
# you are familiar with SLP, the JMX technology, with LDAP and JNDI, and with
# the bourne shell or korn shell syntax.
#
# All the commands below are defined using Unix korn shell syntax.
#
# If you are not running Unix and korn shell you are expected to be able to
# adapt these commands to your favorite OS and shell environment.
#

# Solaris:
#
SLP_HOME=/usr/share/lib/slp

# Define the following variables:
#
SLPLIB=$SLP_HOME

classp=$SLPLIB/slp.jar

#-------------------------------------------------------------------------------
# The SLP daemon needs to be launched with root privilege on each
# host who uses the SLP API. To launch the SLP daemon, simply type
# the following command line:
#
su root -c "java -cp $SLPLIB/slpd.jar com.sun.slp.slpd &"

#-------------------------------------------------------------------------------
# Start an rmiregistry
#
rmiregistry 9999 &

#-------------------------------------------------------------------------------
# Start an ORB daemon:
#
rm -rf ./orb.db
orbd -ORBInitialPort 7777 &

#-------------------------------------------------------------------------------
# Start an LDAP Server, and create a new dc=Test suffix inside.
#
# (only needed if you wish to register the RMI or IIOP stubs in
# LDAP, instead of using CORBA Naming Service or RMI registry)
#
# On Solaris 9 you should first login as root and execute
# the following commands:

# Setup an LDAP server (you don't need to do this if the
# server has already been configured).
#
/usr/sbin/directoryserver setup

# Start the console, and if needed create a new suffix, a database,
# and a root node (e.g. dc=Test)
#
/usr/sbin/directoryserver startconsole

# NOTE: if you're not using Solaris 9 Directory Server you will have
#       to make sure the Java Schema (RFC 2713:
#       http://www.ietf.org/rfc/rfc2713.txt) is known by that server

#-------------------------------------------------------------------------------
# Compile Server.java and Client.java
#
# * Server.java: creates an MBeanServer, creates and starts an
#                RMI connector (JRMP/IIOP)
# * Client.java: lookup a connector in SLP
#                list all MBeans.
#
javac -d . -classpath $classp Server.java Client.java

#-------------------------------------------------------------------------------
# LDAP Parameters

# Supply the appropriate hostname below, and define this variable:
#
ldaphost=gigondas

# Supply the appropriate port number below, and define this variable:
#
ldapport=6666

# Supply the appropriate principal below, and define this variable:
#
principal="cn=Directory Manager"

# Supply the appropriate credentials below, and define this variable:
#
credentials=

#-------------------------------------------------------------------------------
# JNDI URLs
#
jndirmi="rmi://localhost:9999"
jndiiiop="iiop://localhost:7777"
jndildap="ldap://$ldaphost:$ldapport"

#-------------------------------------------------------------------------------
# JMX Service URLs
#
jmxiiopurl="service:jmx:iiop:///jndi/${jndiiiop}/server"
jmxrmiurl="service:jmx:rmi:///jndi/${jndirmi}/server"
jmxiiopldapurl="service:jmx:iiop:///jndi/${jndildap}/cn=x,dc=Test"
jmxrmildapurl="service:jmx:rmi:///jndi/${jndildap}/cn=x,dc=Test"
jmxstuburl="service:jmx:rmi://"
jmxiorurl="service:jmx:iiop://"

#-------------------------------------------------------------------------------
# Below we illustrate the different JMX Connector Servers
# which you have the choice to start.
# There are seven cases labelled (a) to (f):
#
#   * RMI Connectors
#       + over JRMP
#           - without any external directory (a)
#           - using rmiregistry as external directory (b)
#           - using LDAP as external directory (c)
#       + over IIOP
#           - without any external directory (d)
#           - using CORBA Naming Service as external directory (e)
#           - using LDAP as external directory (f)

# NOTE-1: As defined in section 6.1 "Terminology" of the "JMX Remote API 1.0
# Specification" document, an agent is composed of one MBean Server and of
# one or more Connector Servers. There can be several agents running in one JVM.
# For flexibility of this example, the slp.Server class creates an agent which
# is composed of one MBean Server and of only one Connector Server. The class
# slp.Server decides which type of Connector Server to create depending on the
# value given to the "url" system property when you start the example.

# NOTE-2: The value of the "agent.name" system property is the value that the
# slp.Server class will give to the "AgentName" lookup attribute when it
# registers the connector's URL in the lookup service. As defined in Table 6.1
# "Lookup attributes for connectors" of the "JMX Remote API 1.0 Specification"
# document: the "AgentName" lookup attribute is a simple name used to identify
# the *AGENT* to which the connector is attached. It makes it possible to
# search, with a query to the lookup service, for all the connectors registered
# by a given agent.

# (a) You can start an agent with an RMI Connector Server over JRMP
#     without using any external directory
#
java -classpath .:$classp -Ddebug=true \
-Dagent.name=test-server-a \
-Durl="service:jmx:rmi://" \
slp.Server &

# (b) Or you can start an agent with an RMI Connector Server over JRMP
#     using rmiregistry as external directory
#     (Start rmiregistry first, if not yet started)
#
java -classpath .:$classp -Ddebug=true \
-Dagent.name=test-server-b \
-Durl="service:jmx:rmi:///jndi/${jndirmi}/server" \
slp.Server &

# (c) Or you can start an agent with an RMI Connector Server over JRMP
#     using LDAP as external directory
#     (First start an LDAP server and create the dc=Test suffix)
#
java -classpath .:$classp -Ddebug=true \
-Dagent.name=test-server-c \
-Durl="service:jmx:rmi:///jndi/${jndildap}/cn=x,dc=Test" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
slp.Server &

# (d) Or you can start an agent with an RMI Connector Server over IIOP
#     without using any external directory
#
java -classpath .:$classp -Ddebug=true \
-Dagent.name=test-server-d \
-Durl="service:jmx:iiop://" \
slp.Server &

# (e) Or you can start an agent with an RMI Connector Server over IIOP
#     using CORBA Naming Service as external directory
#     (Start ORBD first if not yet started).
#
java -classpath .:$classp -Ddebug=true \
-Dagent.name=test-server-e \
-Durl="service:jmx:iiop:///jndi/${jndiiiop}/server" \
slp.Server &

# (f) Or you can start an agent with an RMI Connector Server over IIOP
#     using LDAP as external directory
#     (First start an LDAP server and create the dc=Test suffix)
#
java -classpath .:$classp -Ddebug=true \
-Dagent.name=test-server-f \
-Durl="service:jmx:iiop:///jndi/${jndildap}/cn=x,dc=Test" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
slp.Server &

# Once you have started one or more agents, you can start the Client.
# Note that for the client to look up through SLP an agent you have just
# started, you must start the client before your agent's SLP lease has
# expired. You can update the Server.java file and recompile it to change
# the lease period.
#
java -classpath .:$classp -Ddebug=true \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
slp.Client

#-------------------------------------------------------------------------------

examples/Lookup/slp/Server.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package slp;

import com.sun.slp.ServiceLocationManager;
import com.sun.slp.ServiceLocationException;
import com.sun.slp.Advertiser;
import com.sun.slp.ServiceURL;
import com.sun.slp.ServiceLocationAttribute;

import javax.management.*;
import javax.management.remote.*;
import javax.management.remote.rmi.*;

import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Vector;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;

import javax.naming.Context;
import javax.naming.NamingException;

/**
* This class demonstrates how to use SLP as a lookup service for
* JSR 160 connectors. It shows how to register a JMXConnectorServer
* with the Service Location Protocol.
* <p>
* See README file and {@link #main(String[])} for more details.
* <p>
* Make sure to read the section "Binding with Lookup Services" of
* the JMX Remote API 1.0 Specification before looking at this example.
*/
public class Server {

// The Service URL will remain registered for 300 secs.
// This is an intentionally long time for the purpose of this example.
// In practice, a shorter lease, periodically refreshed, is preferable.
//
public final static int JMX_DEFAULT_LEASE = 300;

// Default scope.
//
public final static String JMX_SCOPE = "DEFAULT";

// The local MBeanServer.
//
private final MBeanServer mbs;

private static boolean debug = false;

/**
* Constructs a Server object. Creates a new MBeanServer.
*/
public Server() {
mbs = MBeanServerFactory.createMBeanServer();
}

/**
* Registers a JMX Connector URL with the SLP Lookup Service.
*
* @param jmxUrl A JMX Connector Server URL obtained from
*               {@link JMXConnectorServer#getAddress()
*               JMXConnectorServer.getAddress()}
* @param name   The AgentName with which the URL will be
*               registered in the SLP Lookup Service.
*/
public static void register(JMXServiceURL jmxUrl, String name)
throws ServiceLocationException {

// Create the SLP service URL
//
// Note: It is recommended that the JMX Agents make use of the
// leasing feature of SLP, and periodically renew their lease
//
ServiceURL serviceURL = new ServiceURL(jmxUrl.toString(),
JMX_DEFAULT_LEASE);

System.out.println("\nRegistering URL for " +  name + ": " + jmxUrl);
debug("ServiceType is: " + serviceURL.getServiceType());

// Prepare Lookup Attributes
//
Vector attributes = new Vector();
Vector attrValues = new Vector();

// Specify default SLP scope
//
attrValues.add(JMX_SCOPE);
ServiceLocationAttribute attr1 =
new ServiceLocationAttribute("SCOPE", attrValues);
attributes.add(attr1);

// Specify AgentName attribute (mandatory)
//
attrValues.removeAllElements();
attrValues.add(name);
ServiceLocationAttribute attr2 =
new ServiceLocationAttribute("AgentName", attrValues);
attributes.add(attr2);

// Register with SLP
// -----------------

// Get SLP Advertiser
//
final Advertiser slpAdvertiser =
ServiceLocationManager.getAdvertiser(Locale.US);

// Register the service: URL
//
slpAdvertiser.register(serviceURL, attributes);
System.out.println("\nRegistered URL: " + jmxUrl);
}

/**
* Creates an RMI Connector Server, starts it, and registers it
* with the SLP Lookup Service.
* <p>
* This method will transfer a fixed set of System Properties to
* the Map given to the RMIConnectorServer constructor. Some
* JNDI properties, if defined, are transfered to the Map so
* that they may be used when LDAP is used as external directory
* to register the RMI Stub (see {@link javax.management.remote.rmi}
* Javadoc). Note that even if LDAP is used as external directory
* the {@link Context#INITIAL_CONTEXT_FACTORY
*            Context.INITIAL_CONTEXT_FACTORY} and
* {@link Context#PROVIDER_URL Context.PROVIDER_URL} properties
* usually don't need to be passed.
* <p>
* The following System properties, if defined, are transfered to
* the Map given to the RMIConnectorServer constructor.
* <ul><li>{@link Context#INITIAL_CONTEXT_FACTORY
*           Context.INITIAL_CONTEXT_FACTORY}</li>
*     <li>{@link Context#PROVIDER_URL
*           Context.PROVIDER_URL}</li>
*     <li>{@link Context#SECURITY_PRINCIPAL
*           Context.SECURITY_PRINCIPAL}</li>
*     <li>{@link Context#SECURITY_CREDENTIALS
*           Context.SECURITY_CREDENTIALS}</li>
*     <li>{@link RMIConnectorServer#JNDI_REBIND_ATTRIBUTE
*           RMIConnectorServer.JNDI_REBIND_ATTRIBUTE} - default
*           is <code>true</code>.</li>
* </ul>
*
* @param url A string representation of the JMXServiceURL.
*
* @return the created RMIConnectorServer.
*/
public JMXConnectorServer rmi(String url) throws
IOException,
JMException,
NamingException,
ClassNotFoundException,
ServiceLocationException {

// Make a JMXServiceURL from the url string.
//
JMXServiceURL jurl = new JMXServiceURL(url);

// Prepare the environment Map
//
final HashMap env = new HashMap();
final String rprop = RMIConnectorServer.JNDI_REBIND_ATTRIBUTE;
final String rebind = System.getProperty(rprop,"true");
final String factory =
System.getProperty(Context.INITIAL_CONTEXT_FACTORY);
final String ldapServerUrl =
System.getProperty(Context.PROVIDER_URL);
final String ldapUser =
System.getProperty(Context.SECURITY_PRINCIPAL);
final String ldapPasswd =
System.getProperty(Context.SECURITY_CREDENTIALS);

// Transfer some system properties to the Map
//
if (factory!= null) // this should not be needed
env.put(Context.INITIAL_CONTEXT_FACTORY,factory);
if (ldapServerUrl!=null) // this should not be needed
env.put(Context.PROVIDER_URL, ldapServerUrl);
if (ldapUser!=null) // this is needed when LDAP is used
env.put(Context.SECURITY_PRINCIPAL, ldapUser);
if (ldapPasswd != null) // this is needed when LDAP is used
env.put(Context.SECURITY_CREDENTIALS, ldapPasswd);
env.put(rprop,rebind); // default is true.

// Create an RMIConnectorServer
//
System.out.println("Creating RMI Connector: " + jurl);
JMXConnectorServer rmis =
JMXConnectorServerFactory.newJMXConnectorServer(jurl, env, mbs);

// Get the AgentName for registering the Connector in the Lookup Service
//
final String agentName = System.getProperty("agent.name",
"DefaultAgent");

// Start the connector and register it with SLP Lookup Service
//
start(rmis, agentName);

return rmis;
}

/**
* Start a JMXConnectorServer and register it with SLP Lookup Service.
*
* @param server the JMXConnectorServer to start and register.
* @param agentName the AgentName with which the URL must be registered
*                  in the SLP Lookup Service.
*/
public void start(JMXConnectorServer server, String agentName)
throws IOException, ServiceLocationException {

// Start the JMXConnectorServer
//
server.start();

// Create a JMX Service URL to register with SLP
//
final JMXServiceURL address = server.getAddress();

// Register the URL with the SLP Lookup Service.
//
register(address, agentName);
}

/**
* Trace a debug message.
*/
private static void debug(String msg) {
if (debug) System.out.println(msg);
}

/**
* Program Main
* <p>
* Creates a server object, gets the JMX Service URL, and calls
* the method that will create and register the appropriate JMX
* Connector Server for that URL.
* <p>
* You may wish to use the following properties on the Java command line:
* <ul>
* <li><code>-Durl=&lt;jmxServiceURL&gt;</code>: specifies the URL of
*     the JMX Connector Server you wish to use. See README file for more
*     details.</li>
* <li><code>-Dagent.name=&lt;AgentName&gt;</code>: specifies the
*     AgentName to register with.</li>
* <li><code>-Ddebug="true|false"</code>: switch the Server debug flag
*     on/off (default is "false").</li>
* </ul>
*/
public static void main(String[] args) {
try {
// Get the value of the debug flag.
//
debug = (Boolean.valueOf(System.getProperty("debug","false"))).
booleanValue();

// Create a new Server object.
//
final Server s = new Server();

// Get the JMXConnector URL
//
final String url = System.getProperty("url", "service:jmx:rmi://");

// Build a JMXServiceURL
//
final JMXServiceURL jurl = new JMXServiceURL(url);

// Creates a JMX Connector Server
//
debug("Creating Connector: " + jurl);
final String p = jurl.getProtocol();
if (p.equals("rmi"))         // Create an RMI Connector
s.rmi(url);
else if (p.equals("iiop"))   // Create an RMI/IIOP Connector
s.rmi(url);
else                         // Unsupported protocol
throw new MalformedURLException("Unsupported protocol: " + p);

System.out.println("\nService URL successfully registered " +
"in the SLP Lookup Service");

} catch (Exception x) {
System.err.println("Unexpected exception caught in main: " + x);
x.printStackTrace(System.err);
}
}
}

examples/Lookup/slp/Client.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package slp;

import com.sun.slp.ServiceLocationManager;
import com.sun.slp.ServiceLocationException;
import com.sun.slp.Locator;
import com.sun.slp.ServiceURL;
import com.sun.slp.ServiceLocationAttribute;
import com.sun.slp.ServiceType;
import com.sun.slp.ServiceLocationEnumeration;

import javax.management.*;
import javax.management.remote.*;

import javax.naming.Context;

import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Iterator;
import java.util.Locale;
import java.util.Vector;

import java.io.IOException;
import java.io.Serializable;

/**
* This class demonstrates how to use SLP as a lookup service for
* JSR 160 connectors. It shows how to lookup a JMXServiceURL
* from the SLP lookup service.
* <p>
* See README file and {@link #main(String[])} for more details.
* <p>
* Make sure to read the section "Binding with Lookup Services" of
* the JMX Remote API 1.0 Specification before looking at this example.
*/
public class Client {

// Default scope.
//
public final static String JMX_SCOPE = "DEFAULT";

private static boolean debug = false;

/**
* Get a pointer to the SLP Lookup Service.
* (See RFC 2614 for more info).
* @return a pointer to the SLP Lookup Service.
*/
public static Locator getLocator() throws ServiceLocationException {
// Getting the Locator (for lookup purposes)
//
final Locator slpLocator = ServiceLocationManager.getLocator(Locale.US);
return slpLocator;
}

/**
* Lookup JMXConnectors in the SLP Lookup Service.
*
* @param slpLocator A pointer to the SLP Lookup Service,
*        returned by {@link #getLocator()}.
* @param name the AgentName of the JMXConnectors that should
*        be returned. If <var>name</var> is null, then
*        the JMXConnectors for all agents are returned
*        (null is an equivalent for a wildcard).
* @return The list of matching JMXConnectors retrieved from
*         the SLP Lookup Service.
*/
public static List lookup(Locator slpLocator, String name)
throws IOException, ServiceLocationException {

final ArrayList list = new ArrayList();

// Set the lookup SCOPE.
//
Vector scopes = new Vector();
scopes.add(JMX_SCOPE);

// Set the LDAPv3 query string
//
// Will return only those services for which the AgentName
// attribute was registered. Since JSR 160 specifies that
// the AgentName attribute is mandatory, this makes it possible
// to filter out all the services that do not conform
// to the spec.
// If <name> is null, it is replaced by "*", so that all
// services for which the AgentName attribute was specified match,
// regardless of the value of that attribute.
// Otherwise, only those services for which AgentName matches the
// name or pattern specified by <name> will be returned.
//
String query = "(&(AgentName=" + ((name!=null)?name:"*") + "))";

debug("Looking up JMX Agents with filter: " + query );

// Lookup the JMX agents....
//
ServiceLocationEnumeration result =
slpLocator.findServices(new ServiceType("service:jmx"),
scopes, query);

debug("... Got service enumeration.");

// Build the JMXConnector list
//
while (result.hasMoreElements()) {
final ServiceURL surl = (ServiceURL) result.next();
debug("\nFound Service URL: " + surl);

// Some debug info:
//
if (debug) {
// Retrieve the Lookup Attributes that were registered
// with this URL
//
debug("Getting attributes...");
final ServiceLocationEnumeration slpAttributes =
slpLocator.findAttributes(surl, scopes, new Vector());
debug("... Got attribute enumeration.");
while (slpAttributes.hasMoreElements()) {
final ServiceLocationAttribute slpAttribute =
(ServiceLocationAttribute) slpAttributes.nextElement();
debug("\tAttribute: " + slpAttribute);
}
}

// Create a JMXConnector
// ---------------------

// Create a JMX Service URL
//
JMXServiceURL jmxUrl = new JMXServiceURL(surl.toString());
debug("JMX Service URL: " + jmxUrl);

// Obtain a JMXConnector from the factory
//
try {
JMXConnector client =
JMXConnectorFactory.newJMXConnector(jmxUrl,null);
debug("JMX Connector: " + client);

// Add the connector to the result list.
//
if (client != null) list.add(client);
} catch (IOException x ) {
System.err.println("Failed to create JMXConnector for " +
jmxUrl);
System.err.println("Error is: " + x);
System.err.println("Skipping...");
}
}

return list;
}

/**
* List all MBeans and their attributes.
*/
public static void listMBeans(MBeanServerConnection server)
throws IOException {

final Set names = server.queryNames(null,null);
for (final Iterator i=names.iterator(); i.hasNext(); ) {
ObjectName name = (ObjectName)i.next();
System.out.println("Got MBean: "+name);
try {
MBeanInfo info =
server.getMBeanInfo((ObjectName)name);
MBeanAttributeInfo[] attrs = info.getAttributes();
if (attrs == null) continue;
for (int j=0; j<attrs.length; j++) {
if (attrs[j].isReadable()) {
try {
Object o =
server.getAttribute(name,attrs[j].getName());
System.out.println("\t\t" + attrs[j].getName() +
" = "+o);
} catch (Exception x) {
System.err.println("JmxClient failed to get " +
attrs[j].getName());
x.printStackTrace(System.err);
}
}
}
} catch (Exception x) {
System.err.println("JmxClient failed to get MBeanInfo: "  + x);
x.printStackTrace(System.err);
}
}
}

/**
* Trace a debug message.
*/
private static void debug(String msg) {
if (debug) System.out.println(msg);
}

/**
* Program Main.
* <p>
* Lookup all JMX agents in the SLP Lookup Service and list
* their MBeans and attributes.
* <p>
* You may wish to use the following properties on the Java command line:
* <ul>
* <li><code>-Dagent.name=&lt;AgentName&gt;</code>: specifies an
*     AgentName to lookup (default is null, meaning any agent).</li>
* <li><code>-Ddebug="true|false"</code>: switch the Client debug flag
*     on/off (default is "false").</li>
* </ul>
*/
public static void main(String[] args) {
try {
// Get the value of the debug flag.
//
debug = (Boolean.valueOf(System.getProperty("debug","false"))).
booleanValue();

// Get AgentName to lookup.
// If not defined, all agents are taken into account.
//
final String agentName = System.getProperty("agent.name");

// Get a pointer to the SLP Lookup Service.
//
final Locator slpLocator = getLocator();
debug("slpLocator is: " + slpLocator);

// Lookup all matching agents in the SLP Lookup Service.
//
List l = lookup(slpLocator,agentName);

// Attempt to connect to retrieved agents
//
System.out.println("\nNumber of agents found : " + l.size());
int j = 1;
for (Iterator i=l.iterator();i.hasNext();j++) {
JMXConnector c1 = (JMXConnector) i.next();
if (c1 != null) {

// Connect
//
System.out.println(
"\n----------------------------------------------------");
System.out.println("\tConnecting to agent number "+j);
System.out.println(
"----------------------------------------------------");
debug("JMXConnector is: " + c1);

// Prepare the environment Map
//
final HashMap env = new HashMap();
final String factory =
System.getProperty(Context.INITIAL_CONTEXT_FACTORY);
final String ldapServerUrl =
System.getProperty(Context.PROVIDER_URL);
final String ldapUser =
System.getProperty(Context.SECURITY_PRINCIPAL);
final String ldapPasswd =
System.getProperty(Context.SECURITY_CREDENTIALS);

// Transfer some system properties to the Map
//
if (factory!= null) // this should not be needed
env.put(Context.INITIAL_CONTEXT_FACTORY,factory);
if (ldapServerUrl!=null) // this should not be needed
env.put(Context.PROVIDER_URL, ldapServerUrl);
if (ldapUser!=null) // this is needed when LDAP is used
env.put(Context.SECURITY_PRINCIPAL, ldapUser);
if (ldapPasswd != null) // this is needed when LDAP is used
env.put(Context.SECURITY_CREDENTIALS, ldapPasswd);

try {
c1.connect(env);
} catch (IOException x) {
System.err.println("Connection failed: " + x);
x.printStackTrace(System.err);
continue;
}

// Get MBeanServerConnection
//
MBeanServerConnection conn =
c1.getMBeanServerConnection();
debug("Connection is:" + conn);
System.out.println("Server domain is: " +
conn.getDefaultDomain());

// List all MBeans
//
try {
listMBeans(conn);
} catch (IOException x) {
System.err.println("Failed to list MBeans: " + x);
x.printStackTrace(System.err);
}

// Close connector
//
try {
c1.close();
} catch (IOException x) {
System.err.println("Failed to close connection: " + x);
x.printStackTrace(System.err);
}
}
}
} catch (Exception x) {
System.err.println("Unexpected exception caught in main: " + x);
x.printStackTrace(System.err);
}
}
}

20 Jini検索サービス

JMX APIは既存の検索テクノロジを使用した、検索サービスの3つのバインディングを定義しています。この例では、Jini検索サービスの次のような実装例が用意されています。

- README file

- Server

- Client

- java.policy

- jini.properties.template

examples/Lookup/jini/README

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/

# ==============================================================================
#
# Example of using Jini as Lookup service - registering and looking up
# an RMI Connector (IIOP/JRMP)
#
# ==============================================================================
#
# Requirements:
#
# Before running this example you will have to:
# ---------------------------------------------
#
# Get and install Jini:
#
#     http://www.jini.org/
#     http://jini.dev.java.net/
#     http://starterkit.dev.java.net/downloads/index.html
#
# This example has been implemented using the Jini Technology Starter Kit
# Version 1.2.1_002.
#
# If you wish to use an external directory for the RMI JMX Connectors
# (URLs of the form jmx:service:[rmi|iiop]:/host:port/jndi/jndi-url)
# then:
#
#   o If you wish to use rmiregistry in conjunction with the RMI/JRMP
#     JMX Connector you will have to start a rmiregistry (see below).
#
#   o If you wish to use CORBA Naming Service in conjunction with the RMI/IIOP
#     JMX Connector you will have to start an ORB daemon (see below).
#
#   o If you wish to use LDAP in conjunction with the RMI JMX Connectors
#     you will have to install/setup a directory server
#
# In order to compile and run the example, make a copy of this README file, and
# then simply cut and paste all the commands as needed into a terminal window.
#
# This README makes the assumption that you are running under Java SE 6 on Unix,
# you are familiar with Jini, the JMX technology, with LDAP and JNDI, and with
# the bourne shell or korn shell syntax.
#
# All the commands below are defined using Unix korn shell syntax.
#
# If you are not running Unix and korn shell you are expected to be able to
# adapt these commands to your favorite OS and shell environment.
#
# Update & define the following variables to match your local installation:
#
JINI_HOME=@INSTALL_HOME_FOR_JINI@

# Define the following variables:
#
JINILIB=$JINI_HOME/lib

classp=$JINILIB/jini-core.jar:$JINILIB/jini-ext.jar

# Create a jini.properties file, either from
# $JINI_HOME/example/launcher/jini12_<platform>.properties
# or from the jini.properties.template file
# provided in this example for the Unix platform.

# Replace the paths and hostnames (default is localhost) where needed in the
# jini.properties file.

# Launch Jini StartService example:
#
java -classpath $JINILIB/jini-examples.jar com.sun.jini.example.launcher.StartService &

# Load the edited jini.properties file in the launcher tool.

# Use Jini StartService example to start:
#    * RMID,
#    * WebServer,
#    * Reggie,
#    * and LookupBrowser

#-------------------------------------------------------------------------------
# Start an rmiregistry
#
rmiregistry 9999 &

#-------------------------------------------------------------------------------
# Start an ORB daemon:
#
rm -rf ./orb.db
orbd -ORBInitialPort 7777 &

#-------------------------------------------------------------------------------
# Start an LDAP Server, and create a new dc=Test suffix inside.
#
# (only needed if you wish to register the RMI or IIOP
#  stubs in LDAP, instead of using CORBA Naming Service or RMI registry)
#
# On Solaris 9 you should first login as root and execute
# the following commands:

# Setup an LDAP server (you don't need to do this if the
# server has already been configured).
#
/usr/sbin/directoryserver setup

# Start the console, and if needed create a new suffix, a database,
# and a root node (e.g. dc=Test)
#
/usr/sbin/directoryserver startconsole

# NOTE: if you're not using Solaris 9 Directory Server you will have
#       to make sure the Java Schema (RFC 2713:
#       http://www.ietf.org/rfc/rfc2713.txt) is known by that server

#-------------------------------------------------------------------------------
# Compile Server.java and Client.java
#
# * Server.java: creates an MBeanServer, creates and starts an
#                RMI connector (JRMP/IIOP)
# * Client.java: lookup a connector in Jini
#                list all MBeans.

javac -d . -classpath $classp Server.java Client.java

#-------------------------------------------------------------------------------
# LDAP parameters:

# Supply the appropriate hostname below, and define this variable:
#
ldaphost=gigondas

# Supply the appropriate port number below, and define this variable:
#
ldapport=6666

# Supply the appropriate principal below, and define this variable:
#
principal="cn=Directory Manager"

# Supply the appropriate credentials below, and define this variable:
#
credentials=

#-------------------------------------------------------------------------------
# JNDI URLs
#
jndirmi="rmi://localhost:9999"
jndiiiop="iiop://localhost:7777"
jndildap="ldap://$ldaphost:$ldapport"

#-------------------------------------------------------------------------------
# JMX Service URLs
#
jmxiiopurl="service:jmx:iiop:///jndi/${jndiiiop}/server"
jmxrmiurl="service:jmx:rmi:///jndi/${jndirmi}/server"
jmxiiopldapurl="service:jmx:iiop:///jndi/${jndildap}/cn=x,dc=Test"
jmxrmildapurl="service:jmx:rmi:///jndi/${jndildap}/cn=x,dc=Test"
jmxstuburl="service:jmx:rmi://"
jmxiorurl="service:jmx:iiop://"

#-------------------------------------------------------------------------------
# Below we illustrate the different JMX Connector Servers
# which you have the choice to start.
# There are seven cases labelled (a) to (f):
#
#   * RMI Connectors
#       + over JRMP
#           - without any external directory (a)
#           - using rmiregistry as external directory (b)
#           - using LDAP as external directory (c)
#       + over IIOP
#           - without any external directory (d)
#           - using CORBA Naming Service as external directory (e)
#           - using LDAP as external directory (f)

# NOTE-1: As defined in section 6.1 "Terminology" of the "JMX Remote API 1.0
# Specification" document, an agent is composed of one MBean Server and of
# one or more Connector Servers. There can be several agents running in one JVM.
# For flexibility of this example, the jini.Server class creates an agent which
# is composed of one MBean Server and of only one Connector Server. The class
# jini.Server decides which type of Connector Server to create depending on the
# value given to the "url" system property when you start the example.

# NOTE-2: The value of the "agent.name" system property is the value that the
# jini.Server class will give to the "AgentName" lookup attribute when it
# registers the connector's URL in the lookup service. As defined in Table 6.1
# "Lookup attributes for connectors" of the "JMX Remote API 1.0 Specification"
# document: the "AgentName" lookup attribute is a simple name used to identify
# the *AGENT* to which the connector is attached. It makes it possible to
# search, with a query to the lookup service, for all the connectors registered
# by a given agent.

# (a) You can start an agent with an RMI Connector Server over JRMP
#     without using any external directory
#
java -classpath .:$classp -Ddebug=true \
-Dagent.name=test-server-a \
-Durl="service:jmx:rmi://" \
-Djava.security.policy=java.policy \
jini.Server &

# (b) Or you can start an agent with an RMI Connector Server over JRMP
#     using rmiregistry as external directory
#     (Start rmiregistry first, if not yet started)
#
java -classpath .:$classp -Ddebug=true \
-Dagent.name=test-server-b \
-Durl="service:jmx:rmi:///jndi/${jndirmi}/server" \
-Djava.security.policy=java.policy \
jini.Server &

# (c) Or you can start an agent with an RMI Connector Server over JRMP
#     using LDAP as external directory
#     (First start an LDAP server and create the dc=Test suffix)
#
java -classpath .:$classp -Ddebug=true \
-Dagent.name=test-server-c \
-Durl="service:jmx:rmi:///jndi/${jndildap}/cn=x,dc=Test" \
-Djava.security.policy=java.policy \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jini.Server &

# (d) Or you can start an agent with an RMI Connector Server over IIOP
#     without using any external directory
#
java -classpath .:$classp -Ddebug=true \
-Dagent.name=test-server-d \
-Durl="service:jmx:iiop://" \
-Djava.security.policy=java.policy \
jini.Server &

# (e) Or you can start an agent with an RMI Connector Server over IIOP
#     using CORBA Naming Service as external directory
#     (Start ORBD first if not yet started).
#
java -classpath .:$classp -Ddebug=true \
-Dagent.name=test-server-e \
-Durl="service:jmx:iiop:///jndi/${jndiiiop}/server" \
-Djava.security.policy=java.policy \
jini.Server &

# (f) Or you can start an agent with an RMI Connector Server over IIOP
#     using LDAP as external directory
#     (First start an LDAP server and create the dc=Test suffix)
#
java -classpath .:$classp -Ddebug=true \
-Dagent.name=test-server-f \
-Durl="service:jmx:iiop:///jndi/${jndildap}/cn=x,dc=Test" \
-Djava.security.policy=java.policy \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jini.Server &

# Once you have started one or more agents, you can start the Client.
#
java -classpath .:$classp -Ddebug=true \
-Djava.security.policy=java.policy \
jini.Client

#-------------------------------------------------------------------------------

examples/Lookup/jini/Server.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package jini;

import net.jini.core.lookup.ServiceRegistrar;
import net.jini.admin.Administrable;
import net.jini.core.discovery.LookupLocator;
import net.jini.core.lookup.ServiceItem;
import net.jini.core.lookup.ServiceRegistration;
import net.jini.core.entry.Entry;
import net.jini.core.lease.Lease;
import net.jini.core.lookup.ServiceTemplate;
import net.jini.core.lookup.ServiceMatches;

import javax.management.remote.*;
import javax.management.remote.rmi.*;
import javax.management.*;

import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.ArrayList;
import java.io.IOException;
import java.net.MalformedURLException;
import java.io.Serializable;
import java.rmi.RMISecurityManager;

import javax.naming.Context;

/**
* This class demonstrates how to use Jini as a lookup service for
* JSR 160 connectors. It shows how to register a JMXConnectorServer
* with the Jini lookup service.
* <p>
* See README file and {@link #main(String[])} for more details.
* <p>
* Make sure to read the section "Binding with Lookup Services" of
* the JMX Remote API 1.0 Specification before looking at this example.
*/
public class Server {

/**
* The local MBeanServer.
*/
private final MBeanServer mbs;
private static boolean debug = false;

/**
* Constructs a Server object. Creates a new MBeanServer.
*/
public Server() {
mbs = MBeanServerFactory.createMBeanServer();
}

/**
* Creates an RMI Connector Server, starts it, and registers it
* with the Jini Lookup Service.
* <p>
* This method will transfer a fixed set of System Properties to
* the Map given to the RMIConnectorServer constructor. Some
* JNDI properties, if defined, are transfered to the Map so
* that they may be used when LDAP is used as external directory
* to register the RMI Stub (see {@link javax.management.remote.rmi}
* Javadoc). Note that even if LDAP is used as external directory
* the {@link Context#INITIAL_CONTEXT_FACTORY
*            Context.INITIAL_CONTEXT_FACTORY} and
* {@link Context#PROVIDER_URL Context.PROVIDER_URL} properties
* usually don't need to be passed.
* <p>
* The following System properties, if defined, are transfered to
* the Map given to the RMIConnectorServer constructor.
* <ul><li>{@link Context#INITIAL_CONTEXT_FACTORY
*           Context.INITIAL_CONTEXT_FACTORY}</li>
*     <li>{@link Context#PROVIDER_URL
*           Context.PROVIDER_URL}</li>
*     <li>{@link Context#SECURITY_PRINCIPAL
*           Context.SECURITY_PRINCIPAL}</li>
*     <li>{@link Context#SECURITY_CREDENTIALS
*           Context.SECURITY_CREDENTIALS}</li>
*     <li>{@link RMIConnectorServer#JNDI_REBIND_ATTRIBUTE
*           RMIConnectorServer.JNDI_REBIND_ATTRIBUTE} - default
*           is <code>true</code>.</li>
* </ul>
*
* @param url A string representation of the JMXServiceURL.
*
* @return the created RMIConnectorServer.
*/
public JMXConnectorServer rmi(String url)
throws IOException, JMException, ClassNotFoundException {

// Make a JMXServiceURL from the url string.
//
JMXServiceURL jurl = new JMXServiceURL(url);

// Prepare the environment Map
//
final HashMap env = new HashMap();
final String rprop = RMIConnectorServer.JNDI_REBIND_ATTRIBUTE;
final String rebind=System.getProperty(rprop,"true");
final String factory =
System.getProperty(Context.INITIAL_CONTEXT_FACTORY);
final String ldapServerUrl =
System.getProperty(Context.PROVIDER_URL);
final String ldapUser =
System.getProperty(Context.SECURITY_PRINCIPAL);
final String ldapPasswd =
System.getProperty(Context.SECURITY_CREDENTIALS);

// Transfer some system properties to the Map
//
if (factory!= null) // this should not be needed
env.put(Context.INITIAL_CONTEXT_FACTORY,factory);
if (ldapServerUrl!=null) // this should not be needed
env.put(Context.PROVIDER_URL, ldapServerUrl);
if (ldapUser!=null) // this is needed when LDAP is used
env.put(Context.SECURITY_PRINCIPAL, ldapUser);
if (ldapPasswd != null) // this is needed when LDAP is used
env.put(Context.SECURITY_CREDENTIALS, ldapPasswd);
env.put(rprop,rebind); // default is true.

// Create an RMIConnectorServer
//
System.out.println("Creating RMI Connector: " + jurl);
JMXConnectorServer rmis =
JMXConnectorServerFactory.newJMXConnectorServer(jurl, env, mbs);

// Get the AgentName for registering the Connector in the Lookup Service
//
final String agentName = System.getProperty("agent.name",
"DefaultAgent");

// Start the connector and register it with Jini Lookup Service.
//
start(rmis,env,agentName);

return rmis;
}

/**
* Start a JMXConnectorServer and register it with Jini Lookup Service.
*
* @param server the JMXConnectorServer to start and register.
* @param env   the environment Map.
* @param agentName the AgentName with which the proxy must be registered
*                  in the Jini Lookup Service.
*/
public void start(JMXConnectorServer server, Map env, String agentName)
throws IOException, ClassNotFoundException {

// Start the JMXConnectorServer
//
server.start();

// Get a pointer to Jini Lookup Service
//
final ServiceRegistrar registrar = getRegistrar();

// Create a JMXConnector proxy to register with Jini
//
final JMXConnector proxy = server.toJMXConnector(env);

// Register the proxy with Jini Lookup Service.
//
register(registrar,proxy,agentName);
}

/**
* Get a pointer to the Jini Lookup Service.
* (See Jini documentation for more info).
* <p>
* The Jini Lookup Service URL is determined as follows:
* <p>
* If the System property <code>"jini.lookup.url"</code> is provided,
* its value is the Jini Lookup Service URL.
* <p>
* Otherwise, the default URL is assumed to be
* <code>"jini://localhost"</code>
* @return a pointer to the Jini Lookup Service.
*/
public static ServiceRegistrar getRegistrar()
throws IOException, ClassNotFoundException, MalformedURLException {
final String jurl =
System.getProperty("jini.lookup.url","jini://localhost");
final LookupLocator lookup = new LookupLocator(jurl);
final ServiceRegistrar registrar = lookup.getRegistrar();
if (registrar instanceof Administrable)
debug("Registry is administrable.");
return registrar;
}

/**
* Register a JMXConnector proxy with the Jini Lookup Service.
*
* @param registrar A pointer to the Jini Lookup Service, as returned
*                  by {@link #getRegistrar()}.
* @param proxy     A JMXConnector server proxy, that should have
*                  been obtained from
*                  {@link JMXConnectorServer#toJMXConnector(Map)
*                  JMXConnectorServer.toJMXConnector(Map)};
* @param name      The AgentName with which the proxy must be registered
*                  in the Jini Lookup Service.
*
* @return The ServiceRegistration object returned by the Jini Lookup
*         Service.
*/
public static ServiceRegistration register(ServiceRegistrar registrar,
JMXConnector proxy, String name)
throws IOException {

// Prepare Service's attributes entry
//
Entry[] serviceAttrs = new Entry[] {
new net.jini.lookup.entry.Name(name)
// Add here the lookup attributes you want to specify.
};

System.out.println("Registering proxy:  AgentName=" +  name );
debug("\t\t" + proxy);

// Create a ServiceItem from the service instance
//
ServiceItem srvcItem = new ServiceItem(null, proxy, serviceAttrs);

// Register the Service with the Lookup Service
//
ServiceRegistration srvcRegistration =
registrar.register(srvcItem, Lease.ANY);
debug("Registered ServiceID:  " +
srvcRegistration.getServiceID().toString());
return srvcRegistration;
}

/**
* Trace a debug message.
*/
private static void debug(String msg) {
if (debug) System.out.println(msg);
}

/**
* Program Main
* <p>
* Creates a server object, gets the JMX Service URL, and calls
* the method that will create and register the appropriate
* JMX Connector Server for that URL.
* <p>
* You may wish to use the following properties on the Java command line:
* <ul>
* <li><code>-Durl=&lt;jmxServiceURL&gt;</code>: specifies the URL of
*     the JMX Connector Server you wish to use. See README file for more
*     details</li>
* <li><code>-Dagent.name=&lt;AgentName&gt;</code>: specifies an
*     AgentName to register with.</li>
* <li><code>-Djini.lookup.url=&lt;jini-url&gt;</code>:
*     the Jini Lookup Service URL (default is "jini://localhost"),
*     see {@link #getRegistrar()}.</li>
* <li><code>-Ddebug="true|false"</code>: switch the Server debug flag
*     on/off (default is "false").</li>
* </ul>
*/
public static void main(String[] args) {
try {
// Jini requires a security manager.
//
if (System.getSecurityManager() == null)
System.setSecurityManager(new RMISecurityManager());

// Get the value of the debug flag.
//
debug = (Boolean.valueOf(System.getProperty("debug","false"))).
booleanValue();

// Create a new Server object.
//
final Server s = new Server();

// Get the JMXConnector URL
//
final String url = System.getProperty("url", "service:jmx:rmi://");

// Build a JMXServiceURL
//
final JMXServiceURL jurl = new JMXServiceURL(url);

// Creates a JMX Connector Server
//
debug("Creating Connector: " + jurl);
final String p = jurl.getProtocol();
if (p.equals("rmi"))         // Create an RMI Connector
s.rmi(url);
else if (p.equals("iiop"))   // Create an RMI/IIOP Connector
s.rmi(url);
else                         // Unsupported protocol
throw new MalformedURLException("Unsupported protocol: " + p);

System.out.println("\nService URL successfully registered " +
"in the Jini Lookup Service");

} catch (Exception x) {
// Something went wrong somewhere....
//
System.err.println("Unexpected exception caught in main: " + x);
x.printStackTrace(System.err);
}
}
}

examples/Lookup/jini/Client.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package jini;

import net.jini.core.lookup.ServiceRegistrar;
import net.jini.admin.Administrable;
import net.jini.core.discovery.LookupLocator;
import net.jini.core.lookup.ServiceItem;
import net.jini.core.lookup.ServiceRegistration;
import net.jini.core.entry.Entry;
import net.jini.core.lease.Lease;
import net.jini.core.lookup.ServiceTemplate;
import net.jini.core.lookup.ServiceMatches;

import javax.management.remote.*;
import javax.management.*;

import java.net.MalformedURLException;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.Iterator;
import java.io.IOException;
import java.io.Serializable;
import java.rmi.RMISecurityManager;

/**
* This class demonstrates how to use Jini as a lookup service for
* JSR 160 connectors. It shows how to lookup a JMXConnector from
* the Jini lookup service.
* <p>
* See README file and {@link #main(String[])} for more details.
* <p>
* Make sure to read the section "Binding with Lookup Services" of
* the JMX Remote API 1.0 Specification before looking at this example.
*/
public class Client {

private static boolean debug = false;

/**
* Get a pointer to the Jini Lookup Service.
* (See Jini documentation for more info).
* <p>
* The Jini Lookup Service URL is determined as follows:
* <p>
* If the System property <code>"jini.lookup.url"</code> is provided,
* its value is the Jini Lookup Service URL.
* <p>
* Otherwise, the default URL is assumed to be
* <code>"jini://localhost"</code>
*
* @return a pointer to the Jini Lookup Service.
*/
public static ServiceRegistrar getRegistrar()
throws IOException, ClassNotFoundException, MalformedURLException {
final String jurl =
System.getProperty("jini.lookup.url","jini://localhost");
final LookupLocator lookup = new LookupLocator(jurl);
final ServiceRegistrar registrar = lookup.getRegistrar();
if (registrar instanceof Administrable)
debug("Registry is administrable.");
return registrar;
}

/**
* Lookup JMXConnectors in the Jini Lookup Service.
*
* @param registrar A pointer to the Jini Lookup Service,
*        returned by {@link #getRegistrar()}.
* @param name the AgentName of the JMXConnectors that should
*        be returned. If <var>name</var> is null, then
*        the JMXConnectors for all agents are returned
*        (null is an equivalent for a wildcard).
* @return The list of matching JMXConnectors retrieved from
*         the Jini Lookup Service.
*/
public static List lookup(ServiceRegistrar registrar,
String name) throws IOException {
final ArrayList list = new ArrayList();

// Returns only JMXConnectors. The filter could be made
// more strict by suplying e.g. RMIConnector.class
// (would only return RMIConnectors).
//
final Class[] classes = new Class[] {JMXConnector.class};

// Will return only those services for which the Name
// attribute was registered. Since JSR 160 specifies that
// the Name attribute is mandatory, this makes it possible
// to filter out all the services that do not conform
// to the spec.
// If <name> is null, then all services for which the
// Name attribute was specified will match, regardless of
// the value of that attribute. Otherwise, only those services
// for which Name matches the specified name will be returned.
//
final Entry[] serviceAttrs = new Entry[] {
// Add here the matching attributes.
new net.jini.lookup.entry.Name(name)
};

// Create a ServiceTemplate to do the matching.
//
ServiceTemplate template =
new ServiceTemplate(null,classes,serviceAttrs);

// Lookup all matching services in the Jini Lookup Service.
//
ServiceMatches matches =
registrar.lookup(template, Integer.MAX_VALUE);

// Retrieve the matching JMX Connectors.
//
for (int i = 0; i < matches.totalMatches; i++) {

debug("Found Service: " + matches.items[i].serviceID);
if (debug) {
// List the lookup attributes that where registered
// for that service.
if (matches.items[i].attributeSets != null) {
final Entry[] attrs = matches.items[i].attributeSets;
for (int j = 0; j < attrs.length ; j++) {
debug("\tAttribute["+j+"]=" + attrs[j]);
}
}
}

if (matches.items[i].service != null) {
// Service could be null if it can't be deserialized, because
// e.g. the class was not found.
// This will not happen with JSR 160 mandatory connectors
// however.

// Get the JMXConnector.
//
JMXConnector c = (JMXConnector)(matches.items[i].service);
debug("Found a JMXConnector: " + c);

// Add the connector to the result list.
list.add(c);
}
}
return list;
}

/**
* List all MBeans and their attributes.
*/
public static void listMBeans(MBeanServerConnection server)
throws IOException {

final Set names = server.queryNames(null,null);
for (final Iterator i=names.iterator(); i.hasNext(); ) {
ObjectName name = (ObjectName)i.next();
System.out.println("Got MBean: "+name);
try {
MBeanInfo info =
server.getMBeanInfo((ObjectName)name);
MBeanAttributeInfo[] attrs = info.getAttributes();
if (attrs == null) continue;
for (int j=0; j<attrs.length; j++) {
if (attrs[j].isReadable()) {
try {
Object o =
server.getAttribute(name,attrs[j].getName());
System.out.println("\t\t" + attrs[j].getName() +
" = "+o);
} catch (Exception x) {
System.err.println("JmxClient failed to get " +
attrs[j].getName());
x.printStackTrace(System.err);
}
}
}
} catch (Exception x) {
System.err.println("JmxClient failed to get MBeanInfo: "  + x);
x.printStackTrace(System.err);
}
}
}

/**
* Trace a debug message.
*/
private static void debug(String msg) {
if (debug) System.out.println(msg);
}

/**
* Program Main
* <p>
* Lookup all JMX agents in the Jini Lookup Service and list
* their MBeans and attributes.
* <p>
* You may wish to use the following properties on the Java command line:
* <ul>
* <li><code>-Dagent.name=&lt;AgentName&gt;</code>: specifies an
*     AgentName to lookup (default is null, meaning any agent).</li>
* <li><code>-Djini.lookup.url=&lt;jini-url&gt;</code>:
*     the Jini Lookup Service URL (default is "jini://localhost"),
*     see {@link #getRegistrar()}.</li>
* <li><code>-Ddebug="true|false"</code>: switch the Client debug flag
*     on/off (default is "false").</li>
* </ul>
*/
public static void main(String[] args) {
try {
// Jini requires a security manager.
//
if (System.getSecurityManager() == null)
System.setSecurityManager(new RMISecurityManager());

// Get the value of the debug flag.
//
debug = (Boolean.valueOf(System.getProperty("debug","false"))).
booleanValue();

// Get AgentName to lookup. If not defined, all agents
// are looked up.
//
final String agentName = System.getProperty("agent.name");

// Get a pointer to the Jini Lookup Service.
//
final ServiceRegistrar registrar = getRegistrar();
debug("registrar is: " + registrar);

// Lookup all matching agents in the Jini Lookup Service.
//
List l = lookup(registrar,agentName);

// Attempt to connect to retrieved agents
//
System.out.println("Number of agents found : " + l.size());
int j = 1;
for (Iterator i=l.iterator();i.hasNext();j++) {
JMXConnector c1 = (JMXConnector) i.next();
if (c1 != null) {

// Connect
//
System.out.println(
"----------------------------------------------------");
System.out.println("\tConnecting to agent number "+j);
System.out.println(
"----------------------------------------------------");
debug("JMXConnector is: " + c1);

try {
c1.connect(null);
} catch (IOException x) {
System.err.println("Connection failed: " + x);
if (debug) x.printStackTrace(System.err);
continue;
}

// Get MBeanServerConnection
//
MBeanServerConnection conn =
c1.getMBeanServerConnection();
debug("Connection is:" + conn);
System.out.println("Server domain is: " +
conn.getDefaultDomain());

// List all MBeans
//
try {
listMBeans(conn);
} catch (IOException x) {
System.err.println("Failed to list MBeans: " + x);
if (debug) x.printStackTrace(System.err);
}

// Close connector
//
try {
c1.close();
} catch (IOException x) {
System.err.println("Failed to close connection: " + x);
if (debug) x.printStackTrace(System.err);
}
}
}
} catch (Exception x) {
System.err.println("Unexpected exception caught in main: " + x);
x.printStackTrace(System.err);
}
}
}

examples/Lookup/jini/java.policy

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/

/* A minimal security policy file for the browser. */
grant {
// needed by the GUI

// permission java.awt.AWTPermission "showWindowWithoutWarningBanner";
// permission java.awt.AWTPermission "accessEventQueue";

// needed by both the GUI and LookupDiscovery

permission java.lang.RuntimePermission "modifyThreadGroup";
permission java.lang.RuntimePermission "modifyThread";

// needed by LookupDiscovery

permission java.util.PropertyPermission "net.jini.discovery.*", "read";
permission java.util.PropertyPermission "jini.*", "read";
// multicast request address
// permission java.net.SocketPermission "224.0.1.85", "connect,accept";
// multicast announcement address
permission java.net.SocketPermission "224.0.1.84", "connect,accept";

// needed by both LookupDiscovery and the GUI

permission net.jini.discovery.DiscoveryPermission "*";
// unicast discovery, http: downloading, RMI
permission java.net.SocketPermission "*:1024-", "connect,accept";
// http: codebases
permission java.net.SocketPermission "*:80", "connect";
// ldap: codebases
permission java.net.SocketPermission "*:389", "connect";
// ldaps: codebases
permission java.net.SocketPermission "*:636", "connect";
// delete this one if you don't need to accept file: codebases
permission java.io.FilePermission "<<ALL FILES>>", "read";

// needed to allow the lookup proxy to perform debug duties
// (ex. display stack trace when unmarshal failures occur)

permission java.util.PropertyPermission "com.sun.jini.reggie.*", "read";
permission javax.management.MBeanServerPermission "*";
permission java.util.PropertyPermission "*", "read";
permission javax.management.MBeanPermission "*", "*";
permission javax.management.MBeanTrustPermission "*";
permission java.lang.RuntimePermission "*";
permission javax.security.auth.AuthPermission "doAsPrivileged";
};

21 Java Naming and Directory Interface (JNDI)/LDAP検索サービス

JMX APIは既存の検索テクノロジを使用した、検索サービスの3つのバインディングを定義しています。この例では、JNDI/LDAP検索サービスの次のような実装例が用意されています。

- README file

- Server

- Client

- jmx-schema.txt

- 60jmx-schema.ldif

examples/Lookup/ldap/README

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
#

# ==============================================================================
#
# Example of using JNDI/LDAP as Lookup service - registering and looking up
# an RMI Connector (IIOP/JRMP)
#
# ==============================================================================
#
# Requirements:
#
# Before running this example you will have to:
# ---------------------------------------------
#
# * Get access (or install & start) an LDAP directory server that
#   will implement the lookup service.
# * Make sure the Java Schema (RFC 2713: http://www.ietf.org/rfc/rfc2713.txt)
#   is known by that server
# * Update the directory server with JSR 160 LDAP Schema
#   - 60jmx-schema.ldif file provided
#   This ldif file corresponds to the schema described in jmx-schema.txt
#   and can be copied as is in the config/schema directory of
#   the Sun ONE Directory Server.
# * Make sure you have write access to the server so that you can
#   create contexts in which the server will register its URL.
#
# The names used in this example make the assumption that you
# have created a new suffix, a database, and a root node (e.g. dc=Test)
# for the purpose of the example. You may however use any names / location
# you want - just make sure to provide the correct names & URLs
# when starting the Server and Client examples.
#
# In addition, if you wish to use an external directory for the  RMI JMX
# Connectors (URLs of the form jmx:service:[rmi|iiop]:/host:port/jndi/jndi-url)
# then:
#
#   o If you wish to use rmiregistry in conjunction with the RMI/JRMP
#     JMX Connector you will have to start a rmiregistry (see below).
#
#   o If you wish to use CORBA Naming Service in conjunction with the RMI/IIOP
#     JMX Connector you will have to start an ORB daemon (see below).
#
#   o If you wish to use LDAP in conjunction with the RMI JMX Connectors
#     you will have to install/setup a directory server (you can use the
#     same server than that used for Lookup, or another one)
#
# In order to compile and run the example, make a copy of this README file, and
# then simply cut and paste all the commands as needed into a terminal window.
#
# This README makes the assumption that you are running under Java SE 6 on Unix,
# you are familiar with the JMX technology, with LDAP and JNDI, and with
# the bourne shell or korn shell syntax.
#
# All the commands below are defined using Unix korn shell syntax.
#
# If you are not running Unix and korn shell you are expected to be able to
# adapt these commands to your favorite OS and shell environment.
#

#-------------------------------------------------------------------------------
# The directory server must be started first.
# On Solaris 9 you should first login as root and execute
# the following commands:

# Setup an LDAP server (you don't need to do this if the
# server has already been configured).
#
/usr/sbin/directoryserver setup

# Stop the server, copy the jmx schema, start the server
#
/usr/sbin/directoryserver stop
cp 60jmx-schema.ldif /var/ds5/slapd-<hostname>/config/schema
/usr/sbin/directoryserver start

# Start the console, and if needed create a new suffix, a database,
# and a root node (e.g. dc=Test)
#
/usr/sbin/directoryserver startconsole

# NOTE: if you're not using Solaris 9 Directory Server you will have
#       to make sure the Java Schema (RFC 2713:
#       http://www.ietf.org/rfc/rfc2713.txt) is known by that server

#-------------------------------------------------------------------------------
# Start an rmiregistry
#
rmiregistry 9999 &

#-------------------------------------------------------------------------------
# Start an ORB daemon:
#
rm -rf ./orb.db
orbd -ORBInitialPort 7777 &

#-------------------------------------------------------------------------------
# Compile Server.java and Client.java
#
# * Server.java: creates an MBeanServer, creates and starts an
#                RMI connector (JRMP/IIOP)
# * Client.java: lookup a connector in JNDI
#                list all MBeans.

javac -d . Server.java Client.java

#-------------------------------------------------------------------------------
# LDAP parameters:
#

# Supply the appropriate hostname below, and define this variable:
#
ldaphost=gigondas

# Supply the appropriate port number below, and define this variable:
#
ldapport=6666

# Supply the appropriate principal below, and define this variable:
#
principal="cn=Directory Manager"

# Supply the appropriate credentials below, and define this variable:
#
credentials=

# Supply the appropriate root under which the Server will try
# to register its URL...
#
provider="ldap://$ldaphost:$ldapport/dc=Test"

#-------------------------------------------------------------------------------
# JNDI URLs
#
jndirmi="rmi://localhost:9999"
jndiiiop="iiop://localhost:7777"
jndildap="ldap://$ldaphost:$ldapport"

#-------------------------------------------------------------------------------
# JMX Service URLs
#
jmxiiopurl="service:jmx:iiop:///jndi/${jndiiiop}/server"
jmxrmiurl="service:jmx:rmi:///jndi/${jndirmi}/server"
jmxiiopldapurl="service:jmx:iiop:///jndi/${jndildap}/cn=x,dc=Test"
jmxrmildapurl="service:jmx:rmi:///jndi/${jndildap}/cn=x,dc=Test"
jmxstuburl="service:jmx:rmi://"
jmxiorurl="service:jmx:iiop://"

#-------------------------------------------------------------------------------
# Below we illustrate the different JMX Connector Servers
# which you have the choice to start.
# There are seven cases labelled (a) to (f):
#
#   * RMI Connectors
#       + over JRMP
#           - without any external directory (a)
#           - using rmiregistry as external directory (b)
#           - using LDAP as external directory (c)
#       + over IIOP
#           - without any external directory (d)
#           - using CORBA Naming Service as external directory (e)
#           - using LDAP as external directory (f)

# NOTE-1: As defined in section 6.1 "Terminology" of the "JMX Remote API 1.0
# Specification" document, an agent is composed of one MBean Server and of
# one or more Connector Servers. There can be several agents running in one JVM.
# For flexibility of this example, the jndi.Server class creates an agent which
# is composed of one MBean Server and of only one Connector Server. The class
# jndi.Server decides which type of Connector Server to create depending on the
# value given to the "url" system property when you start the example.

# NOTE-2: The value of the "agent.name" system property is the value that the
# jndi.Server class will give to the "AgentName" lookup attribute when it
# registers the connector's URL in the lookup service. As defined in Table 6.1
# "Lookup attributes for connectors" of the "JMX Remote API 1.0 Specification"
# document: the "AgentName" lookup attribute is a simple name used to identify
# the *AGENT* to which the connector is attached. It makes it possible to
# search, with a query to the lookup service, for all the connectors registered
# by a given agent.

# (a) You can start an agent with an RMI Connector Server over JRMP
#     without using any external directory
#
java -classpath . -Ddebug=true \
-Dagent.name=test-server-a \
-Durl="service:jmx:rmi://" \
-Djava.naming.provider.url="$provider" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jndi.Server &

# (b) Or you can start an agent with an RMI Connector Server over JRMP
#     using rmiregistry as external directory
#     (Start rmiregistry first, if not yet started)
#
java -classpath . -Ddebug=true \
-Dagent.name=test-server-b \
-Durl="service:jmx:rmi:///jndi/${jndirmi}/server" \
-Djava.naming.provider.url="$provider" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jndi.Server &

# (c) Or you can start an agent with an RMI Connector Server over JRMP
#     using LDAP as external directory
#     (First start an LDAP server and create the dc=Test suffix)
#
java -classpath . -Ddebug=true \
-Dagent.name=test-server-c \
-Durl="service:jmx:rmi:///jndi/${jndildap}/cn=x,dc=Test" \
-Djava.naming.provider.url="$provider" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jndi.Server &

# (d) Or you can start an agent with an RMI Connector Server over IIOP
#     without using any external directory
#
java -classpath . -Ddebug=true \
-Dagent.name=test-server-d \
-Durl="service:jmx:iiop://" \
-Djava.naming.provider.url="$provider" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jndi.Server &

# (e) Or you can start an agent with an RMI Connector Server over IIOP
#     using CORBA Naming Service as external directory
#     (Start ORBD first if not yet started).
#
java -classpath . -Ddebug=true \
-Dagent.name=test-server-e \
-Durl="service:jmx:iiop:///jndi/${jndiiiop}/server" \
-Djava.naming.provider.url="$provider" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jndi.Server &

# (f) Or you can start an agent with an RMI Connector Server over IIOP
#     using LDAP as external directory
#     (First start an LDAP server and create the dc=Test suffix)
#
java -classpath . -Ddebug=true \
-Dagent.name=test-server-f \
-Durl="service:jmx:iiop:///jndi/${jndildap}/cn=x,dc=Test" \
-Djava.naming.provider.url="$provider" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jndi.Server &

# Once you have started one or more agents, you can start the Client.
#
java -classpath . -Ddebug=true \
-Djava.naming.provider.url="$provider" \
-Djava.naming.security.principal="$principal" \
-Djava.naming.security.credentials="$credentials" \
jndi.Client

#-------------------------------------------------------------------------------

examples/Lookup/ldap/Server.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package jndi;

import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;

import javax.naming.directory.DirContext;
import javax.naming.directory.Attribute;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchResult;
import javax.naming.directory.SearchControls;

import javax.naming.ldap.InitialLdapContext;

import javax.management.*;
import javax.management.remote.*;
import javax.management.remote.rmi.*;

import java.text.SimpleDateFormat;

import java.util.Date;
import java.util.Map;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Vector;
import java.io.IOException;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.MalformedURLException;

/**
* This class demonstrates how to use an LDAP directory as a lookup
* service for JSR 160 connectors. It shows how to register a
* JMXConnectorServer with the LDAP directory through JNDI.
* <p>
* See README file and {@link #main(String[])} for more details.
* <p>
* Make sure to read the section "Binding with Lookup Services" of
* the JMX Remote API 1.0 Specification before looking at this example.
*/
public class Server {

// The URL will remain registered for 60 secs.
//
public final static int JMX_DEFAULT_LEASE = 60;

private static boolean debug = false;

/**
* The local MBeanServer.
*/
private final MBeanServer mbs;

/**
* Constructs a Server object. Creates a new MBeanServer.
*/
public Server() {
mbs = MBeanServerFactory.createMBeanServer();
}

/**
* Get a pointer to the root context of the directory tree
* under which this server is supposed to register itself.
* All LDAP DNs will be considered to be relative to that root.
* <p>
* Note that this root is not part of the JSR 160 specification,
* since the actual location where a JMX Agent will register
* its connectors is left completely open by the specification.
* The specification only discuss what the JMX Agent must/may
* put in the directory - but not where.
* <p>
* This method assumes that the root of the directory is
* will be passed in a the {@link Context#PROVIDER_URL
* Context.PROVIDER_URL} System property.
* <p>
* This method will transfer a fixed set of System Properties to
* the Hashtable given to the JNDI InitialContext:
* <ul><li>{@link Context#INITIAL_CONTEXT_FACTORY
*           Context.INITIAL_CONTEXT_FACTORY} - default is
*         <code>"com.sun.jndi.ldap.LdapCtxFactory"</code></li>
*     <li>{@link Context#PROVIDER_URL
*           Context.PROVIDER_URL}</li>
*     <li>{@link Context#SECURITY_PRINCIPAL
*           Context.SECURITY_PRINCIPAL} - default is
*         <code>"cn=Directory Manager"</code></li>
*     <li>{@link Context#SECURITY_CREDENTIALS
*           Context.SECURITY_CREDENTIALS}</li>
* </ul>
*
* @return a pointer to the LDAP Directory.
*/
public static DirContext getRootContext() throws NamingException {
// Prepare environment
//
final Hashtable env = new Hashtable();

// The Initial Context Factory must be provided, and
// must point to an LDAP Context Factory
//
final String factory =
System.getProperty(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");

// The LDAP Provider URL must be provided, and
// must point to a running LDAP directory server
//
final String ldapServerUrl =
System.getProperty(Context.PROVIDER_URL);

// The LDAP user must be provided, and
// must have write access to the subpart of the directory
// where the agent will be registered.
//
final String ldapUser =
System.getProperty(Context.SECURITY_PRINCIPAL,
"cn=Directory Manager");

// Credentials must be provided, so that the user may
// write to the directory.
//
final String ldapPasswd =
System.getProperty(Context.SECURITY_CREDENTIALS);

// Debug info: print provided values:
//
debug(Context.PROVIDER_URL + "=" + ldapServerUrl);
debug(Context.SECURITY_PRINCIPAL + "=" + ldapUser);
if (debug) {
System.out.print(Context.SECURITY_CREDENTIALS + "=");
final int len = (ldapPasswd==null)?0:ldapPasswd.length();
for (int i=0;i<len;i++) System.out.print("*");
System.out.println();
}

// Put provided value in the environment table.
//
env.put(Context.INITIAL_CONTEXT_FACTORY,factory);
env.put(Context.SECURITY_PRINCIPAL, ldapUser);
if (ldapServerUrl != null)
env.put(Context.PROVIDER_URL, ldapServerUrl);
if (ldapPasswd != null)
env.put(Context.SECURITY_CREDENTIALS, ldapPasswd);

// Create initial context
//
InitialContext root = new InitialLdapContext(env,null);

// Now return the root directory context.
//
return (DirContext)(root.lookup(""));
}

/**
* Registers a JMX Connector URL with the LDAP directory.
* <p>
* This method expects to find the LDAP DN where it will register
* the JMX Connector URL in the "dn" System property. If that
* property is not set, then "cn=<var>name</var>" is assumed.
* <p>
* If the given DN does not point to an existing node in the
* directory, then this method will attempt to create it. Yet,
* the parent node must already exist in that case.
* <p>
* If the DN points to a node that is already of the <var>jmxConnector</var>
* class, then this method will simply override its <var>jmxServiceURL</var>
* ,<var>jmxAgentName</var>, <var>jmxProtocolType</var>,
* <var>jmxAgentHost</var> and <var>jmxExpirationDate</var> attributes.
*
* @param root      A pointer to the root context we are using,
*                  as returned by {@link #getRootContext()}.
* @param jmxUrl    A JMX Connector Server URL, that should have
*                  been obtained from
*                  {@link JMXConnectorServer#getAddress()
*                  JMXConnectorServer.getAddress()};
* @param name      The AgentName with which the URL must be registered
*                  in the LDAP directory.
*/
public static void register(DirContext root,
JMXServiceURL jmxUrl,
String name)
throws NamingException, IOException {

// Get the LDAP DN where to register
//
final String mydn = System.getProperty("dn","cn="+name);

debug("dn: " + mydn );

// First check whether <mydn> already exists
//
Object o = null;
try {
o = root.lookup(mydn);
// There is already a node at <mydn>
//
} catch (NameNotFoundException n) {
// <mydn> does not exist! attempt to create it.
//

// Prepare attributes for creating a javaContainer
// with the auxiliary class jmxConnector.
//
Attributes attrs = new BasicAttributes();

// Prepare objectClass attribute: we're going to create
// a javaContainer with the jmxConnector auxiliary class.
//
Attribute objclass = new BasicAttribute("objectClass");
objclass.add("top");
objclass.add("javaContainer");
objclass.add("jmxConnector");
attrs.put(objclass);
attrs.put("jmxAgentName", name);
o = root.createSubcontext(mydn,attrs);
}

// That's not supposed to happen but who knows...
//
if (o == null) throw new NameNotFoundException();

// Check that the entry contains the jmxConnector objectClass
// before modifying the attributes.
//
final Attributes attrs = root.getAttributes(mydn);
final Attribute oc = attrs.get("objectClass");
if (!oc.contains("jmxConnector")) {
// The node does not have the jmxConnector class.
//
final String msg = "The supplied node [" + mydn + "] does not " +
"contain the jmxConnector objectclass";
throw new NamingException(msg);
}

// Now need to replace jmxConnector attributes.
//
final Attributes newattrs = new BasicAttributes();
newattrs.put("jmxAgentName",name);
newattrs.put("jmxServiceURL",jmxUrl.toString());
newattrs.put("jmxAgentHost",InetAddress.getLocalHost().getHostName());
newattrs.put("jmxProtocolType",jmxUrl.getProtocol());
newattrs.put("jmxExpirationDate",
getExpirationDate(JMX_DEFAULT_LEASE));
root.modifyAttributes(mydn,DirContext.REPLACE_ATTRIBUTE,newattrs);
}

/**
* Creates an RMI Connector Server, starts it, and registers it
* with the LDAP directory.
* <p>
* This method will transfer a fixed set of System Properties to
* the Map given to the RMIConnectorServer constructor. Some
* JNDI properties, if defined, are transfered to the Map so
* that they may be used when LDAP is used as external directory
* to register the RMI Stub (see {@link javax.management.remote.rmi}
* Javadoc). Note that even if LDAP is used as external directory
* the {@link Context#INITIAL_CONTEXT_FACTORY
*            Context.INITIAL_CONTEXT_FACTORY} and
* {@link Context#PROVIDER_URL Context.PROVIDER_URL} properties
* usually don't need to be passed.
* <p>
* The following System properties, if defined, are transfered to
* the Map given to the RMIConnectorServer constructor.
* <ul><li>{@link Context#INITIAL_CONTEXT_FACTORY
*           Context.INITIAL_CONTEXT_FACTORY}</li>
*     <li>{@link Context#PROVIDER_URL
*           Context.PROVIDER_URL}</li>
*     <li>{@link Context#SECURITY_PRINCIPAL
*           Context.SECURITY_PRINCIPAL}</li>
*     <li>{@link Context#SECURITY_CREDENTIALS
*           Context.SECURITY_CREDENTIALS}</li>
*     <li>{@link RMIConnectorServer#JNDI_REBIND_ATTRIBUTE
*           RMIConnectorServer.JNDI_REBIND_ATTRIBUTE} - default
*           is <code>true</code>.</li>
* </ul>
*
* @param url A string representation of the JMXServiceURL.
* @return the created RMIConnectorServer.
*/
public JMXConnectorServer rmi(String url)
throws IOException, JMException,
NamingException, ClassNotFoundException {

// Make a JMXServiceURL from the url string.
//
JMXServiceURL jurl = new JMXServiceURL(url);

// Prepare the environment Map
//
final HashMap env = new HashMap();
final String rprop = RMIConnectorServer.JNDI_REBIND_ATTRIBUTE;
final String rebind=System.getProperty(rprop,"true");
final String factory =
System.getProperty(Context.INITIAL_CONTEXT_FACTORY);
final String ldapServerUrl =
System.getProperty(Context.PROVIDER_URL);
final String ldapUser =
System.getProperty(Context.SECURITY_PRINCIPAL);
final String ldapPasswd =
System.getProperty(Context.SECURITY_CREDENTIALS);

// Transfer some system properties to the Map
//
if (factory!= null) // this should not be needed
env.put(Context.INITIAL_CONTEXT_FACTORY,factory);
if (ldapServerUrl!=null) // this should not be needed
env.put(Context.PROVIDER_URL, ldapServerUrl);
if (ldapUser!=null) // this is needed when LDAP is used
env.put(Context.SECURITY_PRINCIPAL, ldapUser);
if (ldapPasswd != null) // this is needed when LDAP is used
env.put(Context.SECURITY_CREDENTIALS, ldapPasswd);
env.put(rprop,rebind); // default is true.

// Create an RMIConnectorServer
//
System.out.println("Creating RMI Connector: " + jurl);
JMXConnectorServer rmis =
JMXConnectorServerFactory.newJMXConnectorServer(jurl, env, mbs);

// Get the AgentName for registering the Connector in the Lookup Service
//
final String agentName = System.getProperty("agent.name",
"DefaultAgent");

// Start the connector and register it in the LDAP directory.
//
start(rmis,env,agentName);

return rmis;
}

/**
* Start a JMXConnectorServer and register it with the LDAP directory.
*
* @param server the JMXConnectorServer to start and register.
* @param env   the environment Map.
* @param agentName the AgentName with which the URL must be registered
*                  in the LDAP Directory. This is not a LDAP DN, but
*                  the value of the jmxAgentName attribute.
*/
public void start(JMXConnectorServer server, Map env, String agentName)
throws IOException, NamingException {

// Start the JMXConnectorServer
//
server.start();

// Get a pointer to the LDAP directory.
//
final DirContext root = getRootContext();

// Create a JMX Service URL to register in the LDAP directory
//
final JMXServiceURL address = server.getAddress();

// Register the URL in the LDAP directory
//
register(root,address,agentName);
}

/**
* Returns a X.208 string representing the GMT date at now + sec.
*
* @param sec Number of seconds from now.
* @return an X.208 GMT GeneralizedTime (ending with Z).
*/
public static String getExpirationDate(long sec) {
final SimpleDateFormat fmt =  new SimpleDateFormat("yyyyMMddHHmmss.S");
final Date date = new Date();
final Date gmtDate;
if (fmt.getCalendar().getTimeZone().inDaylightTime(date))
gmtDate = new Date(System.currentTimeMillis() -
fmt.getCalendar().getTimeZone().getRawOffset() -
fmt.getCalendar().getTimeZone().getDSTSavings() +
1000*sec);
else
gmtDate =
new Date(System.currentTimeMillis() -
fmt.getCalendar().getTimeZone().getRawOffset() +
1000*sec);
return ((fmt.format(gmtDate))+"Z");
}

/**
* Trace a debug message.
*/
private static void debug(String msg) {
if (debug) System.out.println(msg);
}

/**
* Program Main
* <p>
* Creates a server object, gets the JMX Service URL, and calls
* the method that will create and register the appropriate
* JMX Connector Server for that URL.
* <p>
* You may wish to use the following properties on the Java command line:
* <ul>
* <li><code>-Durl=&lt;jmxServiceURL&gt;</code>: specifies the URL of
*     the JMX Connector Server you wish to use. See README file for more
*     details.</li>
* <li><code>-Dagent.name=&lt;AgentName&gt;</code>: specifies an
*     AgentName to register with.</li>
* <li><code>-Djava.naming.factory.initial=&lt;initial-context-factory&gt;
*     </code>: The initial context factory to use for accessing the
*     LDAP directory (see {@link Context#INITIAL_CONTEXT_FACTORY
*     Context.INITIAL_CONTEXT_FACTORY}) - default is
*     <code>"com.sun.jndi.ldap.LdapCtxFactory"</code>.</li>
* <li><code>-Djava.naming.provider.url=&lt;provider-url&gt;</code>:
*     The LDAP Provider URL (see {@link Context#PROVIDER_URL
*     Context.PROVIDER_URL}).</li>
* <li><code>-Djava.naming.security.principal=&lt;ldap-principal&gt;
*     </code>: The security principal (login) to use to connect with
*     the LDAP directory (see {@link Context#SECURITY_PRINCIPAL
*     Context.SECURITY_PRINCIPAL} - default is
*     <code>"cn=Directory Manager"</code>.</li>
* <li><code>-Djava.naming.security.credentials=&lt;ldap-credentials&gt;
*     </code>: The security credentials (password) to use to
*     connect with the LDAP directory (see
*     {@link Context#SECURITY_CREDENTIALS
*     Context.SECURITY_CREDENTIALS}).</li>
* <li><code>-Ddebug="true|false"</code>: switch the Server debug flag
*     on/off (default is "false")</li>
* </ul>
*/
public static void main(String[] args) {
try {
// Get the value of the debug flag.
//
debug = (Boolean.valueOf(System.getProperty("debug","false"))).
booleanValue();

// Create a new Server object.
//
final Server s = new Server();

// Get the JMXConnector URL
//
final String url =
System.getProperty("url", "service:jmx:rmi://");

// Build a JMXServiceURL
//
final JMXServiceURL jurl = new JMXServiceURL(url);

// Creates a JMX Connector Server
//
final JMXConnectorServer server;
debug("Creating Connector: " + jurl);

final String p = jurl.getProtocol();
if (p.equals("rmi"))        // Create an RMI Connector
s.rmi(url);
else if (p.equals("iiop"))  // Create an RMI/IIOP Connector
s.rmi(url);
else                        // Unsupported protocol
throw new MalformedURLException("Unsupported protocol: " + p);

System.out.println("\nService URL successfully registered " +
"in the LDAP Lookup Service");

} catch (Exception x) {
System.err.println("Unexpected exception caught in main: " + x);
x.printStackTrace(System.err);
}
}
}

examples/Lookup/ldap/Client.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package jndi;

import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;

import javax.naming.directory.DirContext;
import javax.naming.directory.Attribute;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchResult;
import javax.naming.directory.SearchControls;

import javax.naming.ldap.InitialLdapContext;

import javax.management.remote.*;
import javax.management.*;

import java.text.SimpleDateFormat;

import java.util.Date;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Set;
import java.util.Iterator;
import java.util.Locale;
import java.util.Vector;

import java.io.IOException;
import java.io.Serializable;

/**
* This class demonstrates how to use an LDAP directory as a lookup service
* for JSR 160 connectors. It shows how to lookup a JMXServiceURL
* from the LDAP directory.
* <p>
* See README file and {@link #main(String[])} for more details.
* <p>
* Make sure to read the section "Binding with Lookup Services" of
* the JMX Remote API 1.0 Specification before looking at this example.
*/
public class Client {

private static boolean debug = false;

/**
* List all the attributes of an LDAP node.
*
* @param root The root DirContext.
* @param dn   The DN of the node, relative to the root DirContext.
*/
public static void listAttributes(DirContext root, String dn)
throws NamingException {
final Attributes attrs = root.getAttributes(dn);
System.out.println("dn: " + dn);
System.out.println("attributes: " + attrs);
}

/**
* Get a pointer to the root context of the directory tree
* under which this server is supposed to register itself.
* All LDAP DNs will be considered to be relative to that root.
* <p>
* Note that this root is not part of the JSR 160 specification,
* since the actual location where a JMX Agent will register
* its connectors is left completely open by the specification.
* The specification only discuss what the JMX Agent must/may
* put in the directory - but not where.
* <p>
* This method assumes that the root of the directory is
* will be passed in a the {@link Context#PROVIDER_URL
* Context.PROVIDER_URL} System property.
* <p>
* This method will transfer a fixed set of System Properties to
* the Hashtable given to the JNDI InitialContext:
* <ul><li>{@link Context#INITIAL_CONTEXT_FACTORY
*           Context.INITIAL_CONTEXT_FACTORY} - default is
*         <code>"com.sun.jndi.ldap.LdapCtxFactory"</code></li>
*     <li>{@link Context#PROVIDER_URL
*           Context.PROVIDER_URL}</li>
*     <li>{@link Context#SECURITY_PRINCIPAL
*           Context.SECURITY_PRINCIPAL} - default is
*         <code>"cn=Directory Manager"</code></li>
*     <li>{@link Context#SECURITY_CREDENTIALS
*           Context.SECURITY_CREDENTIALS}</li>
* </ul>
*
* @return a pointer to the LDAP Directory.
*/
public static DirContext getRootContext() throws NamingException {
// Prepare environment
//
final Hashtable env = new Hashtable();

// The Initial Context Factory must be provided, and
// must point to an LDAP Context Factory
//
final String factory =
System.getProperty(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");

// The LDAP Provider URL must be provided, and
// must point to a running LDAP directory server
//
final String ldapServerUrl =
System.getProperty(Context.PROVIDER_URL);

// The LDAP user must be provided, and
// must have write access to the subpart of the directory
// where the agent will be registered.
//
final String ldapUser =
System.getProperty(Context.SECURITY_PRINCIPAL,
"cn=Directory Manager");

// Credentials must be provided, so that the user may
// write to the directory.
//
final String ldapPasswd =
System.getProperty(Context.SECURITY_CREDENTIALS);

// Debug info: print provided values:
//
debug(Context.PROVIDER_URL + "=" + ldapServerUrl);
debug(Context.SECURITY_PRINCIPAL + "=" + ldapUser);
if (debug) {
System.out.print(Context.SECURITY_CREDENTIALS + "=");
final int len = (ldapPasswd==null)?0:ldapPasswd.length();
for (int i=0;i<len;i++) System.out.print("*");
System.out.println();
}

// Put provided value in the environment table.
//
env.put(Context.INITIAL_CONTEXT_FACTORY,factory);
env.put(Context.SECURITY_PRINCIPAL, ldapUser);
if (ldapServerUrl != null)
env.put(Context.PROVIDER_URL, ldapServerUrl);
if (ldapPasswd != null)
env.put(Context.SECURITY_CREDENTIALS, ldapPasswd);

// Create initial context
//
InitialContext root = new InitialLdapContext(env,null);

// Now return the root directory context.
//
return (DirContext)(root.lookup(""));
}

/**
* Parses the expirationDate in order to determined whether
* the associated URL has expired.
*
* @param expirationDate an X.208 GeneralizedTime, local or GMT.
*        Only yyyyMMddHHmmss.S (local time) and  yyyyMMddHHmmss.SZ
*        (GMT time) formats are recognized.
* @return true if the expirationDate could be parsed and is past,
*         false otherwise.
*/
public static boolean hasExpired(String expirationDate) {
if (expirationDate == null) return false;
try {
final Date localExpDate = getLocalDate(expirationDate);
final Date now = new Date();
if (localExpDate.before(now)) return true;
} catch (java.text.ParseException x) {
x.printStackTrace(System.out);
}
return false;
}

/**
* Returns a date in the local time zone parsed from an X.208
* formatted date. Only yyyyMMddHHmmss.S (local time) and
* yyyyMMddHHmmss.SZ (GMT time) formats are recognized.
*
* @param expirationDate an X.208 GeneralizedTime, local or GMT.
* @return the corresponding Date in the local time zone.
*/
public static Date getLocalDate(String expirationDate)
throws java.text.ParseException {
final SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMddHHmmss.S");
Date localDate = fmt.parse(expirationDate);
if (expirationDate.endsWith("Z")) {
final Date date = new Date();
if (fmt.getCalendar().getTimeZone().inDaylightTime(date))
localDate =
new Date(localDate.getTime() +
fmt.getCalendar().getTimeZone().getRawOffset() +
fmt.getCalendar().getTimeZone().getDSTSavings());
else
localDate =
new Date(localDate.getTime() +
fmt.getCalendar().getTimeZone().getRawOffset());
}
return localDate;
}

/**
* Lookup JMXConnectors in the LDAP directory.
*
* @param root A pointer to the LDAP directory,
*        returned by {@link #getRootContext()}.
* @param protocolType The protocol type of the JMX Connectors
*        we want to retrieve. If <var>protocolType</var> is null,
*        then the jmxProtocolType attribute is ignored. Otherwise,
*        only those agents that have registered a matching
*        jmxProtocolType attribute will be returned.
* @param name the AgentName of the JMXConnectors that should
*        be returned. If <var>name</var> is null, then
*        the JMXConnectors for all agents are returned
*        (null is an equivalent for a wildcard).
* @return The list of matching JMXConnectors retrieved from
*         the LDAP directory.
*/
public static List lookup(DirContext root, String protocolType, String name)
throws IOException, NamingException {

final ArrayList list = new ArrayList();

// If protocolType is not null, include it in the filter.
//
String queryProtocol =
(protocolType==null)?"":"(jmxProtocolType="+protocolType+")";

// Set the LDAPv3 query string
//
// Only those node that have the jmxConnector object class are
// of interest to us, so we specify (objectClass=jmxConnector)
// in the filter.
//
// We specify the jmxAgentName attribute in the filter so that the
// query will return only those services for which the AgentName
// attribute was registered. Since JSR 160 specifies that
// the AgentName attribute is mandatory, this makes it possible
// to filter out all the services that do not conform
// to the spec.
// If <name> is null, it is replaced by "*", so that all
// services for which the AgentName attribute was specified match,
// regardless of the value of that attribute.
// Otherwise, only those services for which AgentName matches the
// name or pattern specified by <name> will be returned.
//
// We also specify (jmxServiceURL=*) so that only those node
// for which the jmxServiceURL attribute is present will be
// returned. Thus, we filter out all those node corresponding
// to agents that are not currently available.
//
String query =
"(&" + "(objectClass=jmxConnector) " +
"(jmxServiceURL=*) " +
queryProtocol +
"(jmxAgentName=" + ((name!=null)?name:"*") + "))";

System.out.println("Looking up JMX Agents with filter: " + query );

SearchControls ctrls = new SearchControls();

// Want to get all jmxConnector objects, wherever they've been
// registered.
//
ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);

// Want to get only the jmxServiceUrl and jmxExpirationDate
// (comment these lines and all attributes will be returned).
//
// ctrls.setReturningAttributes(new String[] {
//           "jmxServiceURL",
//           "jmxExpirationDate"
//           });

// Search...
//
final NamingEnumeration results = root.search("", query, ctrls);

// Get the URL...
//
while (results.hasMore()) {

// Get node...
//
final SearchResult r = (SearchResult) results.nextElement();
debug("Found node: " + r.getName());

// Get attributes
//
final Attributes attrs = r.getAttributes();

// Get jmxServiceURL attribute
//
final Attribute  attr = attrs.get("jmxServiceURL");
if (attr == null) continue;

// Get jmxExpirationDate
//
final Attribute  exp = attrs.get("jmxExpirationDate");

// Check that URL has not expired.
//
if ((exp != null) && hasExpired((String)exp.get())) {
System.out.print(r.getName() + ": ");
System.out.println("URL expired since: " + exp.get());
continue;
}

// Get the URL string
//
final String urlStr = (String)attr.get();
if (urlStr.length() == 0) continue;

debug("Found URL: " + urlStr);

// Create a JMXServiceURL
//
final JMXServiceURL url  = new JMXServiceURL(urlStr);

// Create a JMXConnector
//
final JMXConnector conn =
JMXConnectorFactory.newJMXConnector(url,null);

// Add the connector to the result list
//
list.add(conn);
if (debug) listAttributes(root,r.getName());
}

return list;
}

/**
* List all MBeans and their attributes.
*/
public static void listMBeans(MBeanServerConnection server)
throws IOException {
final Set names = server.queryNames(null,null);
for (final Iterator i=names.iterator(); i.hasNext(); ) {
ObjectName name = (ObjectName)i.next();
System.out.println("Got MBean: "+name);
try {
MBeanInfo info =
server.getMBeanInfo((ObjectName)name);
MBeanAttributeInfo[] attrs = info.getAttributes();
if (attrs == null) continue;
for (int j=0; j<attrs.length; j++) {
if (attrs[j].isReadable()) {
try {
Object o =
server.getAttribute(name,attrs[j].getName());
System.out.println("\t\t" + attrs[j].getName() +
" = "+o);
} catch (Exception x) {
System.err.println("JmxClient failed to get " +
attrs[j].getName());
x.printStackTrace(System.err);
}
}
}
} catch (Exception x) {
System.err.println("JmxClient failed to get MBeanInfo: "  + x);
x.printStackTrace(System.err);
}
}
}

/**
* Trace a debug message.
*/
private static void debug(String msg) {
if (debug) System.out.println(msg);
}

/**
* Program Main.
* <p>
* Lookup all JMX agents in the LDAP Directory and list
* their MBeans and attributes.
* <p>
* You may wish to use the following properties on the Java command line:
* <ul>
* <li><code>-Dagent.name=&lt;AgentName&gt;</code>: specifies an
*     AgentName to lookup (default is null, meaning any agent).</li>
* <li><code>-Dprotocol=&lt;ProtocolType&gt;</code>: restrains the client
*     to lookup for a specific protocol type (default is null,
*     meaning any type).</li>
* <li><code>-Djava.naming.factory.initial=&lt;initial-context-factory&gt;
*     </code>: The initial context factory to use for accessing the
*     LDAP directory (see {@link Context#INITIAL_CONTEXT_FACTORY
*     Context.INITIAL_CONTEXT_FACTORY}) - default is
*     <code>"com.sun.jndi.ldap.LdapCtxFactory"</code>.</li>
* <li><code>-Djava.naming.provider.url=&lt;provider-url&gt;</code>:
*     The LDAP Provider URL (see {@link Context#PROVIDER_URL
*     Context.PROVIDER_URL}).</li>
* <li><code>-Djava.naming.security.principal=&lt;ldap-principal&gt;
*     </code>: The security principal (login) to use to connect with
*     the LDAP directory (see {@link Context#SECURITY_PRINCIPAL
*     Context.SECURITY_PRINCIPAL} - default is
*     <code>"cn=Directory Manager"</code>.</li>
* <li><code>-Djava.naming.security.credentials=&lt;ldap-credentials&gt;
*     </code>: The security credentials (password) to use to
*     connect with the LDAP directory (see
*     {@link Context#SECURITY_CREDENTIALS
*     Context.SECURITY_CREDENTIALS}).</li>
* <li><code>-Ddebug="true|false"</code>: switch the Server debug flag
*     on/off (default is "false")</li>
* </ul>
*/
public static void main(String[] args) {
try {
// Get the value of the debug flag.
//
debug = (Boolean.valueOf(System.getProperty("debug","false"))).
booleanValue();

// Get a pointer to the LDAP Directory.
//
final DirContext root = getRootContext();
debug("root is: " + root.getNameInNamespace());

final String protocolType=System.getProperty("protocol");
final String agentName=System.getProperty("agent.name");

// Lookup all matching agents in the LDAP Directory.
//
List l = lookup(root,protocolType,agentName);

// Attempt to connect to retrieved agents
//
System.out.println("Number of agents found : " + l.size());
int j = 1;
for (Iterator i=l.iterator();i.hasNext();j++) {
JMXConnector c1 = (JMXConnector) i.next();
if (c1 != null) {

// Connect
//
System.out.println(
"----------------------------------------------------");
System.out.println("\tConnecting to agent number "+j);
System.out.println(
"----------------------------------------------------");
debug("JMXConnector is: " + c1);

// Prepare the environment Map
//
final HashMap env = new HashMap();
final String factory =
System.getProperty(Context.INITIAL_CONTEXT_FACTORY);
final String ldapServerUrl =
System.getProperty(Context.PROVIDER_URL);
final String ldapUser =
System.getProperty(Context.SECURITY_PRINCIPAL);
final String ldapPasswd =
System.getProperty(Context.SECURITY_CREDENTIALS);

// Transfer some system properties to the Map
//
if (factory!= null) // this should not be needed
env.put(Context.INITIAL_CONTEXT_FACTORY,factory);
if (ldapServerUrl!=null) // this should not be needed
env.put(Context.PROVIDER_URL, ldapServerUrl);
if (ldapUser!=null) // this is needed when LDAP is used
env.put(Context.SECURITY_PRINCIPAL, ldapUser);
if (ldapPasswd != null) // this is needed when LDAP is used
env.put(Context.SECURITY_CREDENTIALS, ldapPasswd);

try {
c1.connect(env);
} catch (IOException x) {
System.err.println("Connection failed: " + x);
x.printStackTrace(System.err);
continue;
}

// Get MBeanServerConnection
//
MBeanServerConnection conn =
c1.getMBeanServerConnection();
debug("Connection is:" + conn);
System.out.println("Server domain is: " +
conn.getDefaultDomain());

// List all MBeans
//
try {
listMBeans(conn);
} catch (IOException x) {
System.err.println("Failed to list MBeans: " + x);
x.printStackTrace(System.err);
}

// Close connector
//
try {
c1.close();
} catch (IOException x) {
System.err.println("Failed to close connection: " + x);
x.printStackTrace(System.err);
}
}
}
} catch (Exception x) {
System.err.println("Unexpected exception caught in main: " + x);
x.printStackTrace(System.err);
}
}
}

examples/Lookup/ldap/jmx-schema.txt

--                    LDAP Schema for JSR 160 Lookup
--                    ------------------------------

-- AttributeTypes:
-----------------

-- jmxServiceURL attribute is an IA5 String

( 1.3.6.1.4.1.42.2.27.11.1.1 NAME 'jmxServiceURL'
DESC 'String representation of a JMX Service URL'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE )

-- jmxAgentName attribute is an IA5 String

( 1.3.6.1.4.1.42.2.27.11.1.2 NAME 'jmxAgentName'
DESC 'Name of the JMX Agent'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE )

-- jmxProtocolType attribute is an IA5 String

( 1.3.6.1.4.1.42.2.27.11.1.3 NAME 'jmxProtocolType'
DESC 'Protocol used by the registered connector'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE )

-- jmxAgentHost attribute is an IA5 String

( 1.3.6.1.4.1.42.2.27.11.1.4 NAME 'jmxAgentHost'
DESC 'Names or IP Addresses of the host on which the agent is running.
When multiple values are given, they should be aliases to the
same host.'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26  )

-- jmxProperty attribute is an IA5 String

( 1.3.6.1.4.1.42.2.27.11.1.5 NAME 'jmxProperty'
DESC 'Java-like property characterizing the registered object.
The form of each value should be: "<property-name>=<value>".
For instance: "com.sun.jmx.remote.tcp.timeout=200"'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

-- jmxExpirationDate attribute is a Generalized Time
-- see [RFC 2252] - or X.208 for a description of
-- Generalized Time

( 1.3.6.1.4.1.42.2.27.11.1.6 NAME 'jmxExpirationDate'
DESC 'Date at which the JMX Service URL will be considered obsolete
and may be removed from the directory tree'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE )

-- ObjectClasses:
-----------------

-- jmxConnector class - represents a JMX Connector.
-- must contain the JMX Service URL
-- and the JMX Agent Name

( 1.3.6.1.4.1.42.2.27.11.2.1 NAME 'jmxConnector'
DESC  'A class representing a JMX Connector, and containing a
JMX Service URL. The jmxServiceURL is not present if the server
is not accepting connections'
AUXILIARY
MUST  ( jmxAgentName  )
MAY   ( jmxServiceURL $ jmxAgentHost $ jmxProtocolType $ jmxProperty $
jmxExpirationDate $ description ) )

examples/Lookup/ldap/60jmx-schema.ldif

dn: cn=schema
attributeTypes: ( 1.3.6.1.4.1.42.2.27.11.1.1 NAME 'jmxServiceURL'
DESC 'String representation of a JMX Service URL'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.4.1.42.2.27.11.1.2 NAME 'jmxAgentName'
DESC 'Name of the JMX Agent'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.4.1.42.2.27.11.1.3 NAME 'jmxProtocolType'
DESC 'Protocol used by the registered connector'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE )
attributeTypes: ( 1.3.6.1.4.1.42.2.27.11.1.4 NAME 'jmxAgentHost'
DESC 'Names or IP Addresses of the host on which the agent is running.
When multiple values are given, they should be aliases to the same host.'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributeTypes: ( 1.3.6.1.4.1.42.2.27.11.1.5 NAME 'jmxProperty'
DESC 'Java-like property characterizing the registered object.
The form of each value should be: "<property-name>=<value>".
For instance: "com.sun.jmx.remote.tcp.timeout=200"'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributeTypes: ( 1.3.6.1.4.1.42.2.27.11.1.6 NAME 'jmxExpirationDate'
DESC 'Date at which the JMX Service URL will be considered
obsolete and may be removed from the directory tree'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE )
objectClasses: ( 1.3.6.1.4.1.42.2.27.11.2.1 NAME 'jmxConnector'
DESC  'A class representing a JMX Connector, and containing a
JMX Service URL. The jmxServiceURL is not present if the server is
not accepting connections'
AUXILIARY
MUST  ( jmxAgentName  )
MAY   ( jmxServiceURL $ jmxAgentHost $ jmxProtocolType $
jmxProperty $ jmxExpirationDate $ description ) )

22 簡単なセキュリティ

接続を保護するために存在するJMX API。この例では、次を含む、簡単なセキュリティの実装を提供します。

- README file

- Server

- Client

- ClientListener

- access.properties

- keystore

- password.properties

- truststore

- SimpleStandard

- SimpleStandardMBean

examples/Security/simple/README

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
#

# ==============================================================================
#
#  Example of a secure RMI connector.
#
#  This example uses:
#
#  - the RMI SSL socket factories for encryption,
#  - the password authenticator based on the JMXAuthenticator interface for
#    user authentication,
#  - the file access controller based on the MBeanServerForwarder interface
#    for user access level authorization.
#
# ==============================================================================
#
# In order to compile and run the example, make a copy of this README file, and
# then simply cut and paste all the commands as needed into a terminal window.
#
# This README makes the assumption that you are running under Java SE 6 on Unix,
# you are familiar with the JMX technology, and with the bourne shell or korn
# shell syntax.
#
# All the commands below are defined using Unix korn shell syntax.
#
# If you are not running Unix and korn shell you are expected to be able to
# adapt these commands to your favorite OS and shell environment.
#

# Compile Java classes
#
# * Server.java: creates an MBeanServer and creates and starts a secure RMI
#                connector server (JRMP).
#
# * Client.java: creates a secure RMI connector (JRMP), creates and registers
#                a Simple standard MBean and performs operations on it.
#
# * ClientListener.java: implements a generic notification listener.
#
# * SimpleStandard.java: implements the Simple standard MBean.
#
# * SimpleStandardMBean.java: the management interface exposed by the Simple
#                             standard MBean.
#

javac mbeans/SimpleStandard.java \
mbeans/SimpleStandardMBean.java \
server/Server.java \
client/Client.java \
client/ClientListener.java

# Start the RMI registry:
#

export CLASSPATH=server ; rmiregistry 9999 &

# Start the Server:
#

java -classpath server:mbeans \
-Djavax.net.ssl.keyStore=config/keystore \
-Djavax.net.ssl.keyStorePassword=password \
Server &

# Start the Client:
#

java -classpath client:server:mbeans \
-Djavax.net.ssl.trustStore=config/truststore \
-Djavax.net.ssl.trustStorePassword=trustword \
Client

# ==============================================================================

examples/Security/simple/server/Server.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import java.io.File;
import java.util.HashMap;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnectorServer;
import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;

public class Server {

public static void main(String[] args) {
try {
// Instantiate the MBean server
//
System.out.println("\nCreate the MBean server");
MBeanServer mbs = MBeanServerFactory.createMBeanServer();

// Environment map
//
System.out.println("\nInitialize the environment map");
HashMap env = new HashMap();

// Provide SSL-based RMI socket factories.
//
SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory();
env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,csf);
env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,ssf);

// Provide the password file used by the connector server to
// perform user authentication. The password file is a properties
// based text file specifying username/password pairs. This
// properties based password authenticator has been implemented
// using the JMXAuthenticator interface and is passed to the
// connector through the "jmx.remote.authenticator" property
// in the map.
//
// This property is implementation-dependent and might not be
// supported by all implementations of the JMX Remote API.
//
env.put("jmx.remote.x.password.file",
"config" + File.separator + "password.properties");

// Provide the access level file used by the connector server to
// perform user authorization. The access level file is a properties
// based text file specifying username/access level pairs where
// access level is either "readonly" or "readwrite" access to the
// MBeanServer operations. This properties based access control
// checker has been implemented using the MBeanServerForwarder
// interface which wraps the real MBean server inside an access
// controller MBean server which performs the access control checks
// before forwarding the requests to the real MBean server.
//
// This property is implementation-dependent and might not be
// supported by all implementations of the JMX Remote API.
//
env.put("jmx.remote.x.access.file",
"config" + File.separator + "access.properties");

// Create an RMI connector server
//
System.out.println("\nCreate an RMI connector server");
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);

// Start the RMI connector server
//
System.out.println("\nStart the RMI connector server");
cs.start();
System.out.println("\nRMI connector server successfully started");
System.out.println("\nWaiting for incoming connections...");
} catch (Exception e) {
e.printStackTrace();
}
}
}

examples/Security/simple/client/Client.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import java.util.HashMap;
import javax.management.Attribute;
import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

public class Client {

public static void main(String[] args) {
try {
// Environment map
//
System.out.println("\nInitialize the environment map");
HashMap env = new HashMap();

// Provide the credentials required by the server to successfully
// perform user authentication
//
String[] credentials = new String[] { "username" , "password" };
env.put("jmx.remote.credentials", credentials);

// Create an RMI connector client and
// connect it to the RMI connector server
//
System.out.println("\nCreate an RMI connector client and " +
"connect it to the RMI connector server");
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnector jmxc = JMXConnectorFactory.connect(url, env);

// Get an MBeanServerConnection
//
System.out.println("\nGet an MBeanServerConnection");
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();

// Get domains from MBeanServer
//
System.out.println("\nDomains:");
String domains[] = mbsc.getDomains();
for (int i = 0; i < domains.length; i++) {
System.out.println("\tDomain[" + i + "] = " + domains[i]);
}

// Create SimpleStandard MBean
//
ObjectName mbeanName = new ObjectName("MBeans:type=SimpleStandard");
System.out.println("\nCreate SimpleStandard MBean...");
mbsc.createMBean("SimpleStandard", mbeanName, null, null);

// Get MBean count
//
System.out.println("\nMBean count = " + mbsc.getMBeanCount());

// Get State attribute
//
System.out.println("\nState = " +
mbsc.getAttribute(mbeanName, "State"));

// Set State attribute
//
mbsc.setAttribute(mbeanName,
new Attribute("State", "changed state"));

// Get State attribute
//
// Another way of interacting with a given MBean is through a
// dedicated proxy instead of going directly through the MBean
// server connection
//
SimpleStandardMBean proxy = JMX.newMBeanProxy(
mbsc, mbeanName, SimpleStandardMBean.class);
System.out.println("\nState = " + proxy.getState());

// Add notification listener on SimpleStandard MBean
//
ClientListener listener = new ClientListener();
System.out.println("\nAdd notification listener...");
mbsc.addNotificationListener(mbeanName, listener, null, null);

// Invoke "reset" in SimpleStandard MBean
//
// Calling "reset" makes the SimpleStandard MBean emit a
// notification that will be received by the registered
// ClientListener.
//
System.out.println("\nInvoke reset() in SimpleStandard MBean...");
mbsc.invoke(mbeanName, "reset", null, null);

// Sleep for 2 seconds in order to have time to receive the
// notification before removing the notification listener.
//
System.out.println("\nWaiting for notification...");
Thread.sleep(2000);

// Remove notification listener on SimpleStandard MBean
//
System.out.println("\nRemove notification listener...");
mbsc.removeNotificationListener(mbeanName, listener);

// Unregister SimpleStandard MBean
//
System.out.println("\nUnregister SimpleStandard MBean...");
mbsc.unregisterMBean(mbeanName);

// Close MBeanServer connection
//
System.out.println("\nClose the connection to the server");
jmxc.close();
System.out.println("\nBye! Bye!");
} catch (Exception e) {
e.printStackTrace();
}
}
}

examples/Security/simple/client/ClientListener.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import javax.management.Notification;
import javax.management.NotificationListener;

public class ClientListener implements NotificationListener {
public void handleNotification(Notification notification, Object handback) {
System.out.println("\nReceived notification: " + notification);
}
}

examples/Security/simple/config/access.properties

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
#

# access.properties

# Access control file for Remote JMX API access to MBeanServer resources.
# This file defines the allowed access for different roles.

# The file format for the access file is syntactically the same as the
# Properties file format.  The syntax is described in the Javadoc for
# java.util.Properties.load.

# A typical access file has multiple lines, where each line is blank,
# a comment (like this one), or an access control entry.

# An access control entry consists of a role name, and an associated access
# level. The role name is any string that does not itself contain spaces or
# tabs. It corresponds to an entry in the password file. The access level
# is one of the following:
#
#       "readonly"  grants access to read attributes of MBeans.
#                   For monitoring, this means that a remote client in this
#                   role can read measurements but cannot perform any action
#                   that changes the environment of the running program.
#
#       "readwrite" grants access to read and write attributes of MBeans, to
#                   invoke operations on them, and to create or remove them.
#                   This access should be only granted to trusted clients,
#                   since they can potentially interfere with the smooth
#                   operation of a running program.

# A given role should have at most one entry in this file. If a role has no
# entry, it has no access.
# If multiple entries are found for the same role name, then the last access
# entry is used.

# Access rights granted to the authenticated identity by the RMI connector
# in this example.
#
username readwrite

examples/Security/simple/config/password.properties

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
#

# password.properties

# Password file for Remote JMX API authentication. This file defines
# the different roles and their passwords.

# The file format for the password file is syntactically the same as
# the Properties file format. The syntax is described in the Javadoc
# for java.util.Properties.load.

# A typical password file has multiple lines, where each line is blank,
# a comment (like this one), or a password entry.

# A password entry consists of a role name and an associated password.
# The role name is any string that does not itself contain spaces or
# tabs. The password is again any string that does not contain spaces
# or tabs. Note that passwords appear in the clear in this file, so it
# is a good idea not to use valuable passwords.

# A given role should have at most one entry in this file. If a role
# has no entry, it has no access.
# If multiple entries are found for the same role name, then the last
# one is used.

# In a typical installation, this file can be read by anybody on the
# local machine, and possibly by people on other machines.
# For security, you should either restrict the access to this file,
# or specify another, less accessible file in the management config
# file as described above.

# Role and password used for authentication by the RMI connector in
# this example.
#
username password

examples/Security/simple/mbeans/SimpleStandard.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* Simple definition of a standard MBean, named "SimpleStandard".
*
* The "SimpleStandard" standard MBean shows how to expose attributes
* and operations for management by implementing its corresponding
* "SimpleStandardMBean" management interface.
*
* This MBean has two attributes and one operation exposed
* for management by a JMX agent:
*      - the read/write "State" attribute,
*      - the read only "NbChanges" attribute,
*      - the "reset()" operation.
*
* This object also has one property and one method not exposed
* for management by a JMX agent:
*      - the "NbResets" property,
*      - the "getNbResets()" method.
*/

import javax.management.AttributeChangeNotification;
import javax.management.MBeanNotificationInfo;
import javax.management.NotificationBroadcasterSupport;

public class SimpleStandard
extends NotificationBroadcasterSupport
implements SimpleStandardMBean {

/*
* -----------------------------------------------------
* CONSTRUCTORS
* -----------------------------------------------------
*/

/* "SimpleStandard" does not provide any specific constructors.
* However, "SimpleStandard" is JMX compliant with regards to
* contructors because the default contructor SimpleStandard()
* provided by the Java compiler is public.
*/

/*
* -----------------------------------------------------
* IMPLEMENTATION OF THE SimpleStandardMBean INTERFACE
* -----------------------------------------------------
*/

/**
* Getter: get the "State" attribute of the "SimpleStandard" standard MBean.
*
* @return the current value of the "State" attribute.
*/
public String getState() {
return state;
}

/**
* Setter: set the "State" attribute of the "SimpleStandard" standard MBean.
*
* @param <VAR>s</VAR> the new value of the "State" attribute.
*/
public void setState(String s) {
state = s;
nbChanges++;
}

/**
* Getter: get the "NbChanges" attribute of the "SimpleStandard" standard
* MBean.
*
* @return the current value of the "NbChanges" attribute.
*/
public int getNbChanges() {
return nbChanges;
}

/**
* Operation: reset to their initial values the "State" and "NbChanges"
* attributes of the "SimpleStandard" standard MBean.
*/
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);
}

/*
* -----------------------------------------------------
* METHOD NOT EXPOSED FOR MANAGEMENT BY A JMX AGENT
* -----------------------------------------------------
*/

/**
* Return the "NbResets" property.
* This method is not a Getter in the JMX sense because it
* is not exposed in the "SimpleStandardMBean" interface.
*
* @return the current value of the "NbResets" property.
*/
public int getNbResets() {
return nbResets;
}

/**
* Returns an array indicating, for each notification this MBean
* may send, the name of the Java class of the notification and
* the notification type.</p>
*
* @return the array of possible notifications.
*/
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.")
};
}

/*
* -----------------------------------------------------
* ATTRIBUTES ACCESSIBLE FOR MANAGEMENT BY A JMX AGENT
* -----------------------------------------------------
*/

private String state = "initial state";
private int nbChanges = 0;

/*
* -----------------------------------------------------
* PROPERTY NOT ACCESSIBLE FOR MANAGEMENT BY A JMX AGENT
* -----------------------------------------------------
*/

private int nbResets = 0;
}

examples/Security/simple/mbeans/SimpleStandardMBean.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* This is the management interface explicitly defined for the
* "SimpleStandard" standard MBean.
*
* The "SimpleStandard" standard MBean implements this interface
* in order to be manageable through a JMX agent.
*
* The "SimpleStandardMBean" interface shows how to expose for management:
* - a read/write attribute (named "State") through its getter and setter
*   methods,
* - a read-only attribute (named "NbChanges") through its getter method,
* - an operation (named "reset").
*/
public interface SimpleStandardMBean {

/**
* Getter: set the "State" attribute of the "SimpleStandard" standard
* MBean.
*
* @return the current value of the "State" attribute.
*/
public String getState();

/**
* Setter: set the "State" attribute of the "SimpleStandard" standard
* MBean.
*
* @param <VAR>s</VAR> the new value of the "State" attribute.
*/
public void setState(String s);

/**
* Getter: get the "NbChanges" attribute of the "SimpleStandard" standard
* MBean.
*
* @return the current value of the "NbChanges" attribute.
*/
public int getNbChanges();

/**
* Operation: reset to their initial values the "State" and "NbChanges"
* attributes of the "SimpleStandard" standard MBean.
*/
public void reset();
}

23 主体委譲を使用したセキュリティ

接続を保護するために存在するJMX API。この例では、次を含む、主体委譲を使用したセキュリティを提供します。

- README file

- Server

- Client

- ClientListener

- access.properties

- keystore

- password.properties

- java.policy

- SimpleStandard

- SimpleStandardMBean

examples/Security/subject_delegation/README

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
#

# ==============================================================================
#
#  Example of a secure RMI connector (subject delegation).
#
#  This example uses:
#
#  - the password authenticator based on the JMXAuthenticator interface for
#    user authentication,
#  - the file access controller based on the MBeanServerForwarder interface
#    for user access level authorization,
#  - the subject delegation feature: the connection is authenticated using
#    "username" as principal but the operations and hence the authorization
#    checks are performed on behalf of the "delegate" principal. The policy
#    file grants permission to the principal "username" to perform operations
#    on behalf of the principal "delegate".
#
# ==============================================================================
#
# In order to compile and run the example, make a copy of this README file, and
# then simply cut and paste all the commands as needed into a terminal window.
#
# This README makes the assumption that you are running under Java SE 6 on Unix,
# you are familiar with the JMX technology, and with the bourne shell or korn
# shell syntax.
#
# All the commands below are defined using Unix korn shell syntax.
#
# If you are not running Unix and korn shell you are expected to be able to
# adapt these commands to your favorite OS and shell environment.
#

# Compile Java classes
#
# * Server.java: creates an MBeanServer and creates and starts a secure RMI
#                connector server (JRMP).
#
# * Client.java: creates a secure RMI connector (JRMP), creates and registers
#                a Simple standard MBean and performs operations on it
#                using a delegation subject.
#
# * ClientListener.java: implements a generic notification listener.
#
# * SimpleStandard.java: implements the Simple standard MBean.
#
# * SimpleStandardMBean.java: the management interface exposed by the Simple
#                             standard MBean.
#

javac mbeans/SimpleStandard.java \
mbeans/SimpleStandardMBean.java \
server/Server.java \
client/Client.java \
client/ClientListener.java

# Start the RMI registry:
#

export CLASSPATH=server ; rmiregistry 9999 &

# Start the Server:
#

java -classpath server:mbeans \
-Djava.security.policy=config/java.policy \
Server &

# Start the Client:
#

java -classpath client:server:mbeans Client

# ==============================================================================

examples/Security/subject_delegation/server/Server.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import java.io.File;
import java.util.HashMap;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

public class Server {

public static void main(String[] args) {
try {
// Instantiate the MBean server
//
System.out.println("\nCreate the MBean server");
MBeanServer mbs = MBeanServerFactory.createMBeanServer();

// Environment map
//
System.out.println("\nInitialize the environment map");
HashMap env = new HashMap();

// Provide the password file used by the connector server to
// perform user authentication. The password file is a properties
// based text file specifying username/password pairs. This
// properties based password authenticator has been implemented
// using the JMXAuthenticator interface and is passed to the
// connector through the "jmx.remote.authenticator" property
// in the map.
//
// This property is implementation-dependent and might not be
// supported by all implementations of the JMX Remote API.
//
env.put("jmx.remote.x.password.file",
"config" + File.separator + "password.properties");

// Provide the access level file used by the connector server to
// perform user authorization. The access level file is a properties
// based text file specifying username/access level pairs where
// access level is either "readonly" or "readwrite" access to the
// MBeanServer operations. This properties based access control
// checker has been implemented using the MBeanServerForwarder
// interface which wraps the real MBean server inside an access
// controller MBean server which performs the access control checks
// before forwarding the requests to the real MBean server.
//
// This property is implementation-dependent and might not be
// supported by all implementations of the JMX Remote API.
//
env.put("jmx.remote.x.access.file",
"config" + File.separator + "access.properties");

// Create an RMI connector server
//
System.out.println("\nCreate an RMI connector server");
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);

// Start the RMI connector server
//
System.out.println("\nStart the RMI connector server");
cs.start();
System.out.println("\nRMI connector server successfully started");
System.out.println("\nWaiting for incoming connections...");
} catch (Exception e) {
e.printStackTrace();
}
}
}

examples/Security/subject_delegation/client/Client.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import java.util.Collections;
import java.util.HashMap;
import javax.management.Attribute;
import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXPrincipal;
import javax.management.remote.JMXServiceURL;
import javax.security.auth.Subject;

public class Client {

public static void main(String[] args) {
try {
// Environment map
//
System.out.println("\nInitialize the environment map");
HashMap env = new HashMap();

// Provide the credentials required by the server to successfully
// perform user authentication
//
String[] credentials = new String[] { "username" , "password" };
env.put("jmx.remote.credentials", credentials);

// Create an RMI connector client and
// connect it to the RMI connector server
//
System.out.println("\nCreate an RMI connector client and " +
"connect it to the RMI connector server");
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnector jmxc = JMXConnectorFactory.connect(url, env);

// Create the delegation subject and retrieve an
// MBeanServerConnection that uses that subject
// when performing the operations on the remote
// MBean server
//
// The connector server will check that the authentication identity
// "username" has the right to execute operations on behalf of the
// given authorization identity "delegate", i.e. the policy file
// must contain the following grant clause:
//
// grant principal javax.management.remote.JMXPrincipal "username" {
//   permission javax.management.remote.SubjectDelegationPermission
//                  "javax.management.remote.JMXPrincipal.delegate";
// };
//
System.out.println("\nCreate the delegation subject");
Subject delegationSubject =
new Subject(true,
Collections.singleton(new JMXPrincipal("delegate")),
Collections.EMPTY_SET,
Collections.EMPTY_SET);

// Get an MBeanServerConnection for the given delegation subject
//
System.out.println("\nGet an MBeanServerConnection " +
"for the given delegation subject");
MBeanServerConnection mbsc =
jmxc.getMBeanServerConnection(delegationSubject);

// Get domains from MBeanServer
//
System.out.println("\nDomains:");
String domains[] = mbsc.getDomains();
for (int i = 0; i < domains.length; i++) {
System.out.println("\tDomain[" + i + "] = " + domains[i]);
}

// Create SimpleStandard MBean
//
ObjectName mbeanName = new ObjectName("MBeans:type=SimpleStandard");
System.out.println("\nCreate SimpleStandard MBean...");
mbsc.createMBean("SimpleStandard", mbeanName, null, null);

// Get MBean count
//
System.out.println("\nMBean count = " + mbsc.getMBeanCount());

// Get State attribute
//
System.out.println("\nState = " +
mbsc.getAttribute(mbeanName, "State"));

// Set State attribute
//
mbsc.setAttribute(mbeanName,
new Attribute("State", "changed state"));

// Get State attribute
//
// Another way of interacting with a given MBean is through a
// dedicated proxy instead of going directly through the MBean
// server connection
//
SimpleStandardMBean proxy = JMX.newMBeanProxy(
mbsc, mbeanName, SimpleStandardMBean.class);
System.out.println("\nState = " + proxy.getState());

// Add notification listener on SimpleStandard MBean
//
ClientListener listener = new ClientListener();
System.out.println("\nAdd notification listener...");
mbsc.addNotificationListener(mbeanName, listener, null, null);

// Invoke "reset" in SimpleStandard MBean
//
// Calling "reset" makes the SimpleStandard MBean emit a
// notification that will be received by the registered
// ClientListener.
//
System.out.println("\nInvoke reset() in SimpleStandard MBean...");
mbsc.invoke(mbeanName, "reset", null, null);

// Sleep for 2 seconds in order to have time to receive the
// notification before removing the notification listener.
//
System.out.println("\nWaiting for notification...");
Thread.sleep(2000);

// Remove notification listener on SimpleStandard MBean
//
System.out.println("\nRemove notification listener...");
mbsc.removeNotificationListener(mbeanName, listener);

// Unregister SimpleStandard MBean
//
System.out.println("\nUnregister SimpleStandard MBean...");
mbsc.unregisterMBean(mbeanName);

// Close MBeanServer connection
//
System.out.println("\nClose the connection to the server");
jmxc.close();
System.out.println("\nBye! Bye!");
} catch (Exception e) {
e.printStackTrace();
}
}
}

examples/Security/subject_delegation/client/ClientListener.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import javax.management.Notification;
import javax.management.NotificationListener;

public class ClientListener implements NotificationListener {
public void handleNotification(Notification notification, Object handback) {
System.out.println("\nReceived notification: " + notification);
}
}

examples/Security/subject_delegation/config/access.properties

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
#

# access.properties

# Access control file for Remote JMX API access to MBeanServer resources.
# This file defines the allowed access for different roles.

# The file format for the access file is syntactically the same as the
# Properties file format.  The syntax is described in the Javadoc for
# java.util.Properties.load.

# A typical access file has multiple lines, where each line is blank,
# a comment (like this one), or an access control entry.

# An access control entry consists of a role name, and an associated access
# level. The role name is any string that does not itself contain spaces or
# tabs. It corresponds to an entry in the password file. The access level
# is one of the following:
#
#       "readonly"  grants access to read attributes of MBeans.
#                   For monitoring, this means that a remote client in this
#                   role can read measurements but cannot perform any action
#                   that changes the environment of the running program.
#
#       "readwrite" grants access to read and write attributes of MBeans, to
#                   invoke operations on them, and to create or remove them.
#                   This access should be only granted to trusted clients,
#                   since they can potentially interfere with the smooth
#                   operation of a running program.

# A given role should have at most one entry in this file. If a role has no
# entry, it has no access.
# If multiple entries are found for the same role name, then the last access
# entry is used.

# Access rights granted to the authenticated identity and the delegated
# identity by the RMI connector in this example.
#
username readwrite
delegate readwrite

examples/Security/subject_delegation/config/password.properties

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
#

# password.properties

# Password file for Remote JMX API authentication. This file defines
# the different roles and their passwords.

# The file format for the password file is syntactically the same as
# the Properties file format. The syntax is described in the Javadoc
# for java.util.Properties.load.

# A typical password file has multiple lines, where each line is blank,
# a comment (like this one), or a password entry.

# A password entry consists of a role name and an associated password.
# The role name is any string that does not itself contain spaces or
# tabs. The password is again any string that does not contain spaces
# or tabs. Note that passwords appear in the clear in this file, so it
# is a good idea not to use valuable passwords.

# A given role should have at most one entry in this file. If a role
# has no entry, it has no access.
# If multiple entries are found for the same role name, then the last
# one is used.

# In a typical installation, this file can be read by anybody on the
# local machine, and possibly by people on other machines.
# For security, you should either restrict the access to this file,
# or specify another, less accessible file in the management config
# file as described above.

# Role and password used for authentication by the RMI connector in
# this example.
#
username password

examples/Security/subject_delegation/config/java.policy

grant codeBase "file:server" {
permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate";
};

grant principal javax.management.remote.JMXPrincipal "username" {
//
// Grant the JMXPrincipal "username" the right to act on behalf of a JMXPrincipal "delegate".
//
permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate";
};

examples/Security/subject_delegation/mbeans/SimpleStandard.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* Simple definition of a standard MBean, named "SimpleStandard".
*
* The "SimpleStandard" standard MBean shows how to expose attributes
* and operations for management by implementing its corresponding
* "SimpleStandardMBean" management interface.
*
* This MBean has two attributes and one operation exposed
* for management by a JMX agent:
*      - the read/write "State" attribute,
*      - the read only "NbChanges" attribute,
*      - the "reset()" operation.
*
* This object also has one property and one method not exposed
* for management by a JMX agent:
*      - the "NbResets" property,
*      - the "getNbResets()" method.
*/

import javax.management.AttributeChangeNotification;
import javax.management.MBeanNotificationInfo;
import javax.management.NotificationBroadcasterSupport;

public class SimpleStandard
extends NotificationBroadcasterSupport
implements SimpleStandardMBean {

/*
* -----------------------------------------------------
* CONSTRUCTORS
* -----------------------------------------------------
*/

/* "SimpleStandard" does not provide any specific constructors.
* However, "SimpleStandard" is JMX compliant with regards to
* contructors because the default contructor SimpleStandard()
* provided by the Java compiler is public.
*/

/*
* -----------------------------------------------------
* IMPLEMENTATION OF THE SimpleStandardMBean INTERFACE
* -----------------------------------------------------
*/

/**
* Getter: get the "State" attribute of the "SimpleStandard" standard MBean.
*
* @return the current value of the "State" attribute.
*/
public String getState() {
return state;
}

/**
* Setter: set the "State" attribute of the "SimpleStandard" standard MBean.
*
* @param <VAR>s</VAR> the new value of the "State" attribute.
*/
public void setState(String s) {
state = s;
nbChanges++;
}

/**
* Getter: get the "NbChanges" attribute of the "SimpleStandard" standard
* MBean.
*
* @return the current value of the "NbChanges" attribute.
*/
public int getNbChanges() {
return nbChanges;
}

/**
* Operation: reset to their initial values the "State" and "NbChanges"
* attributes of the "SimpleStandard" standard MBean.
*/
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);
}

/*
* -----------------------------------------------------
* METHOD NOT EXPOSED FOR MANAGEMENT BY A JMX AGENT
* -----------------------------------------------------
*/

/**
* Return the "NbResets" property.
* This method is not a Getter in the JMX sense because it
* is not exposed in the "SimpleStandardMBean" interface.
*
* @return the current value of the "NbResets" property.
*/
public int getNbResets() {
return nbResets;
}

/**
* Returns an array indicating, for each notification this MBean
* may send, the name of the Java class of the notification and
* the notification type.</p>
*
* @return the array of possible notifications.
*/
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.")
};
}

/*
* -----------------------------------------------------
* ATTRIBUTES ACCESSIBLE FOR MANAGEMENT BY A JMX AGENT
* -----------------------------------------------------
*/

private String state = "initial state";
private int nbChanges = 0;

/*
* -----------------------------------------------------
* PROPERTY NOT ACCESSIBLE FOR MANAGEMENT BY A JMX AGENT
* -----------------------------------------------------
*/

private int nbResets = 0;
}

examples/Security/subject_delegation/mbeans/SimpleStandardMBean.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* This is the management interface explicitly defined for the
* "SimpleStandard" standard MBean.
*
* The "SimpleStandard" standard MBean implements this interface
* in order to be manageable through a JMX agent.
*
* The "SimpleStandardMBean" interface shows how to expose for management:
* - a read/write attribute (named "State") through its getter and setter
*   methods,
* - a read-only attribute (named "NbChanges") through its getter method,
* - an operation (named "reset").
*/
public interface SimpleStandardMBean {

/**
* Getter: set the "State" attribute of the "SimpleStandard" standard
* MBean.
*
* @return the current value of the "State" attribute.
*/
public String getState();

/**
* Setter: set the "State" attribute of the "SimpleStandard" standard
* MBean.
*
* @param <VAR>s</VAR> the new value of the "State" attribute.
*/
public void setState(String s);

/**
* Getter: get the "NbChanges" attribute of the "SimpleStandard" standard
* MBean.
*
* @return the current value of the "NbChanges" attribute.
*/
public int getNbChanges();

/**
* Operation: reset to their initial values the "State" and "NbChanges"
* attributes of the "SimpleStandard" standard MBean.
*/
public void reset();
}

24 詳細なセキュリティ

接続を保護するために存在するJMX API。この例では、次を含む、詳細なセキュリティの実装を提供します。

- README file

- Server

- Client

- ClientListener

- keystore

- password.properties

- truststore

- java.policy

- SimpleStandard

- SimpleStandardMBean

examples/Security/fine_grained/README

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
#

# ==============================================================================
#
#  Example of a secure RMI connector (using Security Manager and Policy File).
#
#  This example uses:
#
#  - the RMI SSL socket factories for encryption,
#  - the password authenticator based on the JMXAuthenticator interface for
#    user authentication,
#  - the JAAS and the J2SE Security Architecture based on the use of security
#    managers and policy files for user access level authorization.
#
# ==============================================================================
#
# In order to compile and run the example, make a copy of this README file, and
# then simply cut and paste all the commands as needed into a terminal window.
#
# This README makes the assumption that you are running under Java SE 6 on Unix,
# you are familiar with the JMX technology, and with the bourne shell or korn
# shell syntax.
#
# All the commands below are defined using Unix korn shell syntax.
#
# If you are not running Unix and korn shell you are expected to be able to
# adapt these commands to your favorite OS and shell environment.
#

# Compile Java classes
#
# * Server.java: creates an MBeanServer and creates and starts a secure RMI
#                connector server (JRMP).
#
# * Client.java: creates a secure RMI connector (JRMP), creates and registers
#                a Simple standard MBean and performs operations on it.
#
# * ClientListener.java: implements a generic notification listener.
#
# * SimpleStandard.java: implements the Simple standard MBean.
#
# * SimpleStandardMBean.java: the management interface exposed by the Simple
#                             standard MBean.
#

javac mbeans/SimpleStandard.java \
mbeans/SimpleStandardMBean.java \
server/Server.java \
client/Client.java \
client/ClientListener.java

# Start the RMI registry:
#

export CLASSPATH=server ; rmiregistry 9999 &

# Start the Server:
#

java -classpath server:mbeans \
-Djavax.net.ssl.keyStore=config/keystore \
-Djavax.net.ssl.keyStorePassword=password \
-Djava.security.manager \
-Djava.security.policy=config/java.policy \
Server &

# Start the Client:
#

java -classpath client:server:mbeans \
-Djavax.net.ssl.trustStore=config/truststore \
-Djavax.net.ssl.trustStorePassword=trustword \
Client

# ==============================================================================

examples/Security/fine_grained/server/Server.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import java.io.File;
import java.util.HashMap;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnectorServer;
import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;

public class Server {

public static void main(String[] args) {
try {
// Instantiate the MBean server
//
System.out.println("\nCreate the MBean server");
MBeanServer mbs = MBeanServerFactory.createMBeanServer();

// Environment map
//
System.out.println("\nInitialize the environment map");
HashMap env = new HashMap();

// Provide SSL-based RMI socket factories.
//
SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory();
env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,csf);
env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,ssf);

// Provide the password file used by the connector server to
// perform user authentication. The password file is a properties
// based text file specifying username/password pairs. This
// properties based password authenticator has been implemented
// using the JMXAuthenticator interface and is passed to the
// connector through the "jmx.remote.authenticator" property
// in the map.
//
// This property is implementation-dependent and might not be
// supported by all implementations of the JMX Remote API.
//
env.put("jmx.remote.x.password.file",
"config" + File.separator + "password.properties");

// Create an RMI connector server
//
System.out.println("\nCreate an RMI connector server");
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);

// Start the RMI connector server
//
System.out.println("\nStart the RMI connector server");
cs.start();
System.out.println("\nRMI connector server successfully started");
System.out.println("\nWaiting for incoming connections...");
} catch (Exception e) {
e.printStackTrace();
}
}
}

examples/Security/fine_grained/client/Client.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import java.util.HashMap;
import javax.management.Attribute;
import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

public class Client {

public static void main(String[] args) {
try {
// Environment map
//
System.out.println("\nInitialize the environment map");
HashMap env = new HashMap();

// Provide the credentials required by the server to successfully
// perform user authentication
//
String[] credentials = new String[] { "username" , "password" };
env.put("jmx.remote.credentials", credentials);

// Create an RMI connector client and
// connect it to the RMI connector server
//
System.out.println("\nCreate an RMI connector client and " +
"connect it to the RMI connector server");
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnector jmxc = JMXConnectorFactory.connect(url, env);

// Get an MBeanServerConnection
//
System.out.println("\nGet an MBeanServerConnection");
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();

// Get domains from MBeanServer
//
System.out.println("\nDomains:");
String domains[] = mbsc.getDomains();
for (int i = 0; i < domains.length; i++) {
System.out.println("\tDomain[" + i + "] = " + domains[i]);
}

// Create SimpleStandard MBean
//
ObjectName mbeanName = new ObjectName("MBeans:type=SimpleStandard");
System.out.println("\nCreate SimpleStandard MBean...");
mbsc.createMBean("SimpleStandard", mbeanName, null, null);

// Get MBean count
//
System.out.println("\nMBean count = " + mbsc.getMBeanCount());

// Get State attribute
//
System.out.println("\nState = " +
mbsc.getAttribute(mbeanName, "State"));

// Set State attribute
//
mbsc.setAttribute(mbeanName,
new Attribute("State", "changed state"));

// Get State attribute
//
// Another way of interacting with a given MBean is through a
// dedicated proxy instead of going directly through the MBean
// server connection
//
SimpleStandardMBean proxy = JMX.newMBeanProxy(
mbsc, mbeanName, SimpleStandardMBean.class);
System.out.println("\nState = " + proxy.getState());

// Add notification listener on SimpleStandard MBean
//
ClientListener listener = new ClientListener();
System.out.println("\nAdd notification listener...");
mbsc.addNotificationListener(mbeanName, listener, null, null);

// Invoke "reset" in SimpleStandard MBean
//
// Calling "reset" makes the SimpleStandard MBean emit a
// notification that will be received by the registered
// ClientListener.
//
System.out.println("\nInvoke reset() in SimpleStandard MBean...");
mbsc.invoke(mbeanName, "reset", null, null);

// Sleep for 2 seconds in order to have time to receive the
// notification before removing the notification listener.
//
System.out.println("\nWaiting for notification...");
Thread.sleep(2000);

// Remove notification listener on SimpleStandard MBean
//
System.out.println("\nRemove notification listener...");
mbsc.removeNotificationListener(mbeanName, listener);

// Unregister SimpleStandard MBean
//
System.out.println("\nUnregister SimpleStandard MBean...");
mbsc.unregisterMBean(mbeanName);

// Close MBeanServer connection
//
System.out.println("\nClose the connection to the server");
jmxc.close();
System.out.println("\nBye! Bye!");
} catch (Exception e) {
e.printStackTrace();
}
}
}

examples/Security/fine_grained/client/ClientListener.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import javax.management.Notification;
import javax.management.NotificationListener;

public class ClientListener implements NotificationListener {
public void handleNotification(Notification notification, Object handback) {
System.out.println("\nReceived notification: " + notification);
}
}

examples/Security/fine_grained/config/password.properties

#
# Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
#

# password.properties

# Password file for Remote JMX API authentication. This file defines
# the different roles and their passwords.

# The file format for the password file is syntactically the same as
# the Properties file format. The syntax is described in the Javadoc
# for java.util.Properties.load.

# A typical password file has multiple lines, where each line is blank,
# a comment (like this one), or a password entry.

# A password entry consists of a role name and an associated password.
# The role name is any string that does not itself contain spaces or
# tabs. The password is again any string that does not contain spaces
# or tabs. Note that passwords appear in the clear in this file, so it
# is a good idea not to use valuable passwords.

# A given role should have at most one entry in this file. If a role
# has no entry, it has no access.
# If multiple entries are found for the same role name, then the last
# one is used.

# In a typical installation, this file can be read by anybody on the
# local machine, and possibly by people on other machines.
# For security, you should either restrict the access to this file,
# or specify another, less accessible file in the management config
# file as described above.

# Role and password used for authentication by the RMI connector in
# this example.
#
username password

examples/Security/fine_grained/config/java.policy

grant codeBase "file:server" {
//
// The server requires the permissions to create and register the connector
// and all the permissions required by the operations performed by remote
// user calls. Here AllPermission is granted for simplicity.
//
permission java.security.AllPermission;
};

grant codeBase "file:mbeans" {
permission javax.management.MBeanTrustPermission "register";
};

grant principal javax.management.remote.JMXPrincipal "username" {
permission javax.management.MBeanPermission "*", "getDomains";
permission javax.management.MBeanPermission "SimpleStandard#-[-]", "instantiate";
permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "registerMBean";
permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute";
permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute";
permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener";
permission javax.management.MBeanPermission "SimpleStandard#reset[MBeans:type=SimpleStandard]", "invoke";
permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "removeNotificationListener";
permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean";
//
// This permission is only required for the authenticated user and not for the delegated users.
//
// The RMI connector client registers a listener on the MBeanServerDelegate to control the MBean
// creation/deletion. The listener is removed when the connection to the server is closed.
//
permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener";
permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener";
};

examples/Security/fine_grained/mbeans/SimpleStandard.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* Simple definition of a standard MBean, named "SimpleStandard".
*
* The "SimpleStandard" standard MBean shows how to expose attributes
* and operations for management by implementing its corresponding
* "SimpleStandardMBean" management interface.
*
* This MBean has two attributes and one operation exposed
* for management by a JMX agent:
*      - the read/write "State" attribute,
*      - the read only "NbChanges" attribute,
*      - the "reset()" operation.
*
* This object also has one property and one method not exposed
* for management by a JMX agent:
*      - the "NbResets" property,
*      - the "getNbResets()" method.
*/

import javax.management.AttributeChangeNotification;
import javax.management.MBeanNotificationInfo;
import javax.management.NotificationBroadcasterSupport;

public class SimpleStandard
extends NotificationBroadcasterSupport
implements SimpleStandardMBean {

/*
* -----------------------------------------------------
* CONSTRUCTORS
* -----------------------------------------------------
*/

/* "SimpleStandard" does not provide any specific constructors.
* However, "SimpleStandard" is JMX compliant with regards to
* contructors because the default contructor SimpleStandard()
* provided by the Java compiler is public.
*/

/*
* -----------------------------------------------------
* IMPLEMENTATION OF THE SimpleStandardMBean INTERFACE
* -----------------------------------------------------
*/

/**
* Getter: get the "State" attribute of the "SimpleStandard" standard MBean.
*
* @return the current value of the "State" attribute.
*/
public String getState() {
return state;
}

/**
* Setter: set the "State" attribute of the "SimpleStandard" standard MBean.
*
* @param <VAR>s</VAR> the new value of the "State" attribute.
*/
public void setState(String s) {
state = s;
nbChanges++;
}

/**
* Getter: get the "NbChanges" attribute of the "SimpleStandard" standard
* MBean.
*
* @return the current value of the "NbChanges" attribute.
*/
public int getNbChanges() {
return nbChanges;
}

/**
* Operation: reset to their initial values the "State" and "NbChanges"
* attributes of the "SimpleStandard" standard MBean.
*/
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);
}

/*
* -----------------------------------------------------
* METHOD NOT EXPOSED FOR MANAGEMENT BY A JMX AGENT
* -----------------------------------------------------
*/

/**
* Return the "NbResets" property.
* This method is not a Getter in the JMX sense because it
* is not exposed in the "SimpleStandardMBean" interface.
*
* @return the current value of the "NbResets" property.
*/
public int getNbResets() {
return nbResets;
}

/**
* Returns an array indicating, for each notification this MBean
* may send, the name of the Java class of the notification and
* the notification type.</p>
*
* @return the array of possible notifications.
*/
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.")
};
}

/*
* -----------------------------------------------------
* ATTRIBUTES ACCESSIBLE FOR MANAGEMENT BY A JMX AGENT
* -----------------------------------------------------
*/

private String state = "initial state";
private int nbChanges = 0;

/*
* -----------------------------------------------------
* PROPERTY NOT ACCESSIBLE FOR MANAGEMENT BY A JMX AGENT
* -----------------------------------------------------
*/

private int nbResets = 0;
}

examples/Security/fine_grained/mbeans/SimpleStandardMBean.java

/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   - Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   - Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*
*   - Neither the name of Oracle or the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**
* This is the management interface explicitly defined for the
* "SimpleStandard" standard MBean.
*
* The "SimpleStandard" standard MBean implements this interface
* in order to be manageable through a JMX agent.
*
* The "SimpleStandardMBean" interface shows how to expose for management:
* - a read/write attribute (named "State") through its getter and setter
*   methods,
* - a read-only attribute (named "NbChanges") through its getter method,
* - an operation (named "reset").
*/
public interface SimpleStandardMBean {

/**
* Getter: set the "State" attribute of the "SimpleStandard" standard
* MBean.
*
* @return the current value of the "State" attribute.
*/
public String getState();

/**
* Setter: set the "State" attribute of the "SimpleStandard" standard
* MBean.
*
* @param <VAR>s</VAR> the new value of the "State" attribute.
*/
public void setState(String s);

/**
* Getter: get the "NbChanges" attribute of the "SimpleStandard" standard
* MBean.
*
* @return the current value of the "NbChanges" attribute.
*/
public int getNbChanges();

/**
* Operation: reset to their initial values the "State" and "NbChanges"
* attributes of the "SimpleStandard" standard MBean.
*/
public void reset();
}

Oracleの法律上の注意点

コピーライト

Copyright © 1994-2018, Oracle and/or its affiliates. All rights reserved.

ライセンス制約の保証と結果的に生じる損害の免責

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

保証免責

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクルまでご連絡ください。

制限付権利について

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs. No other rights are granted to the U.S. Government.

危険な用途への使用について

このソフトウェアまたはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアまたはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用する際、安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、Oracle Corporationおよびその関連会社は一切の責任を負いかねます。

商標と登録商標について

OracleおよびJavaはオラクルおよびその関連会社の登録商標です。その他の社名、商品名等は各社の商標または登録商標である場合があります。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXは、The Open Groupの登録商標です。

第三者のコンテンツ、製品、サービスに対する免責事項

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。適用されるお客様とOracle Corporationとの間の契約に別段の定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。適用されるお客様とOracle Corporationとの間の契約に定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

Pre-General Availability (一般提供前)版のドキュメントについて

このドキュメントがPre-General Availability (一般提供前)版の場合:

このドキュメントはPre-General Availability (一般提供前)版であり、デモおよび暫定使用のみを目的としたものです。このソフトウェアを使用するハードウェアに限定するものではありません。Oracle Corporationおよびその関連会社は、このドキュメントに関して一切の責任を負わず、いかなる保証もいたしません。また、このドキュメントを使用したことによって損失、費用、あるいは損害が発生しても、一切の責任を負いかねます。

非公開のPre-General Availability (一般提供前)版のドキュメントについて

このドキュメントが非公開のPre-General Availability (一般提供前)版の場合:

このドキュメントに含まれる情報は、情報の共有のみを目的としたものであって、顧客諮問委員会(Customer Advisory Board)のメンバーとしてのお客様の立場でのみ、またはお客様のPre-General Availability Trial Agreement (Pre-GAトライアル契約)のみに従って検討されるべきものとします。マテリアル、コード、または機能の提供をお約束するものではなく、購入決定を行う際の判断材料とすべきではありません。このドキュメントに記載されている特徴または機能の開発、リリースおよび時期については、オラクルの裁量により決定されます。

このドキュメントには、ソフトウェアまたは印刷物などの形式を問わず、オラクルが独占的な権利を有する財産的情報が含まれています。この機密資料へのアクセスと使用は、お客様とオラクルとの間で締結され、お客様が遵守に同意した、Oracle Master Agreement、Oracle License and Oracle Services Agreement (オラクル・ライセンスおよびサービスに関する契約書)、Oracle Partner Network Agreement、Oracle Distribution Agreementまたはその他のライセンス契約の条件に従うものとします。このドキュメントとその内容の開示、コピー、複製および配布には、オラクルによる事前の承諾を必要とします。このドキュメントはライセンス契約の一部となるものではなく、オラクルおよびその子会社や関連会社との契約を構成するものではありません。

ドキュメントのアクセシビリティ

オラクルのアクセシビリティについての詳細情報は、Oracle Accessibility ProgramのWebサイト(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc)を参照してください。

Oracle Supportへのアクセス

サポートをご契約のお客様には、My Oracle Supportを通して電子支援サービスを提供しています。詳細情報は(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=info)か、聴覚に障害のあるお客様は(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs)を参照してください。