Package org.jboss.byteman.rule

Source Code of org.jboss.byteman.rule.Rule

/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
* @authors Andrew Dinn
*/
package org.jboss.byteman.rule;

import org.jboss.byteman.agent.HelperManager;
import org.jboss.byteman.rule.type.TypeGroup;
import org.jboss.byteman.rule.type.Type;
import org.jboss.byteman.rule.exception.*;
import org.jboss.byteman.rule.binding.Bindings;
import org.jboss.byteman.rule.binding.Binding;
import org.jboss.byteman.rule.grammar.ECATokenLexer;
import org.jboss.byteman.rule.grammar.ECAGrammarParser;
import org.jboss.byteman.rule.grammar.ParseNode;
import org.jboss.byteman.rule.helper.HelperAdapter;
import org.jboss.byteman.rule.helper.Helper;
import org.jboss.byteman.rule.helper.InterpretedHelper;
import org.jboss.byteman.agent.Location;
import org.jboss.byteman.agent.Transformer;
import org.jboss.byteman.agent.RuleScript;
import org.objectweb.asm.Opcodes;

import org.jboss.byteman.rule.compiler.Compiler;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import java_cup.runtime.Symbol;

/**
* A rule ties together an event, condition and action. It also maintains a TypeGroup
* identifying type information derived from these components.
*/
public class Rule
{
    /**
     * the script defining this rule
     */
    private RuleScript ruleScript;
    /**
     * the name of this rule supplied in the rule script
     */
    private String name;
    /**
     * the class loader for the target class
     */
    private ClassLoader loader;
    /**
     * the parsed event derived from the script for this rule
     */
    private Event event;
    /**
     * the parsed condition derived from the script for this rule
     */
    private Condition condition;
    /**
     * the parsed condition derived from the script for this rule
     */
    private Action action;
    /**
     * the set of bindings derived from the event supplemented, post type checking, with bindings
     * derived from the trigger method. we may eventually also be able to install bindings for
     * method local variables.
     *
     * Note that use of the name bindings is slightly misleading since this instance identifies the
     * name and type of each of the available bound variables and, in the case of an event binding,
     * the expression to be evaluated in order to initialise the variable. It does not identify
     * any bound values for the variable. These are stored <em>per rule-firing</em> in a set
     * attached to the Helper instance used to implement the execute method for the rule.
     */
    private Bindings bindings;
    /**
     * the fully qualified name of the class to which this rule has been attached by the code
     * transformation package. note that this may not be the same as targetClass since the
     * latter may not specify a package.
     */
    private String triggerClass;
    /**
     * the name of the trigger method in which a trigger call for this rule has been inserted by
     * the code transformation package, not including the descriptor component. note that this
     * may not be the same as the targetMethod since the latter may include an argument list.
     */
    private String triggerMethod;
    /**
     * the descriptor of the trigger method in which a trigger call for this rule has been inserted
     * by the code transformation package. note that this will be in encoded format e.g. "(IZ)V"
     * rather than declaration format e.g. "void (int, boolean)"
     */
    private String triggerDescriptor;
    /**
     * the name sof all the exceptions declared by the trigger method in which a trigger call for
     * this rule has been inserted by the code transformation package.
     */
    private String[] triggerExceptions;
    /**
     * the access mode for the target method defined using flag bits defined in the asm Opcodes
     * class.
     */
    private int triggerAccess;
    /**
     * the set of types employed by the rule, inlcuding types referenced by abbreviated name (without
     * mentioning the package), array type sand/or their base types and standard builtin types.
     */
    private TypeGroup typeGroup;
    /**
     * flag set to true only after the rule has been type checked
     */
    private boolean checked;
    /**
     * flag set to true only after the rule has been type checked successfully
     */
    private boolean checkFailed;

    /**
     * return type of the rule's trigger method
     */

    private Type returnType;

    /**
     * the key under which this rule is indexed in the rule key map.
     */

    private String key;

    /**
     * lifecycle event manager for rule helpers
     */
    private HelperManager helperManager;
    /**
     * a list of field objects used by compiled code to enable rule code to access non-public fields
     */
    private List<Field> accessibleFields;

    /**
     * a list of method objects used by compiled code to enable rule code to access non-public methods
     */
    private List<Method> accessibleMethods;

