Rubrique précédente: Extensions d'agent JavaRubrique suivante: Ajout de balises à des trames de transaction


Extension de l'agent

Pour personnaliser le comportement de l'agent, vous pouvez écrire des classes Java qui implémentent l'interface com.itko.lisa.remote.transactions.interceptors.IInterceptor ou étendent la classe com.itko.lisa.remote.transactions.interceptors.AbstractInterceptor. Pour de plus amples informations, reportez-vous au document JavaDocs disponible dans le dossier doc du répertoire d'installation.

public interface IInterceptor {
    /**
     * Indique si cet intercepteur personnalisé est actuellement désactivé
     */
    public boolean isDisabled();
 
    /**
     * Indique si l'interception doit être renvoyée (true) ou de continuer (false)
     */
    public boolean block(boolean wayIn, Object src, String spec, String clazz, String method, String signature, Object[] args, Object ret);
 
    /**
     * Appelé après l'entrée de la méthode pour éventuellement modifier la trame actuelle en fonction de la logique d'intercepteur
     */
    public boolean preProcess(TransactionFrame frame, Object src, String spec, String clazz, String method, String signature, Object[] args, Object ret);
 
    /**
     * Appelé avant la sortie de la méthode pour éventuellement modifier la trame actuelle en fonction de la logique d'intercepteur
     */
    public boolean postProcess(TransactionFrame frame, Object src, String spec, String clazz, String method, String signature, Object[] args, Object ret);
}

Si vous voulez arrêter la capture de données, écrasez la méthode block(). Cette technique est similaire à l'ajout d'une directive exclude au fichier rules.xml, mais offre plus de flexibilité.

Si vous voulez que l'agent effectue la logique immédiatement avant la capture d'une méthode, écrasez la méthode preProcess().

Si vous voulez que l'agent applique la logique immédiatement après la capture d'une méthode, écrasez la méthode postProcess().

Ces méthodes sont automatiquement appelées pour toutes les classes et méthodes interceptées ou suivies. Pour intercepter une méthode ou suivre une classe, vous pouvez la spécifier à l'aide de la syntaxe mentionnée dans le fichier rules.xml. Vous pouvez également spécifier l'interception à l'aide d'un programme dans le constructeur de la classe d'extension. L'avantage de la dernière approche réside dans le fait que l'extension est indépendante.

Le premier argument de la méthode block() est boolean wayIn. La méthode block() est appelée deux fois par méthode, une fois à l'entrée et une fois à la sortie. Lorsque l'appel d'entrée est effectué, la valeur de l'argument wayIn est true. Lorsque l'appel de sortie est effectué, la valeur de l'argument wayIn est false.

Le tableau suivant décrit les arguments communs aux méthodes block(), preProcess() et postProcess() :

Argument

Description

Object src

L'objet pour lequel la méthode est appelée.

String spec

Nom de la classe ou l'interface spécifiée pour l'instrumentation de l'API.

String clazz

Nom de la classe qui définit la méthode interceptée.

String method

Nom de la méthode interceptée.

String signature

Signature (au format de machine virtuelle Java) de la méthode interceptée.

Object[] args

Arguments transférés à la méthode interceptée.

Object ret

Valeur de retour de la méthode interceptée. Lorsque l'argument wayIn est true, la valeur de retour est nulle.

La différence entre les arguments src, spec et clazz peut être expliquée par un exemple.

Supposez que vous avez les définitions d'interface et de classe suivantes :

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

Si les règles spécifient intercept("A", "m", "*") et le code appelle C.m(), les informations suivantes sont vraies :

 

Déploiement

Pour déployer une extension, compilez-la et mettez-la en package dans un fichier .jar avec un fichier manifeste contenant l'entrée suivante :

Agent-Extension: nom de la classe d'extension 

Lorsque vous déplacez ce fichier .jar dans le répertoire JAR de l'agent, l'agent le récupère automatiquement. Si vous ajoutez le fichier après le démarrage de l'agent, un mécanisme de chargement à chaud permet d'assurer l'application du fichier. Si vous mettez à jour l'extension .jar lors de l'exécution de l'agent, les classes JAR seront rechargées de façon dynamique. Le rechargement dynamique simplifie et accélère le test de votre code d'extension sans redémarrer le serveur.

Les fichiers .jar d'extension sont chargés par un chargeur de classes qui peut consulter toutes les classes utilisées dans la classe de l'extension. Vous pouvez compiler votre source d'extension au niveau du LisaAgent.jar et tous les fichiers .jar du conteneur qui définissent des classes que vous voulez utiliser. Il n'est pas nécessaire d'utiliser la réflexion dans votre extension.

 

Exemples

Dans l'exemple suivant, la méthode block() est utilisée pour empêcher l'agent de capturer une méthode dont le nom de thread commence par Event Sink Thread Pool (Pool de threads du récepteur d'événements).

public class MyInterceptor extends AbstractInterceptor {
 
   /** renvoie True si cet appel ne doit pas être intercepté */
   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);
   }
 
   ...
 
}

Dans l'exemple suivant, la méthode postProcess() est utilisée pour capturer des données pour la ligne Response (Réponse) de la fenêtre Transactions. Cet exemple appelle la méthode setResponse() de la classe com.itko.lisa.remote.transactions.TransactionFrame. Pour de plus amples informations, reportez-vous au document JavaDocs disponible dans le dossier doc du répertoire d'installation.

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);
   }

L'exemple suivant illustre la procédure d'impression du contenu XML d'un objet WebMethods com.wm.data.IData lorsqu'il est appelé dans un flux du serveur d'intégration. L'agent prend déjà en charge WebMethods, une extension n'est donc pas utile.

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);
 
 }
 }

Pour créer cette extension vous-même, compilez ce code au niveau du fichier LisaAgent.jar, du fichier wm-isclient.jar et du fichier wm-isserver.jar, puis mettez en package JAR le fichier de classe avec un fichier manifeste contenant la ligne suivante :

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