■WLS 12.2.1.2.0 にて管理対象サーバをリモートで起動しようとした際、以下のエラーが発生しました。
---
####<2017/04/03, 2:13:20,253 午後 JST> <Critical> <WebLogicServer> <xxxx> <Server-0> <main> <<WLS Kernel>> <> <> <1491196400253>
<[severity-value: 4] [partition-id: 0] [partition-name: DOMAIN] >
<BEA-000386> <サーバー・サブシステムに障害が発生しました。理由: A MultiException has 2 exceptions. They are:
1. weblogic.ldap.EmbeddedLDAPException: Empty initial replica
2. java.lang.IllegalStateException: Unable to perform operation: post construct on weblogic.ldap.PreEmbeddedLDAPService
A MultiException has 2 exceptions. They are:
1. weblogic.ldap.EmbeddedLDAPException: Empty initial replica
2. java.lang.IllegalStateException: Unable to perform operation: post construct on weblogic.ldap.PreEmbeddedLDAPService
at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:391)
・・・
-----
■Linux側のOS時刻を合わせることで解消しました。
■発生した環境は以下の通り
管理サーバ:Windows10
管理対象サーバ: Linux(centOS 7)
以下の操作で発生しました。
1. Windows10 、Linux 双方に WLS 12c をインストール
2. Windows10 側にてWLSドメインを作成。管理サーバ、管理対象サーバ(Server-0)を構成
3. Windows10 側にて WLSドメインを pack -managed=true でパック後、Linux 側で unpack。
4. Windows10 側で管理サーバを起動
5. Linux にて $DOMAIN_HOME/bin/startManagedWebLogic.sh Server-0 で起動するとエラー
管理サーバ側には BEA-141149 が出力されます。
----
<2017/05/06, 12:11:49,316 午前 JST> <Error> <Management> <BEA-141149>
<salt m67t55TnLIR/hoG8KV9hvg==、シグネチャRwbmB0APaH95Hr9Y14INaAjBKNP1wm3Sv5FvS/TaOms=の
管理サーバーへ接続しようとする無効な試みが行われました。
おそらく、秘密鍵が一致していないことが原因です。>
----
■原因は筐体間の時刻に著しいずれがあることでした。以下の ディスカッションの通りです。
<BEA-141149> <An invalid attempt was made to connect to the
https://community.oracle.com/thread/3894372
====
14. Re: <BEA-141149> <An invalid attempt was made to connect to the
ksunil
Newbie
ksunil 2016/02/17 13:22 (ksunil への返信)
This is now resolved. There was nothing wrong with the scripts.
Apparently, the clocks on these 2 Linux boxes were apart (4 minutes) and that triggers something internally. Suggestion came from Oracle support
====
2017年5月6日土曜日
2017年1月29日日曜日
Bytemanチュートリアル(日本語意訳)
稼働中に Byteman エージェントをあとからインストールする方法は?
Byteman (http://byteman.jboss.org/docs.html)のチュートリアルを日本語意訳したものです。
実行中のプログラムをチェックするために Byteman を利用する際、Byteman エージェントをロードせずに実行していたことに気づくことがあります。例えば JBoss アプリケーションサーバのようなプログラムを長時間稼働中、何か問題だ生じたことがログに出力されていた場合などです。
少なくとも Hotspot、JRockit、OpenJDK JVM で実行してたなら、Byteman を使用するために稼働中のプログラムを再起動する必要はありません。これらのJVM の場合、稼働中のプログラムにByteman エージェントを動的に追加インストールすることができます。
Linux なら bminstall.sh スクリプトを利用します。
-----
> bminstall.sh 13101
>
-----
すべての JVM で、動的なエージェントのロードができるわけではありません。
Linux では、Oracle JVM 、OpenJDK、JRockit が、macOSX では OracleJVM と OpenJDK ならできます。
IBM JVM や Windows 上でのその他 JVM で可能かは不明です。
Windows も bminstall.bat を利用します。(リリース 2.0.1 以降)
2.0.1 以前の場合 Install.main() を必要な引数を指定して実行します。
-----
> java -classpath %BYTEMAN_HOME%\lib\byteman-install.jar org.jboss.byteman.agent.install.Install 13101
>
-----
上記の数値(13101)の箇所には、Byteman エージェントをインストールする JVM のプロセスIDを指定します。
チェックしたい稼働中の Java プログラムのその時点の PID を指定する必要があります。(PIDの確認は $JAVAHOME/bin/jps を使うと便利です。)
また、稼働中のJavaプログラムの main クラス名を指定することもできます。(jar コマンド($java -jar myapp.jar)のように起動した場合は、jar名を指定することもできます。)
bminstall.sh は、稼働中の JBoss アプリケーション・サーバ・インスタンスに Byteman エージェントをインストールするのに非常に便利です。AppMain3 を -javaagent オプションなしで再度実行し、稼働後に Byteman エージェントとルール・スクリプトを読み込ませてみましょう。
-javaagent オプションなしで起動しておきます。
-----
> java org.my.AppMain3
foo
foo
bar
bar
-----
別のコマンドシェルでエージェントをインストールします。
<Linux>
-----
> bminstall.sh -b -Dorg.jboss.byteman.transform.all org.my.AppMain3
>
-----
bminstall コマンドはルール・スクリプトのロードはできませんが、エージェント・リスナーを自動的に有効にでき、さらに bmsubmt.sh でルールを送信できます。再度 bmsubmit コマンドで thread.btm ルールを送信すると AppMain3 の動作が途中から変更されたことが確認できます。
実行中のプログラムをチェックするために Byteman を利用する際、Byteman エージェントをロードせずに実行していたことに気づくことがあります。例えば JBoss アプリケーションサーバのようなプログラムを長時間稼働中、何か問題だ生じたことがログに出力されていた場合などです。
少なくとも Hotspot、JRockit、OpenJDK JVM で実行してたなら、Byteman を使用するために稼働中のプログラムを再起動する必要はありません。これらのJVM の場合、稼働中のプログラムにByteman エージェントを動的に追加インストールすることができます。
Linux なら bminstall.sh スクリプトを利用します。
-----
> bminstall.sh 13101
>
-----
すべての JVM で、動的なエージェントのロードができるわけではありません。
Linux では、Oracle JVM 、OpenJDK、JRockit が、macOSX では OracleJVM と OpenJDK ならできます。
IBM JVM や Windows 上でのその他 JVM で可能かは不明です。
Windows も bminstall.bat を利用します。(リリース 2.0.1 以降)
2.0.1 以前の場合 Install.main() を必要な引数を指定して実行します。
-----
> java -classpath %BYTEMAN_HOME%\lib\byteman-install.jar org.jboss.byteman.agent.install.Install 13101
>
-----
上記の数値(13101)の箇所には、Byteman エージェントをインストールする JVM のプロセスIDを指定します。
チェックしたい稼働中の Java プログラムのその時点の PID を指定する必要があります。(PIDの確認は $JAVAHOME/bin/jps を使うと便利です。)
また、稼働中のJavaプログラムの main クラス名を指定することもできます。(jar コマンド($java -jar myapp.jar)のように起動した場合は、jar名を指定することもできます。)
bminstall.sh は、稼働中の JBoss アプリケーション・サーバ・インスタンスに Byteman エージェントをインストールするのに非常に便利です。AppMain3 を -javaagent オプションなしで再度実行し、稼働後に Byteman エージェントとルール・スクリプトを読み込ませてみましょう。
-javaagent オプションなしで起動しておきます。
-----
> java org.my.AppMain3
foo
foo
bar
bar
-----
別のコマンドシェルでエージェントをインストールします。
<Linux>
-----
> bminstall.sh -b -Dorg.jboss.byteman.transform.all org.my.AppMain3
>
-----
bminstall コマンドはルール・スクリプトのロードはできませんが、エージェント・リスナーを自動的に有効にでき、さらに bmsubmt.sh でルールを送信できます。再度 bmsubmit コマンドで thread.btm ルールを送信すると AppMain3 の動作が途中から変更されたことが確認できます。
Bytemanチュートリアル(日本語意訳)
ルールのアンロード方法
Byteman (http://byteman.jboss.org/docs.html)のチュートリアルを日本語意訳したものです。
bmsubmit.sh でルールをアンロードして、AppMain3 の Thread.start() メソッドをオリジナルの動作に戻すことができます。
-----
> bmsubmit.sh -u thread.btm
uninstall RULE trace thread start
> bmsubmit.sh
no rules installed
-----
-u オプションの後にルール・スクリプト名を指定します。指定したルールスクリプト内のすべてのルールがアンロードされ、メソッドに注入されたコードが削除されます。
AppMain3 が、入力テキストを繰り返すのみの最初の動作に戻りました。
-----
. . .
mumble
*** start for thread: mumble
mumble
grumble
grumble
bletch
bletch
end
>
-----
ルール・スクリプトの注入コードのみ変更したいなら、ルールのアンロード、リロードは必要ありません。ルール・スクリプトを修正して再度 submit すれば、Byteman は既存の注入コードを削除し新しいコードを再注入します。
bmsubmit.sh でルールをアンロードして、AppMain3 の Thread.start() メソッドをオリジナルの動作に戻すことができます。
-----
> bmsubmit.sh -u thread.btm
uninstall RULE trace thread start
> bmsubmit.sh
no rules installed
-----
-u オプションの後にルール・スクリプト名を指定します。指定したルールスクリプト内のすべてのルールがアンロードされ、メソッドに注入されたコードが削除されます。
AppMain3 が、入力テキストを繰り返すのみの最初の動作に戻りました。
-----
. . .
mumble
*** start for thread: mumble
mumble
grumble
grumble
bletch
bletch
end
>
-----
ルール・スクリプトの注入コードのみ変更したいなら、ルールのアンロード、リロードは必要ありません。ルール・スクリプトを修正して再度 submit すれば、Byteman は既存の注入コードを削除し新しいコードを再注入します。
Bytemanチュートリアル(日本語意訳)
どのルールがロードされコンパイルされたか確認したいんですが?
Byteman (http://byteman.jboss.org/docs.html)のチュートリアルを日本語意訳したものです。
bmsubmit.sh を再度実行するとルールが正常にコンパイルされていることが確認できます。
-----
> bmsubmit.sh
# File thread.btm line 4
RULE trace thread start
CLASS java.lang.Thread
METHOD start()
AT ENTRY
IF true
DO traceln("*** start for thread: "+ $0.getName())
ENDRULE
Transformed in:
loader: sun.misc.Launcher$AppClassLoader@5acac268
trigger method: java.lang.Thread.start() void
compiled successfully
>
-----
「compiled successfully.」と出力されています。これはルールの型チェックに成功し適用されたことを意味します。
ルールが最初にトリガーされたときに型チェックを行った場合([baz]を含む行をタイプした後)は、
型チェック失敗するとコード注入は実行されずに失敗した詳細が出力されます。
注入されたコードはルールがアンロードされたときのみ削除されます。
bmsubmit.sh を再度実行するとルールが正常にコンパイルされていることが確認できます。
-----
> bmsubmit.sh
# File thread.btm line 4
RULE trace thread start
CLASS java.lang.Thread
METHOD start()
AT ENTRY
IF true
DO traceln("*** start for thread: "+ $0.getName())
ENDRULE
Transformed in:
loader: sun.misc.Launcher$AppClassLoader@5acac268
trigger method: java.lang.Thread.start() void
compiled successfully
>
-----
「compiled successfully.」と出力されています。これはルールの型チェックに成功し適用されたことを意味します。
ルールが最初にトリガーされたときに型チェックを行った場合([baz]を含む行をタイプした後)は、
型チェック失敗するとコード注入は実行されずに失敗した詳細が出力されます。
注入されたコードはルールがアンロードされたときのみ削除されます。
Bytemanチュートリアル(日本語意訳)
実行中のプログラムにルールを動的適用する方法は?
Byteman (http://byteman.jboss.org/docs.html)のチュートリアルを日本語意訳したものです。
長時間動くプログラムの場合、プログラム実行後にルールをロードしたり、ルールの再ロードをしたいことがあります。これらは Byteman にエージェント・リスナーを起動されば可能になります。エージェント・リスナーはルールのロード状況の確認もできます。
AppMain3 を使って、リスナーの動作を確認しましょう。
----- AppMain3.java -----
package org.my;
import java.io.DataInputStream;
class AppMain3 {
public static void main(String[] args) {
try {
DataInputStream in = new DataInputStream(System.in);
String next = in.readLine();
while (next != null && next.length() > 0 && !next.contains("end")) {
final String arg = next;
Thread thread = new Thread(arg) {
public void run() {
System.out.println(arg);
}
};
thread.start();
try {
thread.join();
} catch (Exception e){ }
next = in.readLine();
}
} catch (Exception e) {}
}
}
-----
AppMain3 は入力されたテキストをそのまま出力します。"end" 文字列、または EOF が入力されると止まります。Byteman エージェント・リスナーと一緒に AppMain3 を起動すると、AppMain3 の読み込み待機中にルールのロード/アンロードができます。またプログラムに解析され注入されたルールの型チェックや実行された状態チェックもできます。
エージェント・リスナーを有効にするには、エージェント・オプション「listener:true」を使います。
<Linux>
-----
$ java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=listener:true,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain3
-----
<Windows>
-----
> java -javaagent:%BYTEMAN_HOME%\lib\byteman.jar=listener:true,boot:%BYTEMAN_HOME%\lib\byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain3
-----
エージェント・リスナーは通信口(サーバー・ソケット)を開いてコマンド入力を待ちます。エージェント・オプションにルールスクリプトが指定しなかったので、まずは入力内容が繰り返されるのみです(★)。
----- 実行例 ---
> java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=listener:true,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain3
foo
foo --★
bar
bar --★
-----
<Linux>
エージェント・リスナーに処理させる際は bmsubmit.sh を使います。bmsubmit.sh を引数なしで実行すると、インストールされているルールをすべて表示します。
-----
> bmsubmit.sh
no rules installed
>
(※現在、ルール未インストール)
-----
※ bmsubmit.sh は別シェルを立ち上げ実行してください。また、AppMain3 は先に起動すして、 bmsubmit.sh と Byteman エージェントがサーバーソケットを経由して対話できるようしておきます。
<Windows>
bmsubmit.bat を実行します。(Byteman リリース 2.0.1 以降)
-----
> bmsubmit
no rules installed
>
(※現在、ルール未インストール)
-----
(2.0.1 以前のリリースは、リスナーにコマンドを送信するために Java コマンドで Submit クラスを呼び出す必要があります。)
-----
> java -classpath %BYTEMAN_HOME%\lib\byteman-submit.jar org.jboss.byteman.agent.submit.Submit
no rules installed
>
-----
次に bmsubmit.sh を使って実行中のプログラムにルール・スクリプトをロードします。
<Linux>
-----
> bmsubmit.sh -l thread.btm
install rule trace thread start
>
(※ルール・スクリプト trace がインストールされました。)
-----
<Windows>
bmsubmit.bat を使います。
(リリース 2.0.1 以前は、Submitクラスに -l 引数を付与して実行します。
-----
> java -classpath %BYTEMAN_HOME%\lib\byteman-submit.jar org.jboss.byteman.agent.submit.Submit -l thread.btm
install rule trace thread start
>
(※ルール・スクリプト trace がインストールされました。)
-----
インストールされたルールのステータスを再確認すれば、ルールがロードされ解析されて Thread.start() メソッドに注入されていることが確認できます。もしルールの完全な解析に失敗した場合は、注入が阻止されたことと詳細を含む解析エラーが出力されます。
-----解析エラー-----
> bmsubmit.sh
# File thread.btm line 4
RULE trace thread start
CLASS java.lang.Thread
METHOD start()
AT ENTRY
IF true
DO traceln("*** start for thread: "+ $0.getName())
ENDRULE
Transformed in:
loader: sun.misc.Launcher$AppClassLoader@5acac268
trigger method: java.lang.Thread.start() void
>
-----
実行中のAppMain3で入力を進めるとルールが実行されたことが確認できます。
-----
. . .
bar
bar
baz
*** start for thread: baz
baz
mumble
*** start for thread: mumble
mumble
-----
長時間動くプログラムの場合、プログラム実行後にルールをロードしたり、ルールの再ロードをしたいことがあります。これらは Byteman にエージェント・リスナーを起動されば可能になります。エージェント・リスナーはルールのロード状況の確認もできます。
AppMain3 を使って、リスナーの動作を確認しましょう。
----- AppMain3.java -----
package org.my;
import java.io.DataInputStream;
class AppMain3 {
public static void main(String[] args) {
try {
DataInputStream in = new DataInputStream(System.in);
String next = in.readLine();
while (next != null && next.length() > 0 && !next.contains("end")) {
final String arg = next;
Thread thread = new Thread(arg) {
public void run() {
System.out.println(arg);
}
};
thread.start();
try {
thread.join();
} catch (Exception e){ }
next = in.readLine();
}
} catch (Exception e) {}
}
}
-----
AppMain3 は入力されたテキストをそのまま出力します。"end" 文字列、または EOF が入力されると止まります。Byteman エージェント・リスナーと一緒に AppMain3 を起動すると、AppMain3 の読み込み待機中にルールのロード/アンロードができます。またプログラムに解析され注入されたルールの型チェックや実行された状態チェックもできます。
エージェント・リスナーを有効にするには、エージェント・オプション「listener:true」を使います。
<Linux>
-----
$ java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=listener:true,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain3
-----
<Windows>
-----
> java -javaagent:%BYTEMAN_HOME%\lib\byteman.jar=listener:true,boot:%BYTEMAN_HOME%\lib\byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain3
-----
エージェント・リスナーは通信口(サーバー・ソケット)を開いてコマンド入力を待ちます。エージェント・オプションにルールスクリプトが指定しなかったので、まずは入力内容が繰り返されるのみです(★)。
----- 実行例 ---
> java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=listener:true,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain3
foo
foo --★
bar
bar --★
-----
<Linux>
エージェント・リスナーに処理させる際は bmsubmit.sh を使います。bmsubmit.sh を引数なしで実行すると、インストールされているルールをすべて表示します。
-----
> bmsubmit.sh
no rules installed
>
(※現在、ルール未インストール)
-----
※ bmsubmit.sh は別シェルを立ち上げ実行してください。また、AppMain3 は先に起動すして、 bmsubmit.sh と Byteman エージェントがサーバーソケットを経由して対話できるようしておきます。
<Windows>
bmsubmit.bat を実行します。(Byteman リリース 2.0.1 以降)
-----
> bmsubmit
no rules installed
>
(※現在、ルール未インストール)
-----
(2.0.1 以前のリリースは、リスナーにコマンドを送信するために Java コマンドで Submit クラスを呼び出す必要があります。)
-----
> java -classpath %BYTEMAN_HOME%\lib\byteman-submit.jar org.jboss.byteman.agent.submit.Submit
no rules installed
>
-----
次に bmsubmit.sh を使って実行中のプログラムにルール・スクリプトをロードします。
<Linux>
-----
> bmsubmit.sh -l thread.btm
install rule trace thread start
>
(※ルール・スクリプト trace がインストールされました。)
-----
<Windows>
bmsubmit.bat を使います。
(リリース 2.0.1 以前は、Submitクラスに -l 引数を付与して実行します。
-----
> java -classpath %BYTEMAN_HOME%\lib\byteman-submit.jar org.jboss.byteman.agent.submit.Submit -l thread.btm
install rule trace thread start
>
(※ルール・スクリプト trace がインストールされました。)
-----
インストールされたルールのステータスを再確認すれば、ルールがロードされ解析されて Thread.start() メソッドに注入されていることが確認できます。もしルールの完全な解析に失敗した場合は、注入が阻止されたことと詳細を含む解析エラーが出力されます。
-----解析エラー-----
> bmsubmit.sh
# File thread.btm line 4
RULE trace thread start
CLASS java.lang.Thread
METHOD start()
AT ENTRY
IF true
DO traceln("*** start for thread: "+ $0.getName())
ENDRULE
Transformed in:
loader: sun.misc.Launcher$AppClassLoader@5acac268
trigger method: java.lang.Thread.start() void
>
-----
実行中のAppMain3で入力を進めるとルールが実行されたことが確認できます。
-----
. . .
bar
bar
baz
*** start for thread: baz
baz
mumble
*** start for thread: mumble
mumble
-----
Bytemanチュートリアル(日本語意訳)
Byteman を簡単に実行する方法はないの?
Byteman (http://byteman.jboss.org/docs.html)のチュートリアルを日本語意訳したものです。
Linux では、-javaagent オプションをラップした $BYTEMAN_HOME/bin/bmjava.sh を利用できます。java コマンドのように見えますが、 ルール・スクリプトをコマンドラインオプションで渡すと、-javaagent script:<ルールスクリプト> として付与してくれます。また、自動で byteman.jar ファイルを boot:<エージェント> オプションとして付与してくれます。
bmjava.sh を使うと前項のコマンドラインを簡素化することができるのです。-l オプションでロードするスクリプトを渡します。
-----
> bmjava.sh -l thread.btm org.my.AppMain2 foo bar baz
-----
Windows には bmjava.bat という同等のスクリプトが用意されています(Byteman 2.0.1 以降)。
こちらも同様にシンプルに実行できます。
-----
> bmjava -l thread.btm org.my.AppMain2 foo bar baz
-----
スクリプト名で実行できるよう以下を path 環境変数に通しておいてください。
<Linux>
exprot path=$path:${BYTEMAN_HOME}/bin
<windows>
set path=%path%;%BYETMAN_HOME%/bin
Linux では、-javaagent オプションをラップした $BYTEMAN_HOME/bin/bmjava.sh を利用できます。java コマンドのように見えますが、 ルール・スクリプトをコマンドラインオプションで渡すと、-javaagent script:<ルールスクリプト> として付与してくれます。また、自動で byteman.jar ファイルを boot:<エージェント> オプションとして付与してくれます。
bmjava.sh を使うと前項のコマンドラインを簡素化することができるのです。-l オプションでロードするスクリプトを渡します。
-----
> bmjava.sh -l thread.btm org.my.AppMain2 foo bar baz
-----
Windows には bmjava.bat という同等のスクリプトが用意されています(Byteman 2.0.1 以降)。
こちらも同様にシンプルに実行できます。
-----
> bmjava -l thread.btm org.my.AppMain2 foo bar baz
-----
スクリプト名で実行できるよう以下を path 環境変数に通しておいてください。
<Linux>
exprot path=$path:${BYTEMAN_HOME}/bin
<windows>
set path=%path%;%BYETMAN_HOME%/bin
2017年1月5日木曜日
Bytemanチュートリアル(日本語意訳)
どうやって JVM 上のクラスにコードを注入するの?
Byteman (http://byteman.jboss.org/docs.html)のチュートリアルを日本語意訳したものです。
それでは JVM への操作をいくつか行ってみましょう。
以下のような thread.btm ルールファイルを作成してください。
----- thread.btm -----
RULE trace thread start
CLASS java.lang.Thread
METHOD start()
IF true
DO traceln("*** start for thread: "+ $0.getName())
ENDRULE
-----
このルールは JVM のランタイムクラス java.lang.Thread の start() メソッドに処理を注入しています。String 文字列とともに「+」演算子で貼り付けられたトレースメッセージを出力します。
java.lang.Thread#start() は、ある Thread インスタンスのメソッド呼び出し時に呼ばれるインスタンスメソッドです。特殊変数 $0 はこのターゲットオブジェクト自身を参照するために使います。今回の Thread#start() メソッドは引数がありませんが、ルール適用時に引数を伴って呼ばれるメソッドでであれば、その引数を $1、$2 として参照することができます。
$0 が Thread オブジェクトを参照すると認識され、$0.getName() メソッド呼び出しの際にチェックされ、結果が String 型であることが検証されます。このメソッドが呼ばれると、注入されたコードが作成され、String 定数として追加されます。traceln() メソッドに渡されて標準出力(System.out)に書き込まれます。
AppMain を少し変更した AppMain2 にルールを適用してみましょう。AppMain2 はスレッドを複数生成して System.out.println() するクラスです。
----- AppMain2.java -----
package org.my;
class AppMain2
{
public static void main(String[] args)
{
for (int i = 0; i < args.length; i++) {
final String arg = args[i];
Thread thread = new Thread(arg) {
public void run() {
System.out.println(arg);
}
};
thread.start();
try {
thread.join()
} catch (Exception e) {
}
}
}
}
-----
AppMain2 実行時に、script:<agent> オプションで thread.btm を参照させます。
ただ今回はこれだけでは不十分です。特別なオプションと引数を指定する必要があります。
<Linux の場合>
-----
> java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:thread.btm,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain2 foo bar baz
-----
<Windows の場合>
-----
> java -javaagent:%BYTEMAN_HOME%\lib\byteman.jar=script:thread.btm,boot:%BYTEMAN_HOME%\lib\byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain2 foo bar baz
-----
java.lang.Thread クラスはブートストラップ・クラスローダによってロードされます。(ブートストラップ・クラスローダとは、Java の初期クラスローダです。コア・パッケージなど根幹のクラスををロードします)
ブートストラップ・クラスローダでロードされるクラスに処理を注入する場合、Byteman エージェントクラス自体もブートストラップ・クラスローダにロードさせることが必要です。
この場合、特殊なエージェントオプション "boot:${BYTEMAN_HOME}/lib/byteman.jar" を script:<ルールスクリプト> オプションの後ろに追加します。(セパレータとしてカンマ「,」を付与します。)
これで、Byteman エージェントの jar が、ブートストラップ・クラスローダ用のクラスパスに通ります。
また、java.lang.Thread のように java.lang. に所属するようなクラスについて、Byteman ではこのような JVM を中断してしまうようなものはとても慎重に扱っており、デフォルトではコードを注入しない動作をします。このようなコア・パッケージに所属するクラス、メソッドへの変更がどうしても必要な場合、org.jboss.byteman.transform.all システムプロパティの付与が必要です。
AppMain2 を実行してみると、以下の様な出力が得られます。
-----
> java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:thread.btm,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain2 foo bar baz
*** start for thread: foo
foo
*** start for thread: bar
bar
*** start for thread: baz
baz
>
-----
それでは JVM への操作をいくつか行ってみましょう。
以下のような thread.btm ルールファイルを作成してください。
----- thread.btm -----
RULE trace thread start
CLASS java.lang.Thread
METHOD start()
IF true
DO traceln("*** start for thread: "+ $0.getName())
ENDRULE
-----
このルールは JVM のランタイムクラス java.lang.Thread の start() メソッドに処理を注入しています。String 文字列とともに「+」演算子で貼り付けられたトレースメッセージを出力します。
java.lang.Thread#start() は、ある Thread インスタンスのメソッド呼び出し時に呼ばれるインスタンスメソッドです。特殊変数 $0 はこのターゲットオブジェクト自身を参照するために使います。今回の Thread#start() メソッドは引数がありませんが、ルール適用時に引数を伴って呼ばれるメソッドでであれば、その引数を $1、$2 として参照することができます。
$0 が Thread オブジェクトを参照すると認識され、$0.getName() メソッド呼び出しの際にチェックされ、結果が String 型であることが検証されます。このメソッドが呼ばれると、注入されたコードが作成され、String 定数として追加されます。traceln() メソッドに渡されて標準出力(System.out)に書き込まれます。
AppMain を少し変更した AppMain2 にルールを適用してみましょう。AppMain2 はスレッドを複数生成して System.out.println() するクラスです。
----- AppMain2.java -----
package org.my;
class AppMain2
{
public static void main(String[] args)
{
for (int i = 0; i < args.length; i++) {
final String arg = args[i];
Thread thread = new Thread(arg) {
public void run() {
System.out.println(arg);
}
};
thread.start();
try {
thread.join()
} catch (Exception e) {
}
}
}
}
-----
AppMain2 実行時に、script:<agent> オプションで thread.btm を参照させます。
ただ今回はこれだけでは不十分です。特別なオプションと引数を指定する必要があります。
<Linux の場合>
-----
> java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:thread.btm,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain2 foo bar baz
-----
<Windows の場合>
-----
> java -javaagent:%BYTEMAN_HOME%\lib\byteman.jar=script:thread.btm,boot:%BYTEMAN_HOME%\lib\byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain2 foo bar baz
-----
java.lang.Thread クラスはブートストラップ・クラスローダによってロードされます。(ブートストラップ・クラスローダとは、Java の初期クラスローダです。コア・パッケージなど根幹のクラスををロードします)
ブートストラップ・クラスローダでロードされるクラスに処理を注入する場合、Byteman エージェントクラス自体もブートストラップ・クラスローダにロードさせることが必要です。
この場合、特殊なエージェントオプション "boot:${BYTEMAN_HOME}/lib/byteman.jar" を script:<ルールスクリプト> オプションの後ろに追加します。(セパレータとしてカンマ「,」を付与します。)
これで、Byteman エージェントの jar が、ブートストラップ・クラスローダ用のクラスパスに通ります。
また、java.lang.Thread のように java.lang. に所属するようなクラスについて、Byteman ではこのような JVM を中断してしまうようなものはとても慎重に扱っており、デフォルトではコードを注入しない動作をします。このようなコア・パッケージに所属するクラス、メソッドへの変更がどうしても必要な場合、org.jboss.byteman.transform.all システムプロパティの付与が必要です。
AppMain2 を実行してみると、以下の様な出力が得られます。
-----
> java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:thread.btm,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain2 foo bar baz
*** start for thread: foo
foo
*** start for thread: bar
bar
*** start for thread: baz
baz
>
-----
登録:
コメント (Atom)