    private Rule(RuleScript ruleScript, ClassLoader loader, HelperManager helperManager)
            throws ParseException, TypeException, CompileException
    {
        ParseNode ruleTree;

        this.ruleScript = ruleScript;
        this.helperClass = null;
        this.loader = loader;

        typeGroup = new TypeGroup(loader);
        bindings = new Bindings();
        checked = false;
        triggerClass = null;
        triggerMethod = null;
        triggerDescriptor = null;
        triggerAccess = 0;
        returnType = null;
        accessibleFields =  null;
        accessibleMethods = null;
        // this is only set when the rule is created via a real installed transformer
        this.helperManager =  helperManager;
        ECAGrammarParser parser = null;
        try {
            String file = getFile();
            ECATokenLexer lexer = new ECATokenLexer(new StringReader(ruleScript.getRuleText()));
            lexer.setStartLine(getLine());
            lexer.setFile(file);
            parser = new ECAGrammarParser(lexer);
            parser.setFile(file);
            Symbol parse = (debugParse ? parser.debug_parse() : parser.parse());
            if (parser.getErrorCount() != 0) {
                String message = "rule " + ruleScript.getName();
                message += parser.getErrors();
                throw new ParseException(message);
            }
            ruleTree = (ParseNode) parse.value;
        } catch (ParseException pe) {
            throw pe;
        } catch (Throwable th) {
            String message = "rule " + ruleScript.getName();
            if (parser != null && parser.getErrorCount() != 0) {
                message += parser.getErrors();
            }
            message += "\n" + th.getMessage();
            throw new ParseException(message);
        }

        ParseNode eventTree = (ParseNode)ruleTree.getChild(0);
        ParseNode conditionTree = (ParseNode)ruleTree.getChild(1);
        ParseNode actionTree = (ParseNode)ruleTree.getChild(2);

        event = Event.create(this, eventTree);
        condition = Condition.create(this, conditionTree);
        action = Action.create(this, actionTree);
        key = null;
    }

    public TypeGroup getTypeGroup()
    {
        return typeGroup;
    }

    public Bindings getBindings()
    {
        return bindings;
    }

    public String getName() {
        return ruleScript.getName();
    }

    public String getTargetClass() {
        return ruleScript.getTargetClass();
    }

    public String getTargetMethod() {
        return ruleScript.getTargetMethod();
    }

    public Location getTargetLocation() {
        return ruleScript.getTargetLocation();
    }

    public boolean isOverride()
    {
        return ruleScript.isOverride();
    }

    public boolean isInterface()
    {
        return ruleScript.isInterface();
    }

    /**
     * retrieve the start line for the rule
     * @return the start line for the rule
     */
    public int getLine()
    {
        return ruleScript.getLine();
    }

    /**
     * retrieve the name of the file containing this rule
     * @return the name of the file containing this rule
     */
    public String getFile()
    {
        return ruleScript.getFile();
    }

    public Event getEvent()
    {
        return event;
    }

    public Condition getCondition() {
        return condition;
    }

    public Action getAction() {
        return action;
    }

    public String getTriggerClass() {
        return triggerClass;
    }

    public Type getReturnType()
    {
        return returnType;
    }                                                                                    

    /**
     * get the class loader of the target class for the rule
     * @return
     */
    public ClassLoader getLoader()
    {
        return loader;
    }

    public static Rule create(RuleScript ruleScript, ClassLoader loader, HelperManager helperManager)
            throws ParseException, TypeException, CompileException
    {
            return new Rule(ruleScript, loader, helperManager);
    }

    public void setEvent(String eventSpec) throws ParseException, TypeException
    {
        if (event == null) {
            event = Event.create(this, eventSpec);
        }
    }

    public void setCondition(String conditionSpec) throws ParseException, TypeException
    {
        if (event != null & condition == null) {
            condition = Condition.create(this, conditionSpec);
        }
    }

    public void setAction(String actionSpec) throws ParseException, TypeException
    {
        if (event != null & condition != null && action == null) {
            action = Action.create(this, actionSpec);
        }
    }

    public void setTypeInfo(final String className, final int access, final String methodName, final String desc, String[] exceptions)
    {
        triggerClass = className;
        triggerAccess = access;
        triggerMethod = methodName;
        triggerDescriptor = desc;
        triggerExceptions = exceptions;
    }

