" [ type .] field [count | ALL ] or $var-or-idx [count | ALL ] ; follwoing AT, An AFTER READ specification is identical to an AT READ specification except that it locates the trigger point after the getField or variable read operation."
"following AT, [ type .] field [count | ALL ] or $var-or-idx [count | ALL ] ; \n\n\nAT WRITE and AFTER WRITE specifiers are the same as the corresponding READ specifiers except that they correspond to assignments to the named field or named variable in the source code i.e. they identify putField or istore, dstore, etc instructions.\n\nNote that location AT WRITE $0 or, equivalently, AT WRITE $this will never match any candidate trigger method because the target object for an instance method invocation is never assigned.\n\nNote also that for a given local variable, localvar, location AT WRITE $localvar or, equivalently, AT WRITE $localvar 1 identifies the location immediately after the local variable is initialised i.e. it is treated as if it were specified as AFTER WRITE $localvar. This is necessary because the variable is not in scope until after it is initialised. This also ensures that the local variable which has been written can be safely accessed in the rule body.\n"
"The AS TARGET clause tells the type checker to use the target type named in the CLASS or INTERFACE clause when type checking the expression $0 or $this. It also tells the type checker to resolve class names using the class loader of the target type."
"\n\nBy contrast, if the rule uses AS TRIGGER semantics then when the rule is matched against class LinkedList that dynamic type will be used during typecheck to type expression $0 and type check would succeed. The same applies when the rule is matched against any other class that implements a method with signature append(Object). The rule will still fail to typecheck when the trigger class is ArrayList leading to a type error and disabling of injection for that case.\n\nThere are benefits to using the dynamic type scope established at the point of injection as well as the potential for errors as seen above. One common case where using AS TRIGGER semantics is preferable arises when the dynamically determined trigger classes belong to a child classloader of the target class. If AS TRIGGER semantics are used then the body of the rule can reference other classes defined by the child class loader. If AS TARGET semantics were used instead then those types would not be in scope. In many cases this is simply resolved by injecting direct into each specific subclass but cases do arise where it is easier to employ a single rule which relies on injection through an interface and/or down a class hierarchy.\n\nFor hysterical reasons, Byteman uses AS TRIGGER (dynamic) type scoping as the default semantics. However, it also supports AS TARGET (lexical) type scoping. In fact, you can mix and match the two approaches for individual rules or rule groups by inserting an AS TRIGGER or AS TARGET clause into your scripts. If the clause appears in the body of a rule, between the location (AT) and condition (IF) clauses, then it defines the type scope for that specific rule. If it appears at the top level, outside of a rule body then it (re-)defines the default type scope to be used for subsequent rules which do not provide their own declaration.\n"
"Counters\n\nThe rule engine provides Counters which maintain global counts across independent rule triggerings. They can be created and initialised, read, incremented and decremented in order track and respond to the number of times various triggerings or firings have happened. Note that unlike CountDowns there are no special semantics associated with decrementing a Counter to zero. They may even have negative values. The API defined by the helper class is\n\n public boolean createCounter(Object o)\n public boolean createCounter(Object o, int count)\n public boolean deleteCounter(Object o)\n public int incrementCounter(Object o, int amount)\n public int incrementCounter(Object o)\n public int decrementCounter(Object o)\n public int readCounter(Object o)\n public int readCounter(Object o, boolean zero)\n\nAs before, Counters are identified by an arbitrary object. All methods are designed to be used in rule conditions or actions.\n\ncreateCounter can be called to create a new Counter associated with o. If argument count is not supplied then the value of the new Counter defaults to o. createCounter returns true if a new Counter was created and false if a Counter associated with o already exists. Note that the API is designed to ensure that race conditions between multiple threads trying to create a Counter from rule conditions can only have one winner.\n\ndeleteCounter can be called to delete any existing Counter associated with o. It returns true if the Counter was deleted and false if no Counter was associated with o. Note that the API is designed to ensure that race conditions between multiple threads trying to delete a Counter from rule conditions can only have one winner.\n\nincrementCounter can be called to increment the Counter associated with o. If no such Counter exists it will create one with value 0 before incrementing it. incrementCounter returns the new value of the Counter. If amount is omitted it defaults to 1.\n\ndecrementCounter is equivalent to calling incrementCounter(o, -1) i.e. it adds -1 to the value of the counter.\n\nreadCounter can be called to read the value of the Counter associated with o. If no such Counter exists it will create one with value 0. If the optional flag argument zero is passed as true the counter is atomically read and zeroed. zero defaults to false.\n"
"Following AT, An AT ENTRY specifier normally locates the trigger point before the first executable instruction in the trigger method. An exception to this occurs in the case of a constructor method in which case the trigger point is located before the first instruction following the call to the super constructor or redirection call to an alternative constructor. This is necessary to ensure that rules do not attempt to bind and operate on the instance before it is constructed."
"An AT EXCEPTION EXIT specifier identifies the point where a method returns control back to its caller via unhandled exceptional control flow. This can happen either because the method itself has thrown an exception or because it has called out to some other method which has thrown an exception. It can also happen when the method executes certain operations in the Java language, for example dereferencing a null object value or indexing beyond the end of an array.\n\nA rule injected with this location is triggered at the point where the exception would normally propagate back to the caller. Once rule execution completes then normally the exception flow resumes. However, the rule may subvert this resumed flow by executing a RETURN. It may also explicitly rethrow the original exception or throw some newly created exception by executing a THROW (n.b. if the latter is a checked exception then it must be declared as a possible exception by the trigger method).\n\nn.b. when several rules specify the same location the order of injection of trigger calls usually follows the order of the rules in their respective scripts. The exception to this is AFTER locations where the the order of injection is the reverse to the order of occurrence.\n\nn.b.b. when a location specifier (other than ENTRY or EXIT) is used with an overriding rule the rule code is only injected into the original method or overriding methods if the location matches the method in question. So, for example, if location AT READ myField 2 is employed then the rule will only be injected into implementations of the method which include two loads of field myField. Methods which do not match the location are ignored.\n\nn.b.b.b. for historical reasons CALL may be used as a synonym for INVOKE, RETURN may be used as a synonym for EXIT and the AT in an AT LINE specifier is optional.\n"
"Flags\n\nThe rule engine provides a simple mechanism for setting, testing and clearing global flags. The API defined by the helper class is\n\n public boolean flag(Object identifier)\n public boolean flagged(Object identifier)\n public boolean clear(Object identifier)\n\nAs before, Flags are identified by an arbitrary object. All three methods are designed to be used either in conditions or actions.\n\nflag can be called to ensure that the Flag identified by identifier is set. It returns true if the Flag was previously clear otherwise false. Note that the API is designed to ensure that race conditions between multiple threads trying to set a Flag from rule conditions can only have one winner.\n\nflagged tests whether the Flag identified by identifier is set. It returns true if the Flag is set otherwise false.\n\nclear can be called to ensure that the Flag identified by identifier is clear. It returns true if the Flag was previously set otherwise false. Note that the API is designed to ensure that race conditions between multiple threads trying to clear a Flag from rule conditions can only have one winner.\n"
"\n\nA rule can specify it\u2019s own helper class if it wants to extend, override or replace the set of built-in calls available for use in its event, condition or action. For example, in the following rule, class FailureTester is used as the helper class. Its boolean instance method doWrongState(CoordinatorEngine) is called from the condition to decide whether or not to throw a WrongStateException.\n\n # helper example\n RULE help yourself\n CLASS com.arjuna.wst11.messaging.engines.CoordinatorEngine\n METHOD commit\n HELPER com.arjuna.wst11.messaging.engines.FailureTester\n AT EXIT\n IF doWrongState($0)\n DO throw new WrongStateException()\n ENDRULE\n\nA helper class does not need to implement any special interface or inherit from any pre-defined class. It merely needs to provide instance methods to resolve the built-in calls which occur in the rule. The only limitations are\n\n your helper class must not be final\n\n Byteman needs to be able to subclass your helper in order to interface it to the rule execution engine\n\n your helper class must not be abstract\n\n Byteman needs to be able to instantiate your helper when the rule is triggered\n\n you must provide a suitable public constructor for your helper class\n\n by default Byteman will instantiate it using the empty constructor (i.e. the one with signature ())\n\n if you provide a constructor that accepts the rule as argument (i.e. with signature (org.jboss.byteman.agent.rule.Rule)) Byteman will use that for preference\n\nBy sub-classing the default helper it is possible to extend or override the default set of methods. For example, the following rule employs a helper which adds emphasis to the debug messages printed by the rule.\n\n # helper example 2\n RULE help yourself but rely on others\n CLASS com.arjuna.wst11.messaging.engines.CoordinatorEngine\n METHOD commit\n HELPER HelperSub\n AT ENTRY\n IF NOT flagged($this)\n DO debug(\"throwing wrong state\");\n flag($this);\n throw new WrongStateException()\n ENDRULE\n\n class HelperSub extends Helper\n {\n public HelperSub(Rule rule)\n {\n super(rule);\n }\n public boolean debug(String message)\n {\n super(\"!!! IMPORTANT EVENT !!! \" + message);\n }\n }\n\nThe rule is still able to employ the built-in methods flag and flagged defined by the default helper class.\n\nThe examples above use a HELPER line in the rule body to reset the helper for a specific rule. It is also possible to reset the helper for all subsequent rules in a file by adding a HELPER line outside of the scope of a rule. So, in the following example the first two rules use class HelperSub while the third one uses class YellowSub.\n\n HELPER HelperSub\n # helper example 3\n RULE helping hand\n . . .\n RULE I can\'t help myself\n . . .\n RULE help, I need somebody\n CLASS . . .\n METHOD . . .\n HELPER YellowSub\n . . .\n\n"
"following AT [ type .] method [ ( argtypes ) ] [count | ALL ]\nAT INVOKE and AFTER INVOKE specifiers are like READ and WRITE specifiers except that they identify invocations of methods or constructors within the trigger method as the trigger point. The method may be identified using a bare method name or the name may be qualified by a, possibly package-qualified, type or by a descriptor. A descriptor consists of a comma-separated list of type names within brackets. The type names identify the types of the method parameters and may be prefixed with package qualifiers and employ array bracket pairs as suffixes."
"\nByteman provides the English language keywords listed below which can be used in place of the related standard Java operators (in brackets):\nOR (||), AND (&&), NOT (!), LE (< =), LT (<), EQ (==), NE (!=), GE (>=), GT (>), TIMES (*), DIVIDE (/), PLUS (+), MINUS (-), MOD (%), Keywords are recognised in either upper or lower (but not mixed) case.\nKeywords may clash with the same names where they they occur as legal Java identifiers in the target classes and methods specified in Byteman rules"
"[ type ] [ [] ] * [count | ALL ]\n\n\nAT NEW and AFTER NEW specifiers identify locations in the target method where a new operation creates a Java object class or array class. An AT NEW rule is triggered before the object or array is allocated. An AFTER NEW rule is triggered after creation and initialization of the object or array.\n\nSelection of the NEW trigger location may be constrained by supplying a variety of optional arguments, a type name, one or more pairs of square braces and either an integer count or the keyword ALL. These arguments may all be specified independently and they each serve to select a more or less precise set of matches for points where the rule may be considered for injection into the target method.\n\nIf a type name is supplied injection is limited to points where an instance (or array) of the named type is created. The type name can be supplied without a package qualifier, in which case any new operation with a type sharing the same non-package qualified name will match.\n\nIf the type name is omitted then injection can occur at any point where an instance (or array) is created.\n\nNote that extends and implements relationships are ignored when matching. For example, if a rule specifies AT NEW Foo then the location will not be matched against operation new Foobar even if FooBar extends Foo. Similarly, when Foo implements IFoo specifying location AT NEW IFoo will not be matched. Indeed specifying any interface is a mistake. new operations always instantiate a specific class and never an interface. So, locations specifying an interface name will never match.\n\nIf one or more brace pairs are included then injection is limited to points in the method where an array with the equivalent number of dimensions is created. So, for example specifying AT NEW [][] will match any new operation where a 2d array is created, irrespective of what the array base type is, By contrast, specifying AT NEW int[] will only match a new operation where a 1d int array is created. If no braces are supplied then matches will be restricted to new operations where a Java object class (i.e. a non-array class) is instantiated.\n\nWhen there are multiple canidate injection points in a method an integer count may be supplied to pick a specific injection point (count defaults to 1 if it is left unspecified). Keyword ALL can be supplied to request injection at all matching injection points.\n"
"[type .] field [count | ALL ] or $var-or-idx [count | ALL ] ; follwoing AT, an AT READ specifier followed by a field name locates the trigger point before the first mention of an object field whose name matches the supplied field name i.e. it corresponds to the first occurred of a corresponding getField instruction in the bytecode. If a type is specified then the getField instruction will only be matched if the named field is declared by a class whose name matches the supplied type. If a count N is supplied then the Nth matching getField will be used as the trigger point. Note that the count identifies to the Nth textual occurence of the field access, not the Nth field access in a particular execution path at runtime. If the keyword ALL is specified in place of a count then the rule will be triggered at all matching getField calls. \n\nAn AT READ specifier followed by a $-prefixed local variable name, method parameter name or method parameter index locates the trigger point before the first instruction which reads the corresponding local or method parameter variable i.e. it corresponds to an iload, dload, aload etc instruction in the bytecode. If a count N is supplied then the Nth matching read will be used as the trigger point. Note that the count identifies to the Nth textual occurrence of a read of the variable, not the Nth access in a particular execution path at runtime. If the keyword ALL is specified in place of a count then the rule will be triggered before every read of the variable.\n\nNote that it is only possible to use local or parameter variable names such as $i, $this or $arg1 if the trigger method bytecode includes a local variable table, e.g. if it has been compiled with the -g flag. By contrast, it is always possible to refer to parameter variable read operations using the index notation $0, $1 etc (however, note that location AT READ $0 will only match where the trigger method is an instance method).\n"
"[ count | ALL ]\nAT SYNCHRONIZE and AT AFTER SYNCHRONIZE specifiers identify synchronization blocks in the target method, i.e. they correspond to MONITORENTER instructions in the bytecode. Note that AFTER SYNCHRONIZE identifies the point immediately after entry to the synchronized block rather than the point immediately after exit from the block."
" [count | ALL ] \n An AT THROW specifier identifies a throw operation within the trigger method as the trigger point. The throw operation may be qualified by a, possibly package-qualified, typename identifying the lexical type of the thrown exception. If a count N is supplied then the location specifies the Nth textual occurrence of a throw. If the keyword ALL is specified in place of a count then the rule will be triggered at all matching occurrences of a throw."
"Timers\n\nThe rule engine provides Timers which allow measurement of elapsed time between triggerings. Timers can be created, read, reset and deleted via the following API\n\n public boolean createTimer(Object o)\n public long getElapsedTimeFromTimer(Object o)\n public long resetTimer(Object o)\n public boolean deleteTimer(Object o)\n\nAs before, Timers are identified by an arbitrary object. All methods are designed to be used in rule conditions or actions.\n\ncreateTimer can be called to create a new Timer associated with o. createTimer returns true if a new Timer was created and false if a Timer associated with o already exists.\n\ngetElapsedTimeFromTimer can be called to obtain the number of elapsed milliseconds since the Timer associated with o was created or since the last call to resetTimer. If no timer associated with o exists a new timer is created before returning the elapsed time.\n\nresetTimer can be called to zero the Timer associated with o. It returns the number of seconds since the Timer was created or since the last previous call to resetTimer If no timer associated with o exists a new timer is created before returning the elapsed time.\n\ndeleteTimer can be called to delete the Timer associated with o. deleteTimer returns true if a new Timer was deleted and false if no Timer associated with o exists.\n"
"(Object identifier, String filename)\ntraceClose closes the file associated with identifier and removes the association, returning true. If no open file is associated with identifier it returns false."
"(Object identifier, String filename) or (Object identifier)\ntrace prints message to file associated with identifier, returning true. If no open file is associated with identifier then a file will be opened and associated with identifier as if a call to trace had been made with no file name supplied. If identifier is omitted then the output is written to System.out.\nA caveat applies to the all trace* descriptions for three special cases. If identifier is null or the string \"out\", then trace and traceln write to System.out. If identifier is the string \"err\", then trace and traceln write to System.err. traceOpen and traceClose always return false immediately if identifier has any of these values. Calls to trace(message) and traceln(message) which omit identifier are implemented by calling, respectively, trace(\"out\", message) and traceln(\"out\", message)."
"(Object identifier, String filename) or (Object identifier)\ntraceOpen opens the file identified by fileName and associates it with identifier, returning true. filename can be either a relative or absolute path. Relative file names are located relative to the current working directory of the JVM. If there is already a file associated with identifier then traceOpen immediately returns false. If a file with the given name already exists it is opened in append mode. If filename is omitted then a unique name is generated for the file which is guaranteed not to match any existing trace file in the current working directory."
"(Object identifier, String filename) or (Object identifier)\ntraceln prints message to file associated with identifier and appends a newline to the file, returning true. If no open file is associated with identifier then a file will be opened and associated with identifier as if a call to trace had been made "
"following AT, [ type .] field [count | ALL ] or $var-or-idx [count | ALL ] ; \n\nAT WRITE and AFTER WRITE specifiers are the same as the corresponding READ specifiers except that they correspond to assignments to the named field or named variable in the source code i.e. they identify putField or istore, dstore, etc instructions.\n\nNote that location AT WRITE $0 or, equivalently, AT WRITE $this will never match any candidate trigger method because the target object for an instance method invocation is never assigned.\n\nNote also that for a given local variable, localvar, location AT WRITE $localvar or, equivalently, AT WRITE $localvar 1 identifies the location immediately after the local variable is initialised i.e. it is treated as if it were specified as AFTER WRITE $localvar. This is necessary because the variable is not in scope until after it is initialised. This also ensures that the local variable which has been written can be safely accessed in the rule body.\n"