前のトピック: Java エージェント拡張次のトピック: トランザクション フレームへのタグの追加


エージェントの拡張

com.itko.lisa.remote.transactions.interceptors.IInterceptor インターフェースを実装する Java クラス、または com.itko.lisa.remote.transactions.interceptors.AbstractInterceptor クラスを拡張する Java クラスを作成することにより、エージェントの動作をカスタマイズできます。 詳細については、インストール ディレクトリの doc フォルダで、JavaDocs を参照してください。

public interface IInterceptor {
    /**
     * このカスタム インターセプタが現在無効かどうか
     */
    public boolean isDisabled();
 
    /**
     * インターセプトが戻る(true)か続行(false)するかを返します
     */
    public boolean block(boolean wayIn, Object src, String spec, String clazz, String method, String signature, Object[] args, Object ret);
 
    /**
     * メソッドの開始後に呼び出され、インターセプタ ロジックに基づいて現在のフレームを変更する可能性があります。
     */
    public boolean preProcess(TransactionFrame frame, Object src, String spec, String clazz, String method, String signature, Object[] args, Object ret);
 
    /**
     * メソッドの終了前に呼び出され、インターセプタ ロジックに基づいて現在のフレームを変更する可能性があります
     */
    public boolean postProcess(TransactionFrame frame, Object src, String spec, String clazz, String method, String signature, Object[] args, Object ret);
}

データのキャプチャを停止する場合は、block() メソッドを上書きします。 この方法は rules.xml ファイルへの exclude ディレクティブの追加に似ていますが、より柔軟性があります。

エージェントがメソッドをキャプチャする直前にロジックを実行するようにする場合は、preProcess() メソッドを上書きします。

エージェントがメソッドをキャプチャした直後にロジックを実行するようにする場合は、postProcess() メソッドを上書きします。

これらのメソッドは、インターセプトされたか追跡されているすべてのクラスおよびメソッドに対して自動的に呼び出されます。 メソッドをインターセプトするかまたはクラスを追跡するには、rules.xml ファイルで前述の構文を使用して指定できます。 また、拡張クラスのコンストラクタでプログラムによってインターセプトを指定できます。 後の方法の利点は、拡張が自己完結型であるということです。

block() メソッドの最初の引数は boolean wayIn です。 block() メソッドは、1 つのメソッドあたり 2 回コールされます(入口で 1 回、出口で 1 回)。 入口でのコール時の wayIn 引数の値は true です。 出口でのコール時の wayIn 引数の値は false です。

以下では、block()preProcess()、および postProcess() メソッドに共通の引数について説明します。

引数

説明

Object src

メソッドがコールされているオブジェクト。

String spec

API をインスツルメントするように指定されたクラスまたはインターフェース名。

String clazz

インターセプトされたメソッドを定義するクラスの名前。

String method

インターセプトされたメソッドの名前。

String signature

インターセプトされたメソッドのシグネチャ(JVM 形式)。

Object[] args

インターセプトされたメソッドに渡される引数。

Object ret

インターセプトされたメソッドの戻り値。 wayIn 引数が true の場合、戻り値は NULL です。

srcspec、および clazz 引数の違いについては、以下の例で説明できます。

以下のインターフェースおよびクラス定義があると仮定します。

public interface A {
     void m();
}
 
public class B implements A {
     void m() {}
}
 
public class C extends B {
}

ルールで intercept("A", "m", "*") を指定し、コードが C.m() をコールする場合、以下の情報は true です。

 

展開

拡張を展開するには、拡張をコンパイルして、以下のエントリを含むマニフェストと共に JAR ファイルにパッケージ化します。

Agent-Extension: extension class name 

エージェントの JAR ディレクトリにこの JAR を配置すると、エージェントは自動的にそれを取得します。 エージェントが起動した後にファイルを追加した場合、ホット ロード メカニズムによってファイルが確実に適用されます。 エージェントの実行中に拡張 JAR を更新した場合、JAR クラスが動的に再ロードされます。 動的な再ロードにより、サーバを再起動せずに、拡張コードをすばやく簡単にテストできます。