    /**
     * has this rule been typechecked and/or compiled
     * @return true if this rule has been typechecked and/or compiled otherwise false
     */
    public boolean isChecked()
    {
        return checked;
    }

    /**
     * has this rule failed to typecheck or compile
     * @return true if this rule has failed to typecheck or compile otherwise false
     */
    public boolean isCheckFailed()
    {
        return checkFailed;
    }

    /**
     * has this rule been typechecked and compiled without error.
     * @return true if this rule has been typechecked and compiled without error otherwise false
     */
    public boolean isCheckedOk()
    {
        return (checked && !checkFailed);
    }

    /**
     * disable triggering of rules inside the current thread. this is the version called internally
     * after returning from a method call in a rule binding, condition or action.
     * @return true if triggering was previously enabled and false if it was already disabled
     */
    public static boolean disableTriggersInternal()
    {
        return Transformer.disableTriggers(false);
    }

    /**
     * enable triggering of rules inside the current thread n.b. this is called internally by the rule
     * engine before it executes a method call in a rule binding, condition or action. it will not
     * enable triggers if they have been switched off by an earlier call to userDisableTriggers.
     * @return true if triggering was previously enabled and false if it was already disabled
     */
    public static boolean enableTriggersInternal()
    {
        return Transformer.enableTriggers(false);
    }

    /**
     * disable triggering of rules inside the current thread. this is the version which should be
     * called from a Helper class to ensure that subsequent method invocatiosn during execution of
     * the current rule bindings, condition or action do not recursively trigger rules. It ensures
     * that subsequent calls to enableTriggers have no effect. The effect lasts until the end of
     * processing for the current rule when resetTriggers is called.
     * @return true if triggering was previously enabled and false if it was already disabled
     */
    public static boolean disableTriggers()
    {
        return Transformer.disableTriggers(true);
    }

    /**
     * enable triggering of rules inside the current thread. this is called internally by the rule
     * engine after rule execution has completed. it will re-enable triggers even if they have been
     * switched off by an earlier call to userDisableTriggers. It is also called by the default helper
     * to reverse the effect of calling userDisableTriggers.
     * @return true if triggering was previously enabled and false if it was already disabled
     */
    public static boolean enableTriggers()
    {
        return Transformer.enableTriggers(true);
    }

    /**
     * check if triggering of rules is enabled inside the current thread
     * @return true if triggering is enabled and false if it is disabled
     */
    public static boolean isTriggeringEnabled()
    {
        return Transformer.isTriggeringEnabled();
    }

    /**
     * typecheck and then compile this rule unless either action has been tried before
     * @return true if the rule successfully type checks and then compiles under this call or a previous
     * call or false if either operation has previously failed or fails under this call.
     */
    private synchronized boolean ensureTypeCheckedCompiled()
    {
        if (checkFailed) {
            return false;
        }

        if (!checked) {
            // ensure we don't trigger any code inside the type check or compile
            // n.b. we may still allow recursive triggering while executing
            boolean triggerEnabled = false;
            String detail = "";
            try {
                typeCheck();
                compile();
                checked = true;
                installed();
            } catch (TypeException te) {
                checkFailed = true;
                StringWriter stringWriter = new StringWriter();
                PrintWriter writer = new PrintWriter(stringWriter);
                writer.println("Rule.ensureTypeCheckedCompiled : error type checking rule " + getName());
                te.printStackTrace(writer);
                detail = stringWriter.toString();
                System.out.println(detail);
            } catch (CompileException ce) {
                checkFailed = true;
                StringWriter stringWriter = new StringWriter();
                PrintWriter writer = new PrintWriter(stringWriter);
                writer.println("Rule.ensureTypeCheckedCompiled : error compiling rule " + getName());
                ce.printStackTrace(writer);
                detail = stringWriter.toString();
                System.out.println(detail);
            }

            ruleScript.recordCompile(triggerClass, loader, !checkFailed, detail);
            return !checkFailed;
        }

        return true;
    }

    /**
     * type check this rule
     * @throws TypeException if the ruele contains type errors
     */
    public void typeCheck()
            throws TypeException
    {
        String helperName = ruleScript.getTargetHelper();
       
        // ensure that we have a valid helper class
        if (helperName != null) {
            try {
                helperClass = loader.loadClass(helperName);
            } catch (ClassNotFoundException e) {
                throw new TypeException("Rule.typecheck : unknown helper class " + helperName + " for rule " + getName());
            }
        } else {
            helperClass = Helper.class;
        }
        if (triggerExceptions != null) {
            // ensure that the type group includes the exception types
            typeGroup.addExceptionTypes(triggerExceptions);
        }
       
        // try to resolve all types in the type group to classes

        typeGroup.resolveTypes();

        // use the descriptor to derive the method argument types and type any bindings for them
        // that are located in the bindings list

        installParameters((triggerAccess & Opcodes.ACC_STATIC) != 0, triggerClass);

        event.typeCheck(Type.VOID);
        condition.typeCheck(Type.Z);
        action.typeCheck(Type.VOID);
    }

    /**
     * install helper class used to execute this rule. this may involve generating a compiled helper class
     * for the rule and, if compilation to bytecode is enabled, generating bytecode for a method of this class
     * used to execute the rule binding, condition and action expressions. If the rule employ sthe default helper
     * without enabling compilation to bytecode then no class need be generated. the installed helper class will
     * be the predefined class InterpretedHelper.
     * @throws CompileException if the rule cannot be compiled
     */
    public void compile()
            throws CompileException
    {
        boolean compileToBytecode = isCompileToBytecode();

        if (helperClass == Helper.class && !compileToBytecode) {
            // we can use the builtin interpreted helper adapter for class Helper
           helperImplementationClass = InterpretedHelper.class;
        } else {
            // we need to generate a helper adapter class which either interprets or compiles

            helperImplementationClass = Compiler.getHelperAdapter(this, helperClass, compileToBytecode);
        }
    }

    /**
     * should rules be compiled to bytecode
     * @return true if rules should be compiled to bytecode otherwise false
     */
    private boolean isCompileToBytecode()
    {
        return Transformer.isCompileToBytecode();
    }

    private void installParameters(boolean isStatic, String className)
            throws TypeException
    {
        Type type;
        // add a binding for the helper so we can call builtin static methods
        type = typeGroup.create(helperClass.getName());
        Binding ruleBinding = bindings.lookup("$$");
        if (ruleBinding != null) {
            ruleBinding.setType(type);
        } else {
            bindings.append(new Binding(this, "$$", type));
        }

        if (!isStatic) {
            Binding recipientBinding = bindings.lookup("$0");
            if (recipientBinding != null) {
                type = typeGroup.create(className);
                if (type.isUndefined()) {
                    throw new TypeException("Rule.installParameters : Rule " + name + " unable to load class " + className);
                }
                recipientBinding.setType(type);
            }
        }

        String returnTypeName = Type.parseMethodReturnType(triggerDescriptor);

        returnType = typeGroup.create(returnTypeName);

        Iterator<Binding> iterator = bindings.iterator();

        while (iterator.hasNext()) {
            Binding binding = iterator.next();
            // these bindings are typed via the descriptor installed during trigger injection
            // note that the return type has to be done this way because it may represent the
            // trigger method return type or the invoke method return type
            if (binding.isParam() || binding.isLocalVar() || binding.isReturn()) {
                String typeName = binding.getDescriptor();
                String[] typeAndArrayBounds = typeName.split("\\[");
                Type baseType = typeGroup.create(typeAndArrayBounds[0]);
                Type fullType = baseType;
                if (baseType.isUndefined()) {
                    throw new TypeException("Rule.installParameters : Rule " + name + " unable to load class " + baseType);
                }
                for (int i = 1; i < typeAndArrayBounds.length ; i++) {
                    fullType = typeGroup.createArray(fullType);
                }
                binding.setType(fullType);
            } else if (binding.isThrowable()) {
                // TODO -- enable a more precise specification of the throwable type
                // we need to be able to obtain the type descriptor for the throw operation
                binding.setType(typeGroup.ensureType(Throwable.class));
            } else if (binding.isParamCount()) {
                binding.setType(Type.I);
            } else if (binding.isParamArray() || binding.isInvokeParamArray()) {
                binding.setType(Type.OBJECT.arrayType());
            }
        }
    }