拡張 JAR は、拡張クラスで使用されるクラスをすべて参照できるクラスローダによってロードされます。 使用するクラスを定義する LisaAgent.jar およびすべてのコンテナ JAR に対して、拡張ソースをコンパイルできます。 拡張にリフレクションを使用する必要はありません。

 

以下の例では、block() メソッドを使用して、スレッド名が Event Sink Thread Pool で始まるメソッドをエージェントがキャプチャしないようにします。

public class MyInterceptor extends AbstractInterceptor {
 
   /** このコールをインターセプトしない場合は true を返します */
   public boolean block(boolean wayIn, Object src, String spec, String clazz, String method, String signature, Object[] args, Object ret) {
      if (Thread.currentThread().getName().startsWith("Event Sink Thread Pool")) {
         return true;
      }
      return super.block(wayIn, src, spec, clazz, method, signature, args, ret);
   }
 
   ...
 
}

以下の例では、postProcess() メソッドを使用して、トランザクション ウィンドウの[応答]行のデータをキャプチャします。 この例では、com.itko.lisa.remote.transactions.TransactionFrame クラスの setResponse() メソッドをコールしています。 詳細については、インストール ディレクトリの doc フォルダで、JavaDocs を参照してください。

public class MyInterceptor extends AbstractInterceptor {
 
   ...
 
   public boolean postProcess(TransactionFrame frame, Object src, String spec, String clazz, String method, String signature, Object[] args, Object ret) {
      if (clazz.equals("com.itko.lisa.training.NotCaptured") && method.equals("doRequest")) {
         frame.setResponse((String) ret);
      }
      return super.postProcess(frame, src, spec, clazz, method, signature, args, ret);
   }

以下の例では、WebMethods の com.wm.data.IData オブジェクトが Integration Server のフローで呼び出されたときにそのオブジェクトの XML コンテンツを出力する方法を示します。 エージェントはすでに WebMethods をサポートしているので、そのための拡張は必要ありません。

package com.itko.lisa.ext;
 
 import java.io.ByteArrayOutputStream;
 import com.itko.lisa.remote.transactions.interceptors.AbstractInterceptor;
 import com.itko.lisa.remote.transactions.TransactionFrame;
 import com.wm.app.b2b.server.ServiceManager;
 import com.wm.app.b2b.server.BaseService;
 import com.wm.data.IData;
 import com.wm.util.coder.IDataXMLCoder;
 
 public class IDataInterceptor extends AbstractInterceptor {
 
 public IDataInterceptor() {
     super.intercept("com.wm.app.b2b.server.ServiceManager", "invoke", "(Lcom/wm/app/b2b/server/BaseService;Lcom/wm/data/IData;Z)Lcom/wm/data/IData;");
 }
 
 public boolean preProcess(TransactionFrame frame, Object src, String spec, String clazz, String method, String signature, Object[] args, Object ret) {
     if (ServiceManager.class.getName().equals(clazz) && "invoke".equals(method)) {
         doCustomLogic((BaseService) args\[0\], (IData) args\[1\], false);
     }
 
     return super.preProcess(frame, src, spec, clazz, method, signature, args, ret);
 }
 
 public boolean postProcess(TransactionFrame frame, Object src, String spec, String clazz, String method, String signature, Object[] args, Object ret) {
     if (ServiceManager.class.getName().equals(clazz) && "invoke".equals(method)) {
         doCustomLogic((BaseService) args\[0\], (IData) ret, true);
     }
 
     return super.postProcess(frame, src, spec, clazz, method, signature, args, ret);
 }
 
 private void doCustomLogic(BaseService flow, IData p, boolean output) {
     ByteArrayOutputStream baos = new ByteArrayOutputStream(63);
 
     try {
         new IDataXMLCoder().encode(baos, p);
     } catch (IOException e) {
         e.printStackTrace();
     }
 
     System.out.println("Flow: " + flow.getNSName());
     System.out.println((output ? "Output" : " Input") + "Pipeline: " + baos);
 
 }
 }

この拡張をビルドするには、LisaAgent.jarwm-isclient.jar、および wm-isserver.jar に対してこのコードをコンパイルし、以下の行を含むマニフェストと共にクラス ファイルを JAR にまとめます。

Agent-Extension: com.itko.lisa.ext.IDataInterceptor