    /**
     * forward an execute request a rule identified by its unique key
     * @param key a string key identifying the rule instance to be fired
     * @param recipient the recipient of the method from which execution of the rule was
     * triggered or null if it was a static method
     * @param args the arguments of the method from which execution of the rule was
     * triggered
     */
    public static void execute(String key, Object recipient, Object[] args) throws ExecuteException
    {
        boolean enabled = isTriggeringEnabled();
        if (!enabled) {
            // we don't trigger code while we are doing rule housekeeping
            return;
        }

        // disable triggering until we get into actual rule code
       
        disableTriggersInternal();

        try {
        Rule rule = ruleKeyMap.get(key);
        if (Transformer.isVerbose()) {
            System.out.println("Rule.execute called for " + key);
        }

        // if the key is no longer present it just means the rule has been decommissioned so return
        if (rule == null) {
            if (Transformer.isVerbose()) {
                System.out.println("Rule.execute for decommissioned key " + key);
            }
            return;
        }

        rule.execute(recipient, args);
        } finally {
            // restore the status quo -- we must have been enabled if we got to this method
            enableTriggers();
        }           
    }

    /**
     * forward an execute request to a helper instance associated with the rule
     * @param recipient the recipient of the method from which execution of this rule was
     * triggered or null if it was a static method
     * @param args the arguments of the method from which execution of this rule was
     * triggered
     */

    private void execute(Object recipient, Object[] args) throws ExecuteException
    {
        // type check and createHelperAdapter the rule now if it has not already been done

        if (ensureTypeCheckedCompiled()) {

            // create a helper and get it to execute the rule
            // eventually we will create a subclass of helper for each rule and createHelperAdapter
            // an implementation of execute from the rule source. for now we create a generic
            // helper and call the generic execute method which interprets the rule
            HelperAdapter helper;
            try {
                Constructor constructor = helperImplementationClass.getConstructor(Rule.class);
                helper = (HelperAdapter)constructor.newInstance(this);
                //helper = (RuleHelper)helperClass.newInstance();
                //helper.setRule(this);
                helper.execute(recipient, args);
            } catch (NoSuchMethodException e) {
                // should not happen!!!
                System.out.println("cannot find constructor " + helperImplementationClass.getCanonicalName() + "(Rule) for helper class");
                e.printStackTrace(System.out);
                return;
            } catch (InvocationTargetException e) {
                e.printStackTrace()//To change body of catch statement use File | Settings | File Templates.
            } catch (InstantiationException e) {
                // should not happen
                System.out.println("cannot create instance of " + helperImplementationClass.getCanonicalName());
                e.printStackTrace(System.out);
                return;
            } catch (IllegalAccessException e) {
                // should not happen
                System.out.println("cannot access " + helperImplementationClass.getCanonicalName());
                e.printStackTrace(System.out);
                return;
            } catch (ClassCastException e) {
                // should not happen
                System.out.println("cast exception " + helperImplementationClass.getCanonicalName());
                e.printStackTrace(System.out);
                return;
            } catch (EarlyReturnException e) {
                throw e;
            } catch (ThrowException e) {
                throw e;
            } catch (ExecuteException e) {
                System.out.println(getName() + " : " + e);
                throw e;
            } catch (Throwable throwable) {
                System.out.println(getName() + " : " + throwable);
                throw new ExecuteException(getName() + "  : caught " + throwable, throwable);
            }
        }
    }

    /**
     * called when a trigger is compiled for the rule to provide a String key which can be used
     * at execution time to obtain a handle on the rule instance
     *
     * @return a key which can be used later to obtain a reference to the rule
     */

    public String getKey()
    {
        if (key != null) {
            return key;
        }
       
        String key = getName() + "_" + nextId();
        this.key = key;
        ruleKeyMap.put(key, this);
        return key;
    }

    /**
     * return the key under which this rule has been indexed in the rule key map
     * @return
     */
    public String lookupKey()
    {
        return key;
    }


    /**
     * delete any reference to the rule from the rule map
     */
    public void purge()
    {
        // nothing to do unless we actually allocated a key
        if (key != null) {
            ruleKeyMap.remove(key);
            if (checked) {
                uninstalled();
            }
        }
    }

    /**
     * a hash map used to identify rules from their keys
     */
    private static HashMap<String, Rule> ruleKeyMap = new HashMap<String, Rule>();

    /**
     * a counter used to ensure rule identifiers are unique
     */
    private static int nextId = 0;

    /**
     * a method to return the next available counter for use in constructing a key for the rule
     * @return
     */
    private synchronized static int nextId()
    {
        return nextId++;
    }

    private static boolean compileRules()
    {
        return Transformer.isCompileToBytecode();
    }

    /**
     * generate a string representation of the rule
     *
     * @return a string representation of the rule
     */

    public String toString()
    {
        StringWriter stringWriter = new StringWriter();
        stringWriter.write("RULE ");
        stringWriter.write(getName());
        stringWriter.write("\n");
        if (isInterface()) {
            stringWriter.write("INTERFACE ");
        } else {
            stringWriter.write("CLASS ");
        }
        if (isOverride()) {
            stringWriter.write("^");
        }
        stringWriter.write(getTargetClass());
        stringWriter.write('\n');
        stringWriter.write("METHOD ");
        stringWriter.write(getTargetMethod());
        stringWriter.write('\n');
        stringWriter.write(getTargetLocation().toString());
        stringWriter.write('\n');
        if (event != null) {
            event.writeTo(stringWriter);
        } else {
            stringWriter.write("BIND NOTHING\n");
        }
        if (condition != null) {
            condition.writeTo(stringWriter);
        } else {
            stringWriter.write("COND   TRUE\n");
        }
        if (action != null) {
            action.writeTo(stringWriter);
        } else {
            stringWriter.write("DO   NOTHING\n");
        }
       
        return stringWriter.toString();
    }

    /**
     * a helper class which defines the builtin methods available to this rule -- by default Helper
     */
    private Class helperClass;

    /**
     * an extension of the helper class which implements the methods of interface RuleHelper -- by default
     * InterpretedHelper. This is the class which is instantiated and used as the target for an execute
     * operation.
     */

    private Class helperImplementationClass;

    /**
     * a getter allowing the helper class for the rule to be identified
     *
     * @return
     */
    public Class getHelperClass()
    {
        return helperClass;
    }

    /**
     * flag true if debugging of rule parsing is desired and false if it should not be performed
     */
    private static boolean debugParse = (System.getProperty("org.jboss.byteman.rule.debug") != null ? true : false);

    /**
     * method called when the rule has been successfully injected into a class, type checked and compiled. it passes
     * the message on to the Transformer so it can perform helper lifecycle management.
     */
    private void installed()
    {
        helperManager.installed(this);
    }

    /**
     * method called when the rule has been uninstalled after previously being successfully injected into a class,
     * type checked and compiled. it passes the message on to the Transformer so it can perform helper lifecycle
     * management.
     */
    private void uninstalled()
    {
        helperManager.uninstalled(this);
    }

    public int addAccessibleField(Field field) {
        if (accessibleFields == null) {
            accessibleFields = new ArrayList<Field>();
        }
        int index = accessibleFields.size();
        accessibleFields.add(field);
        return index;
    }
   
    public int addAccessibleMethod(Method method) {
        if (accessibleMethods == null) {
            accessibleMethods = new ArrayList<Method>();
        }
        int index = accessibleMethods.size();
        accessibleMethods.add(method);
        return index;
    }

    public Object getAccessibleField(Object owner, int fieldIndex) throws ExecuteException
    {
        try {
            Field field = accessibleFields.get(fieldIndex);
            return field.get(owner);
        } catch (Exception e) {
            throw new  ExecuteException("Rule.getAccessibleField : unexpected error getting non-public field in rule " + getName(), e);
        }
    }

    public void setAccessibleField(Object owner, Object value, int fieldIndex) throws ExecuteException
    {
        try {
            Field field = accessibleFields.get(fieldIndex);
            field.set(owner, value);
        } catch (Exception e) {
            throw new  ExecuteException("Rule.setAccessibleField : unexpected error setting non-public field in rule " + getName(), e);
        }
    }

    public Object invokeAccessibleMethod(Object target, Object[] args, int methodIndex)
    {
        try {
            Method method = accessibleMethods.get(methodIndex);
            return method.invoke(target, args);
        } catch (Exception e) {
            throw new  ExecuteException("Rule.invokeAccessibleMethod : unexpected error invoking non-public method in rule " + getName(), e);
        }
    }
}
TOP

Related Classes of org.jboss.byteman.rule.Rule

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.