[jboss-svn-commits] JBL Code SVN: r24000 - in labs/jbosstm/workspace/adinn/orchestration: src/org/jboss/jbossts/orchestration and 5 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Nov 20 12:28:49 EST 2008


Author: adinn
Date: 2008-11-20 12:28:48 -0500 (Thu, 20 Nov 2008)
New Revision: 24000

Added:
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Location.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/LocationType.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Script.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/AccessCheckAdapter.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/AccessTriggerAdapter.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/InvokeCheckAdapter.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/InvokeTriggerAdapter.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineCheckAdapter.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineTriggerAdapter.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleAdapter.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleCheckAdapter.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleTriggerAdapter.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/SynchronizeCheckAdapter.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/SynchronizeTriggerAdapter.java
Removed:
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/RuleAdapter.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/RuleCheckAdapter.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/annotation/
Modified:
   labs/jbosstm/workspace/adinn/orchestration/handler.txt
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Main.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Transformer.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Rule.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/type/TypeHelper.java
   labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/test/TestScript.java
Log:
modified to allow various extra specifiers for where to place the trigger point besides (AT) LINE

Modified: labs/jbosstm/workspace/adinn/orchestration/handler.txt
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/handler.txt	2008-11-20 17:20:26 UTC (rev 23999)
+++ labs/jbosstm/workspace/adinn/orchestration/handler.txt	2008-11-20 17:28:48 UTC (rev 24000)
@@ -83,7 +83,7 @@
 RULE add coordinator engine countdown
 CLASS com.arjuna.wst11.messaging.engines.CoordinatorEngine
 METHOD <init>(String, boolean, W3CEndpointReference, boolean, State)
-LINE 96
+AFTER WRITE recovered
 BIND engine:CoordinatorEngine = $0,
      recovered:boolean = engine.isRecovered(),
      identifier:String = engine.getId()
@@ -102,7 +102,7 @@
 RULE kill JVM
 CLASS com.arjuna.wst11.messaging.engines.CoordinatorEngine
 METHOD commit
-LINE 316
+AT SYNCHRONIZE
 BIND engine:CoordinatorEngine = $0,
      recovered:boolean = engine.isRecovered(), 
      identifier:String = engine.getId()
@@ -125,7 +125,7 @@
 RULE countdown at commit
 CLASS com.arjuna.wst11.messaging.engines.CoordinatorEngine
 METHOD commit
-LINE 316
+AFTER SYNCHRONIZE
 BIND engine:CoordinatorEngine = $0,
      recovered:boolean = engine.isRecovered(),
      identifier:String = engine.getId()
@@ -151,7 +151,7 @@
 RULE kill committed thread
 CLASS com.arjuna.wst11.messaging.engines.CoordinatorEngine
 METHOD committed(Notification, AddressingProperties, ArjunaContext)
-LINE -1
+AT ENTRY
 BIND engine:CoordinatorEngine = $0,
      recovered:boolean = engine.isRecovered(),
      identifier:String = engine.getId()
@@ -175,7 +175,7 @@
 RULE trace prepared replay
 CLASS org.jboss.jbossts.xts.recovery.coordinator.at.RecoverACCoordinator
 METHOD replayPhase2
-LINE 74
+AT INVOKE phase2Commit
 BIND coordinator = $0,
      uid : Uid = coordinator.identifier(),
      status : int = coordinator.status()
@@ -196,7 +196,7 @@
 RULE trace heuristic committed replay
 CLASS org.jboss.jbossts.xts.recovery.coordinator.at.RecoverACCoordinator
 METHOD replayPhase2
-LINE 74
+AT INVOKE phase2Commit
 BIND coordinator = $0,
      uid : Uid = coordinator.identifier(),
      status : int = coordinator.status()
@@ -215,7 +215,7 @@
 RULE trace remove committed state
 CLASS com.arjuna.ats.arjuna.coordinator.BasicAction
 METHOD updateState
-LINE 3529
+AFTER CALL remove_committed
 BIND action : BasicAction = $0,
      uid  = action.get_uid()
 IF TRUE

Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Location.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Location.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Location.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,555 @@
+package org.jboss.jbossts.orchestration.agent;
+
+import org.objectweb.asm.ClassVisitor;
+import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.type.TypeHelper;
+import org.jboss.jbossts.orchestration.agent.adapter.*;
+
+/**
+ * Specifies a location in a method at which a rule trigger should be inserted
+ */
+public abstract class Location
+{
+    /**
+     * create a location object of a given type
+     * @param type the type of location being specified
+     * @param parameters the text of the parameters appended to the location specifier
+     * @return a location of the appropriate type or null if the parameters are incorrectly specified
+     */
+    public static Location create(LocationType type, String parameters)
+    {
+        switch (type)
+        {
+            case ENTRY:
+                return EntryLocation.create(parameters);
+            case LINE:
+                return LineLocation.create(parameters);
+            case READ:
+                return AccessLocation.create(parameters, ACCESS_READ, false);
+            case READ_COMPLETED:
+                return AccessLocation.create(parameters, ACCESS_READ, true);
+            case WRITE:
+                return AccessLocation.create(parameters, ACCESS_WRITE, false);
+            case WRITE_COMPLETED:
+                return AccessLocation.create(parameters, ACCESS_WRITE, true);
+            case INVOKE:
+                return InvokeLocation.create(parameters, false);
+            case INVOKE_COMPLETED:
+                return InvokeLocation.create(parameters, true);
+            case SYNCHRONIZE:
+                return SynchronizeLocation.create(parameters, false);
+            case SYNCHRONIZE_COMPLETED:
+                return SynchronizeLocation.create(parameters, true);
+        }
+
+        return null;
+    }
+
+    /**
+     * return an adapter which can be used to check whether a method contains a trigger point whose position
+     * matches this location
+     * @return the required adapter
+     */
+    public abstract RuleCheckAdapter getRuleCheckAdapter(ClassVisitor cv, String targetClass, String targetMethod);
+
+    /**
+     * return an adapter which can be used to insert a trigger call in a method containing a trigger point whose
+     * position matches this location
+     * @return the required adapter
+     */
+    public abstract RuleTriggerAdapter getRuleAdapter(ClassVisitor cv, Rule rule, String targetClass, String targetMethod);
+
+    /**
+     * flag indicating that a field access location refers to field READ operations
+     */
+    public static final int ACCESS_READ = 1;
+
+    /**
+     * flag indicating that a field access location refers to field WRITE operations
+     */
+    public static final int ACCESS_WRITE = 2;
+
+    /**
+     * location identifying a method entry trigger point
+     */
+    private static class EntryLocation extends Location
+    {
+        /**
+         * create a location identifying a method entry trigger point
+         * @param parameters the text of the parameters appended to the location specifier
+         * @return a method entry location or null if the parameters is not a blank String
+         */
+        protected static Location create(String parameters) {
+            if (!parameters.trim().equals("")) {
+                // hmm, not expecting any parameters here
+                return null;
+            }
+            return new EntryLocation();
+        }
+
+        /**
+         * return an adapter which can be used to check whether a method contains a trigger point whose position
+         * matches this location
+         * @return the required adapter
+         */
+        public RuleCheckAdapter getRuleCheckAdapter(ClassVisitor cv, String targetClass, String targetMethod) {
+            // a line check adapter with line -1 will do the job
+
+            return new LineCheckAdapter(cv, targetClass, targetMethod, -1);
+        }
+
+        /**
+         * return an adapter which can be used to insert a trigger call in a method containing a trigger point whose
+         * position matches this location
+         * @return the required adapter
+         */
+        public RuleTriggerAdapter getRuleAdapter(ClassVisitor cv, Rule rule, String targetClass, String targetMethod) {
+            // a line adapter with line -1 will do the job
+
+            return new LineTriggerAdapter(cv, rule, targetClass, targetMethod, -1);
+        }
+
+        public String toString() {
+            return "AT ENTRY";
+        }
+    }
+
+    /**
+     * location identifying a method line trigger point
+     */
+    private static class LineLocation extends Location
+    {
+        /**
+         * the line at which the trigger point should be inserted
+         */
+        private int targetLine;
+
+        /**
+         * construct a location identifying a method line trigger point
+         * @param targetLine the line at which the trigger point should be inserted
+         */
+        private LineLocation(int targetLine)
+        {
+            this.targetLine = targetLine;
+        }
+
+        /**
+         * create a location identifying a method entry trigger point
+         * @param parameters the text of the parameters appended to the location specifier
+         * @return a method entry location or null if the parameters is not a blank String
+         */
+        protected static Location create(String parameters)
+        {
+            try {
+                int targetLine = Integer.decode(parameters.trim());
+                return new LineLocation(targetLine);
+            } catch (NumberFormatException nfe) {
+                return null;
+            }
+        }
+
+        /**
+         * return an adapter which can be used to check whether a method contains a trigger point whose position
+         * matches this location
+         * @return the required adapter
+         */
+        public RuleCheckAdapter getRuleCheckAdapter(ClassVisitor cv, String targetClass, String targetMethod) {
+            return new LineCheckAdapter(cv, targetClass, targetMethod, targetLine);
+        }
+
+        /**
+         * return an adapter which can be used to insert a trigger call in a method containing a trigger point whose
+         * position matches this location
+         * @return the required adapter
+         */
+        public RuleTriggerAdapter getRuleAdapter(ClassVisitor cv, Rule rule, String targetClass, String targetMethod) {
+            return new LineTriggerAdapter(cv, rule, targetClass,targetMethod, targetLine);
+        }
+
+        public String toString() {
+            return "AT LINE " + targetLine;
+        }
+    }
+
+    /**
+     * location identifying a method field access trigger point
+     */
+    private static class AccessLocation extends Location
+    {
+        /**
+         * the name of the field being accessed at the point where the trigger point should be inserted
+         */
+        private String fieldName;
+
+        /**
+         * the name of the type to which the field belongs or null if any type will do
+         */
+        private String typeName;
+
+        /**
+         * count identifying which access should be taken as the trigger point. if not specified
+         * as a parameter this defaults to the first access.
+         */
+        private int count;
+
+        /**
+         * flags identifying which type of access should be used to identify the trigger. this is either
+         * ACCESS_READ, ACCESS_WRITE or an OR of these two values
+         */
+        private int flags;
+
+        /**
+         * flag which is false if the trigger should be inserted before the field access is performed
+         * and true if it should be inserted after
+         */
+        private boolean whenComplete;
+
+        /**
+         * construct a location identifying a field read trigger point
+         * @param typeName the name of the class owning the field
+         * @param fieldName the name of the field being read
+         * @param count count identifying which access should be taken as the trigger point
+         * @param flags bit field comprising one or other of flags ACCESS_READ and ACCESS_WRITE identifying
+         * whether this specifies field READ or WRITE operations
+         * @param whenComplete false if the trigger should be inserted before the access is performed
+         * and true if it should be inserted after
+         */
+        private AccessLocation(String typeName, String fieldName, int count, int flags, boolean whenComplete)
+        {
+            this.typeName = typeName;
+            this.fieldName = fieldName;
+            this.count = count;
+            this.flags = flags;
+            this.whenComplete = whenComplete;
+        }
+
+        /**
+         * create a location identifying a method entry trigger point
+         * @param parameters the text of the parameters appended to the location specifier
+         * @param whenComplete false if the trigger should be inserted before the access is performed
+         * and true if it should be inserted after
+         * @return a method entry location or null if the parameters is not a blank String
+         */
+        protected static Location create(String parameters, int flags, boolean whenComplete)
+        {
+            String text = parameters.trim();
+            String typeName;
+            String fieldName;
+            int count;
+
+            // check for trailing count
+            if (text.contains(" ")) {
+                int spaceIdx = text.lastIndexOf(" ");
+                String countText = text.substring(spaceIdx).trim();
+                try {
+                    count = Integer.valueOf(countText);
+                } catch (NumberFormatException nfe) {
+                    return null;
+                }
+                text = text.substring(0, spaceIdx).trim();
+            } else {
+                count = 1;
+            }
+            // check for leading type name
+            if (text.contains(".")) {
+                int dotIdx = text.lastIndexOf(".");
+                typeName = text.substring(0, dotIdx).trim();
+                fieldName=text.substring(dotIdx + 1).trim();
+            } else {
+                typeName = null;
+                fieldName = text;
+            }
+            // TODO sanity check type and field name
+                
+            return new AccessLocation(typeName, fieldName, count, flags, whenComplete);
+        }
+
+        /**
+         * return an adapter which can be used to check whether a method contains a trigger point whose position
+         * matches this location
+         * @return the required adapter
+         */
+        public RuleCheckAdapter getRuleCheckAdapter(ClassVisitor cv, String targetClass, String targetMethod) {
+            return new AccessCheckAdapter(cv, targetClass, targetMethod, typeName, fieldName, flags, count);
+        }
+
+        /**
+         * return an adapter which can be used to insert a trigger call in a method containing a trigger point whose
+         * position matches this location
+         * @return the required adapter
+         */
+        public RuleTriggerAdapter getRuleAdapter(ClassVisitor cv, Rule rule, String targetClass, String targetMethod) {
+            return new AccessTriggerAdapter(cv, rule, targetClass, targetMethod, typeName, fieldName, flags, count, whenComplete);
+        }
+
+        public String toString() {
+            String text;
+
+            if (whenComplete) {
+                text = "AFTER ";
+            } else {
+                text = "AT ";
+            }
+            if (flags == ACCESS_READ) {
+                text += "READ ";
+            } else if (flags == ACCESS_WRITE) {
+                text += "WRITE ";
+            } else {
+                text += "ACCESS ";
+            }
+
+            if (typeName != null) {
+                text += typeName + ".";
+            }
+            text += fieldName;
+
+            if (count != 1) {
+                text += " " + count;
+            }
+
+            return text;
+        }
+    }
+
+    /**
+     * location identifying a method invocation trigger point
+     */
+    private static class InvokeLocation extends Location
+    {
+        /**
+         * the name of the method being invoked at the point where the trigger point should be inserted
+         */
+        private String methodName;
+
+        /**
+         * the name of the type to which the method belongs or null if any type will do
+         */
+        private String typeName;
+
+        /**
+         * the method signature in externalised form
+         */
+        private String signature;
+
+        /**
+         * count identifying which invocation should be taken as the trigger point. if not specified
+         * as a parameter this defaults to the first invocation.
+         */
+        private int count;
+
+        /**
+         * flag which is false if the trigger should be inserted before the method invocation is performed
+         * and true if it should be inserted after
+         */
+        private boolean whenComplete;
+
+        /**
+         * construct a location identifying a method invocation trigger point
+         * @param typeName the name of the class owning the method
+         * @param methodName the name of the method being called
+         * @param signature the method signature in externalised form
+         * @param count count identifying which invocation should be taken as the trigger point
+         * @param whenComplete false if the trigger should be inserted before the method invocation is
+         * performed and true if it should be inserted after
+         */
+        private InvokeLocation(String typeName, String methodName, String signature, int count, boolean whenComplete)
+        {
+            this.typeName = typeName;
+            this.methodName = methodName;
+            this.signature = signature;
+            this.count = count;
+            this.whenComplete = whenComplete;
+        }
+
+        /**
+         * create a location identifying a method entry trigger point
+         * @param parameters the text of the parameters appended to the location specifier
+         * @param whenComplete false if the trigger should be inserted before the access is performed
+         * and true if ti shoudl be inserted after
+         * @return a method entry location or null if the parameters is not a blank String
+         */
+        protected static Location create(String parameters, boolean whenComplete)
+        {
+            String text = parameters.trim();
+            String typeName;
+            String fieldName;
+            String signature;
+            int count;
+
+            // check for trailing count
+            if (text.contains(")")) {
+                int tailIdx = text.lastIndexOf(")");
+                String countText = text.substring(tailIdx + 1).trim();
+                try {
+                    count = Integer.valueOf(countText);
+                } catch (NumberFormatException nfe) {
+                    return null;
+                }
+                text = text.substring(0, tailIdx).trim();
+            } else if (text.contains(" ")) {
+                int tailIdx = text.lastIndexOf(" ");
+                String countText = text.substring(tailIdx + 1).trim();
+                try {
+                    count = Integer.valueOf(countText);
+                } catch (NumberFormatException nfe) {
+                    return null;
+                }
+                text = text.substring(0, tailIdx).trim();
+            } else {
+                count = 1;
+            }
+            // check for argument list
+            if (text.contains("(")) {
+                text=TypeHelper.parseMethodName(text);
+                signature = TypeHelper.parseMethodDescriptor(text);
+            } else {
+                signature = "";
+            }
+            // check for leading type name
+            if (text.contains(".")) {
+                int dotIdx = text.lastIndexOf(".");
+                typeName = text.substring(0, dotIdx).trim();
+                fieldName=text.substring(dotIdx + 1).trim();
+            } else {
+                typeName = null;
+                fieldName = text;
+            }
+            // TODO sanity check type and field name
+
+            return new InvokeLocation(typeName, fieldName, signature, count, whenComplete);
+        }
+
+        /**
+         * return an adapter which can be used to check whether a method contains a trigger point whose position
+         * matches this location
+         * @return the required adapter
+         */
+        public RuleCheckAdapter getRuleCheckAdapter(ClassVisitor cv, String targetClass, String targetMethod) {
+            return new InvokeCheckAdapter(cv, targetClass, targetMethod, typeName, methodName, signature, count);
+        }
+
+        /**
+         * return an adapter which can be used to insert a trigger call in a method containing a trigger point whose
+         * position matches this location
+         * @return the required adapter
+         */
+        public RuleTriggerAdapter getRuleAdapter(ClassVisitor cv, Rule rule, String targetClass, String targetMethod) {
+            return new InvokeTriggerAdapter(cv, rule, targetClass, targetMethod, typeName, methodName, signature, count, whenComplete);
+        }
+
+        public String toString() {
+            String text;
+
+            if (whenComplete) {
+                text = "AFTER INVOKE ";
+            } else {
+                text = "AT INVOKE ";
+            }
+
+            if (typeName != null) {
+                text += typeName + ".";
+            }
+            text += methodName;
+
+            if (signature.length() > 0) {
+                text = text + TypeHelper.internalizeDescriptor(signature);
+            }
+            
+            if (count != 1) {
+                text += " " + count;
+            }
+
+            return text;
+        }
+    }
+
+    /**
+     * location identifying a synchronization trigger point
+     */
+    private static class SynchronizeLocation extends Location
+    {
+        /**
+         * count identifying which synchronization should be taken as the trigger point. if not specified
+         * as a parameter this defaults to the first synchronization.
+         */
+        private int count;
+
+        /**
+         * flag which is false if the trigger should be inserted before the synchronization is performed
+         * and true if it should be inserted after
+         */
+        private boolean whenComplete;
+
+        /**
+         * construct a location identifying a synchronization trigger point
+         * @param count count identifying which synchronization should be taken as the trigger point
+         * @param whenComplete false if the trigger should be inserted before the synchronization is
+         * performed and true if it should be inserted after
+         */
+        private SynchronizeLocation(int count, boolean whenComplete)
+        {
+            this.count = count;
+            this.whenComplete = whenComplete;
+        }
+
+        /**
+         * create a location identifying a synchronization trigger point
+         * @param parameters the text of the parameters appended to the location specifier
+         * @param whenComplete false if the trigger should be inserted before the synchronization is
+         * performed and true if it should be inserted after
+         * @return a method entry location or null if the parameters is not a blank String
+         */
+        protected static Location create(String parameters, boolean whenComplete)
+        {
+            String text = parameters.trim();
+            int count;
+
+            // check for count
+            if (text.length() != 0) {
+                try {
+                    count = Integer.valueOf(text);
+                } catch (NumberFormatException nfe) {
+                    return null;
+                }
+            } else {
+                count = 1;
+            }
+
+            return new SynchronizeLocation(count, whenComplete);
+        }
+
+        /**
+         * return an adapter which can be used to check whether a method contains a trigger point whose position
+         * matches this location
+         * @return the required adapter
+         */
+        public RuleCheckAdapter getRuleCheckAdapter(ClassVisitor cv, String targetClass, String targetMethod) {
+            return new SynchronizeCheckAdapter(cv, targetClass, targetMethod, count);
+        }
+
+        /**
+         * return an adapter which can be used to insert a trigger call in a method containing a trigger point whose
+         * position matches this location
+         * @return the required adapter
+         */
+        public RuleTriggerAdapter getRuleAdapter(ClassVisitor cv, Rule rule, String targetClass, String targetMethod) {
+            return new SynchronizeTriggerAdapter(cv, rule, targetClass, targetMethod, count, whenComplete);
+        }
+
+        public String toString() {
+            String text;
+
+            if (whenComplete) {
+                text= "AFTER SYNCHRONIZE";
+            } else {
+                text= "AT SYNCHRONIZE";
+            }
+
+            if (count != 1) {
+                text += " " + count;
+            }
+
+            return text;
+        }
+    }
+}

Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/LocationType.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/LocationType.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/LocationType.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,150 @@
+package org.jboss.jbossts.orchestration.agent;
+
+/**
+ * enum categorizing types of locations at which rule triggers can be inserted
+ */
+public enum LocationType
+{
+    /**
+     * specifies the default location for trigger insertion which is either the first line of a method or
+     * the first line of a constructor following any indirection via an alternative constructor or via
+     * the super constructor.
+     *
+     * script syntax : 'AT' 'ENTRY'
+     */
+    ENTRY,
+    /**
+     * specifies a location for trigger insertion via a line number.
+     *
+     * script syntax : 'AT' 'LINE' <linenumber>
+     */
+    LINE,
+    /**
+     * specifies a location for trigger insertion by identifying a field read operation or the nth such field
+     * read if a count is supplied.
+     *
+     * script syntax : 'AT' 'READ' [<typename> '.' ] <fieldname> [ <count> ]
+     */
+    READ,
+    /**
+     * specifies a location for trigger insertion by identifying a field read operation or the nth such field
+     * read if a count is supplied.
+     *
+     * script syntax : 'AFTER' 'READ' [<typename> '.' ] <fieldname> [ <count> ]
+     */
+    READ_COMPLETED,
+    /**
+     * specifies a location for trigger insertion by identifying a field write operation or the nth such field
+     * write if a count is supplied.
+     *
+     * script syntax : 'AT' 'WRITE' [<typename> '.' ] <fieldname> [ <count> ]
+     */
+    WRITE,
+    /**
+     * specifies a location for trigger insertion by identifying a field write operation or the nth such field
+     * write if a count is supplied.
+     *
+     * script syntax : 'AFTER' 'WRITE' [<typename> '.' ] <fieldname> [ <count> ]
+     */
+    WRITE_COMPLETED,
+    /**
+     * specifies a location for trigger insertion by identifying a method invoke operation or the nth such
+     * method invoke if a count is supplied.
+     *
+     * script syntax : 'AT' 'INVOKE' [<typename> '.' ] <methodname> ['(' <argtypes> ')' [ <count> ]
+     */
+    INVOKE,
+    /**
+     * specifies a location for trigger insertion by identifying return from a method invoke operation or the
+     * nth such return if a count is supplied.
+     *
+     * script syntax : 'AFTER' 'INVOKE' [<typename> '.' ] <methodname> ['(' <argtypes> ')' [ <count> ]
+     */
+    INVOKE_COMPLETED,
+    // this is tricky so we exclude it for now
+    // EXIT,
+    /**
+     * specifies a location for trigger insertion by identifying a synchronize operation or the nth such
+     * operation if a count is supplied.
+     *
+     * script syntax : 'AT' 'SYNCHRONIZE' [ <count> ]
+     */
+    SYNCHRONIZE,
+    /**
+     * specifies a location for trigger insertion by identifying completion of a synchronize operation or the
+     * nth such operation if a count is supplied.
+     *
+     * script syntax : 'AFTER' 'SYNCHRONIZE' [ <count> ]
+     */
+    SYNCHRONIZE_COMPLETED;
+
+    public String specifierText()
+    {
+        for (int i = 0; i < specifiers.length; i++) {
+            if (types[i] == this) {
+                return specifiers[i];
+            }
+        }
+        // hmm, well default to entry
+        return specifiers[0];
+    }
+
+    public static LocationType type(String locationSpec)
+    {
+        locationSpec = locationSpec.trim();
+        for (int i = 0; i < specifiers.length; i++) {
+            String specifier = specifiers[i];
+            if (locationSpec.startsWith(specifier)) {
+                return types[i];
+            }
+        }
+        // hmm, well default to entry
+        return null;
+    }
+
+    public static String parameterText(String locationSpec)
+    {
+        locationSpec = locationSpec.trim();
+        for (int i = 0; i < specifiers.length; i++) {
+            String specifier = specifiers[i];
+            if (locationSpec.startsWith(specifier)) {
+                return locationSpec.substring(specifier.length());
+            }
+        }
+        // hmm, doesn't really matter but ENTRY has no parameters
+
+        return "";
+    }
+
+    private static String[] specifiers = {
+            "AT ENTRY",
+            "AT LINE",
+            "AT READ",
+            "AFTER READ",
+            "AT WRITE",
+            "AFTER WRITE",
+            "AT INVOKE",
+            "AFTER INVOKE",
+            "AT SYNCHRONIZE",
+            "AFTER SYNCHRONIZE",
+            "LINE", // for compatibility
+            "AT CALL", // for ambiguity :-)
+            "AFTER CALL" // for ambiguity :-)
+    };
+
+    private static LocationType[] types = {
+            ENTRY,
+            LINE,
+            READ,
+            READ_COMPLETED,
+            WRITE,
+            WRITE_COMPLETED,
+            INVOKE,
+            INVOKE_COMPLETED,
+            SYNCHRONIZE,
+            SYNCHRONIZE_COMPLETED,
+            LINE,
+            INVOKE,
+            INVOKE_COMPLETED
+    };
+}

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Main.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Main.java	2008-11-20 17:20:26 UTC (rev 23999)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Main.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -23,21 +23,14 @@
 */
 package org.jboss.jbossts.orchestration.agent;
 
-import org.jboss.jbossts.orchestration.annotation.EventHandlerClass;
 
 import java.lang.instrument.Instrumentation;
-import java.lang.annotation.Annotation;
 import java.util.jar.JarFile;
-import java.util.jar.JarEntry;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Enumeration;
 import java.io.File;
 import java.io.IOException;
 import java.io.FileInputStream;
-import java.net.URLClassLoader;
-import java.net.URL;
-import java.net.MalformedURLException;
 
 /**
  * agent class supplied at JVM startup to install orchestration package bytecode transformer

Deleted: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/RuleAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/RuleAdapter.java	2008-11-20 17:20:26 UTC (rev 23999)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/RuleAdapter.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -1,252 +0,0 @@
-/*
-* 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.jbossts.orchestration.agent;
-
-import org.jboss.jbossts.orchestration.rule.Rule;
-import org.jboss.jbossts.orchestration.rule.type.TypeHelper;
-import org.objectweb.asm.*;
-import org.objectweb.asm.commons.GeneratorAdapter;
-import org.objectweb.asm.commons.Method;
-
-/**
- * asm Adapter class used to add a rule event trigger call to a method of som egiven class
- */
-public class RuleAdapter extends ClassAdapter
-{
-    RuleAdapter(ClassVisitor cv, Rule rule, String targetClass, String handlerMethod, int handlerLine)
-    {
-        super(cv);
-        this.rule = rule;
-        this.targetClass = targetClass;
-        this.targetMethod = TypeHelper.parseMethodName(handlerMethod);
-        this.targetDescriptor = TypeHelper.parseMethodDescriptor(handlerMethod);
-        this.targetLine = handlerLine;
-        this.visitedLine = false;
-    }
-
-    void visitClass(
-            final int version,
-            final int access,
-            final String name,
-            final String signature,
-            final String superName,
-            final String[] interfaces)
-    {
-        super.visit(version, access, name, signature, superName, interfaces);
-    }
-
-    public FieldVisitor visitField(
-        final int access,
-        final String name,
-        final String desc,
-        final String signature,
-        final Object value)
-    {
-        FieldVisitor fv = super.visitField(access, name, desc, signature, value);
-        return fv;
-    }
-
-    public MethodVisitor visitMethod(
-        final int access,
-        final String name,
-        final String desc,
-        final String signature,
-        final String[] exceptions)
-    {
-        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
-        if (targetMethod.equals(name)) {
-            if (targetDescriptor.equals("") || TypeHelper.equalDescriptors(targetDescriptor, desc))
-            {
-                if (name == "<init>") {
-                    return new RuleConstructorAdapter(mv, access, name, desc, signature, exceptions);
-                } else {
-                    return new RuleMethodAdapter(mv, access, name, desc, signature, exceptions);
-                }
-            }
-        }
-
-        return mv;
-    }
-
-    /**
-     * a method visitor used to add a rule event trigger call to a method
-     */
-
-    private class RuleMethodAdapter extends GeneratorAdapter
-    {
-        private int access;
-        private String name;
-        private String descriptor;
-        private String signature;
-        private String[] exceptions;
-        private Label startLabel;
-        private Label endLabel;
-
-        RuleMethodAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
-        {
-            super(mv, access, name, descriptor);
-            this.access = access;
-            this.name = name;
-            this.descriptor = descriptor;
-            this.signature = signature;
-            this.exceptions = exceptions;
-            startLabel = null;
-            endLabel = null;
-        }
-
-        // somewhere we need to add a catch exception block
-        // super.catchException(startLabel, endLabel, new Type("org.jboss.jbossts.orchestration.rule.exception.ExecuteException")));
-
-        public void visitLineNumber(final int line, final Label start) {
-            if (!visitedLine && (targetLine <= line)) {
-                rule.setTypeInfo(targetClass, access, name, descriptor, exceptions);
-                String key = rule.getKey();
-                Type ruleType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.Rule"));
-                Method method = Method.getMethod("void execute(String, Object, Object[])");
-                // we are at the relevant line in the method -- so add a trigger call here
-                System.out.println("RuleMethodAdapter.visitLineNumber : inserting trigger for " + rule.getName());
-                startLabel = super.newLabel();
-                endLabel = super.newLabel();
-                super.visitLabel(startLabel);
-                super.push(key);
-                if ((access & Opcodes.ACC_STATIC) == 0) {
-                    super.loadThis();
-                } else {
-                    super.push((Type)null);
-                }
-                super.loadArgArray();
-                super.invokeStatic(ruleType, method);
-                super.visitLabel(endLabel);
-                visitedLine = true;
-            }
-            super.visitLineNumber(line, start);
-        }
-
-        public void visitEnd()
-        {
-            /*
-             * unfortunately, if we generate the handler code here it comes too late for the stack size
-             * computation to take account of it. the handler code uses 4 stack slots so this causes and
-             * error when the method body uses less than 4. we can patch this by generating the handler
-             * code when visitMaxs is called
-            Type exceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ExecuteException"));
-            Type earlyReturnExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException"));
-            Type returnType =  Type.getReturnType(descriptor);
-            // add exception handling code subclass first
-            super.catchException(startLabel, endLabel, earlyReturnExceptionType);
-            if (returnType == Type.VOID_TYPE) {
-                // drop exception and just return
-                super.pop();
-                super.visitInsn(Opcodes.RETURN);
-            } else {
-                // fetch value from exception, unbox if needed and return value
-                Method getReturnValueMethod = Method.getMethod("Object getReturnValue()");
-                super.invokeVirtual(earlyReturnExceptionType, getReturnValueMethod);
-                super.unbox(returnType);
-                super.returnValue();
-            }
-            super.catchException(startLabel, endLabel, exceptionType);
-            super.throwException(exceptionType, rule.getName() + " execution exception ");
-            */
-            super.visitEnd();
-        }
-
-        public void visitMaxs(int maxStack, int maxLocals) {
-            /*
-             * this really ought to be in visitEnd but see above for why we do it here
-             */
-            Type exceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ExecuteException"));
-            Type earlyReturnExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException"));
-            Type throwExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ThrowException"));
-            Type throwableType = Type.getType(TypeHelper.externalizeType("java.lang.Throwable"));
-            Type returnType =  Type.getReturnType(descriptor);
-            // add exception handling code subclass first
-            super.catchException(startLabel, endLabel, earlyReturnExceptionType);
-            if (returnType == Type.VOID_TYPE) {
-                // drop exception and just return
-                super.pop();
-                super.visitInsn(Opcodes.RETURN);
-            } else {
-                // fetch value from exception, unbox if needed and return value
-                Method getReturnValueMethod = Method.getMethod("Object getReturnValue()");
-                super.invokeVirtual(earlyReturnExceptionType, getReturnValueMethod);
-                super.unbox(returnType);
-                super.returnValue();
-            }
-            super.catchException(startLabel, endLabel, throwExceptionType);
-            // fetch value from exception, unbox if needed and return value
-            Method getThrowableMethod = Method.getMethod("Throwable getThrowable()");
-            super.invokeVirtual(throwExceptionType, getThrowableMethod);
-            super.throwException();
-
-            super.catchException(startLabel, endLabel, exceptionType);
-            super.throwException(exceptionType, rule.getName() + " execution exception ");
-            // ok now recompute the stack size
-            super.visitMaxs(maxStack, maxLocals);
-        }
-
-    }
-
-    /**
-     * a method visitor used to add a rule event trigger call to a constructor -- this has to make sure
-     * the super constructor has been called before allowing a trigger call to be compiled
-     */
-
-    private class RuleConstructorAdapter extends RuleMethodAdapter
-    {
-        private boolean superCalled;
-
-        RuleConstructorAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
-        {
-            super(mv, access, name, descriptor, signature, exceptions);
-            this.superCalled = false;
-        }
-
-        // don't pass on line visits until we have seen an INVOKESPECIAL
-        public void visitLineNumber(final int line, final Label start) {
-            if (superCalled) {
-                super.visitLineNumber(line, start);
-            }
-        }
-
-        public void visitMethodInsn(
-            final int opcode,
-            final String owner,
-            final String name,
-            final String desc)
-        {
-            super.visitMethodInsn(opcode, owner, name, desc);
-            // hmm, this probably means the super constructor has been invoked :-)
-            superCalled &= (opcode == Opcodes.INVOKESPECIAL);
-        }
-    }
-
-    private Rule rule;
-    private String targetClass;
-    private String targetMethod;
-    private String targetDescriptor;
-    private int targetLine;
-    private String fieldName;
-    private boolean visitedLine;
-}

Deleted: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/RuleCheckAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/RuleCheckAdapter.java	2008-11-20 17:20:26 UTC (rev 23999)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/RuleCheckAdapter.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -1,114 +0,0 @@
-/*
-* 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.jbossts.orchestration.agent;
-
-import org.jboss.jbossts.orchestration.rule.Rule;
-import org.jboss.jbossts.orchestration.rule.exception.TypeException;
-import org.jboss.jbossts.orchestration.rule.type.TypeHelper;
-import org.objectweb.asm.*;
-
-/**
- * asm Adapter class used to check that the target method for a rule exists in a class
- */
-public class RuleCheckAdapter extends ClassAdapter
-{
-    RuleCheckAdapter(ClassVisitor cv, String targetClass, String handlerMethod, int handlerLine)
-    {
-        super(cv);
-        this.targetClass = targetClass;
-        this.targetMethod = TypeHelper.parseMethodName(handlerMethod);
-        this.targetDescriptor = TypeHelper.parseMethodDescriptor(handlerMethod);
-        this.targetLine = handlerLine;
-        this.visitOk = false;
-    }
-
-    public MethodVisitor visitMethod(
-        final int access,
-        final String name,
-        final String desc,
-        final String signature,
-        final String[] exceptions)
-    {
-        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
-        if (targetMethod.equals(name)) {
-            if (targetDescriptor.equals("") || TypeHelper.equalDescriptors(targetDescriptor, desc))
-            {
-                return new RuleCheckMethodAdapter(mv, access, name, desc, signature, exceptions);
-            }
-        }
-
-        return mv;
-    }
-
-    public boolean isVisitOk()
-    {
-        return visitOk;
-    }
-
-    /**
-     * a method visitor used to add a rule event trigger call to a method
-     */
-
-    private class RuleCheckMethodAdapter extends MethodAdapter
-    {
-        private int access;
-        private String name;
-        private String descriptor;
-        private String signature;
-        private String[] exceptions;
-        private boolean visited;
-
-        RuleCheckMethodAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
-        {
-            super(mv);
-            this.access = access;
-            this.name = name;
-            this.descriptor = descriptor;
-            this.signature = signature;
-            this.exceptions = exceptions;
-            this.visited = false;
-        }
-
-        public void visitLineNumber(final int line, final Label start) {
-            if (!visited && (targetLine <= line)) {
-                // the relevant line occurs in the called method
-                visited = true;
-                visitOk = true;
-                String name = targetClass + "." + targetMethod + targetDescriptor;
-                if (targetLine >= 0) {
-                    name += targetLine;
-                }
-            }
-            mv.visitLineNumber(line, start);
-        }
-
-    }
-
-    private Rule rule;
-    private String targetClass;
-    private String targetMethod;
-    private String targetDescriptor;
-    private int targetLine;
-    private boolean visitOk;
-}
\ No newline at end of file

Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Script.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Script.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Script.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,43 @@
+package org.jboss.jbossts.orchestration.agent;
+
+/**
+ * information about a single rule derived from a rule script
+ */
+
+public class Script
+{
+    private String name;
+    private String targetClass;
+    private String targetMethod;
+    private Location targetLocation;
+    private String ruleText;
+
+    Script (String name, String targetClass, String targetMethod, Location targetLocation, String ruleText)
+    {
+        this.name = name;
+        this.targetClass = targetClass;
+        this.targetMethod = targetMethod;
+        this.targetLocation = targetLocation;
+        this.ruleText = ruleText;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getTargetClass() {
+        return targetClass;
+    }
+
+    public String getTargetMethod() {
+        return targetMethod;
+    }
+
+    public Location getTargetLocation() {
+        return targetLocation;
+    }
+
+    public String getRuleText() {
+        return ruleText;
+    }
+}

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Transformer.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Transformer.java	2008-11-20 17:20:26 UTC (rev 23999)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Transformer.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -27,6 +27,8 @@
 import org.jboss.jbossts.orchestration.rule.type.TypeHelper;
 import org.jboss.jbossts.orchestration.rule.exception.ParseException;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
+import org.jboss.jbossts.orchestration.agent.adapter.RuleTriggerAdapter;
+import org.jboss.jbossts.orchestration.agent.adapter.RuleCheckAdapter;
 import org.objectweb.asm.*;
 import org.objectweb.asm.commons.EmptyVisitor;
 
@@ -71,12 +73,13 @@
                 String name = null;
                 String targetClass = null;
                 String targetMethod = null;
-                int targetLine = -1;
+                LocationType locationType = null;
+                Location targetLocation = null;
                 int lineNumber = 0;
                 int maxLines = lines.length;
                 boolean inRule = false;
                 for (String line : lines) {
-                   lineNumber++;
+                    lineNumber++;
                     if (line.trim().startsWith("#")) {
                         if (inRule) {
                             // add a blank line in place of the comment so the line numbers
@@ -95,12 +98,11 @@
                         targetClass = line.substring(6).trim();
                     } else if (line.startsWith("METHOD ")) {
                         targetMethod = line.substring(7).trim();
-                    } else if (line.startsWith("LINE ")) {
-                        String lineSpec = line.substring(5).trim();
-                        try {
-                            targetLine = Integer.valueOf(lineSpec);
-                        } catch (NumberFormatException e) {
-                            throw new Exception("org.jboss.jbossts.orchestration.agent.Transformer : invalid LINE specification " + lineSpec + "for RULE " + name + " in script " + scriptPaths.get(scriptIdx));
+                    } else if ((locationType = LocationType.type(line)) != null) {
+                        String parameters = LocationType.parameterText(line);
+                        targetLocation = Location.create(locationType, parameters);
+                        if (targetLocation == null) {
+                            throw new Exception("org.jboss.jbossts.orchestration.agent.Transformer : invalid target location at line " + lineNumber + " in script " + scriptPaths.get(scriptIdx));
                         }
                     } else if (line.startsWith("ENDRULE")) {
                         if (name == null) {
@@ -109,26 +111,29 @@
                             throw new Exception("org.jboss.jbossts.orchestration.agent.Transformer : no CLASS for RULE  " + name + " in script " + scriptPaths.get(scriptIdx));
                         } else if (targetMethod == null) {
                             throw new Exception("org.jboss.jbossts.orchestration.agent.Transformer : no METHOD for RULE  " + name + " in script " + scriptPaths.get(scriptIdx));
-                        } else if (targetMethod.startsWith("<init>") && targetLine < 0) {
-                            throw new Exception("org.jboss.jbossts.orchestration.agent.Transformer : rule for constructor METHOD " + targetMethod + " must specify source LINE in RULE " + name + " in script " + scriptPaths.get(scriptIdx));
                         } else {
                             List<Script> scripts = targetToScriptMap.get(targetClass);
                             if (scripts == null) {
                                 scripts = new ArrayList<Script>();
                                 targetToScriptMap.put(targetClass, scripts);
                             }
-                            Script script = new Script(name, targetClass, targetMethod, targetLine, nextRule);
+                            Script script = new Script(name, targetClass, targetMethod, targetLocation, nextRule);
                             scripts.add(script);
                             System.out.println("RULE " + script.getName());
                             System.out.println("CLASS " + script.getTargetClass());
                             System.out.println("METHOD " + script.getTargetMethod());
-                            System.out.println("LINE " + script.getTargetLine());
+                            if (targetLocation != null) {
+                                System.out.println(targetLocation);
+                            } else {
+                                System.out.println("AT ENTRY");
+                            }
                             System.out.println(script.getRuleText());
                             System.out.println("ENDRULE");
                         }
                         name = null;
                         targetClass = null;
                         targetMethod = null;
+                        targetLocation = null;
                         nextRule = "";
                         sepr = "";
                         inRule = false;
@@ -296,15 +301,15 @@
     {
         final String handlerClass = script.getTargetClass();
         final String handlerMethod = script.getTargetMethod();
-        final int handlerLine = script.getTargetLine();
+        final Location handlerLocation = script.getTargetLocation();
         System.out.println("org.jboss.jbossts.orchestration.agent.Transformer : Inserting trigger event");
         System.out.println("  class " + handlerClass);
         System.out.println("  method " + handlerMethod);
-        System.out.println("  line " + handlerLine);
+        System.out.println("  " + handlerLocation);
         final Rule rule;
         String ruleName = script.getName();
         try {
-            rule = Rule.create(ruleName, handlerClass, handlerMethod, handlerLine, script.getRuleText(), loader);
+            rule = Rule.create(ruleName, handlerClass, handlerMethod, handlerLocation, script.getRuleText(), loader);
         } catch (ParseException pe) {
             System.out.println("org.jboss.jbossts.orchestration.agent.Transformer : error parsing rule : " + pe);
             return targetClassBytes;
@@ -317,17 +322,17 @@
         }
         System.out.println(rule);
 
-        // ok, we have a rule with a matchingclass and a candidiate method and line number
+        // ok, we have a rule with a matchingclass and a candidiate method and location
         // we need to see if the class has a matching method and, if so, add a call to
         // execute the rule when we hit the relevant line
 
         ClassReader cr = new ClassReader(targetClassBytes);
         // ClassWriter cw = new ClassWriter(0);
         ClassVisitor empty = new EmptyVisitor();
-        RuleCheckAdapter checkAdapter = new RuleCheckAdapter(empty, className, handlerMethod, handlerLine);
+        RuleCheckAdapter checkAdapter = handlerLocation.getRuleCheckAdapter(empty, className, handlerMethod);
         // PrintWriter pw = new PrintWriter(System.out);
         // ClassVisitor traceAdapter = new TraceClassVisitor(cw, pw);
-        // RuleCheckAdapter adapter = new RuleAdapter(traceAdapter, rule, className, handlerMethod, handlerLine, loader);
+        // RuleCheckAdapter adapter = handlerLocation.getRuleCheckAdapter(traceAdapter, rule, className, handlerMethod);
         try {
             cr.accept(checkAdapter, 0);
         } catch (Throwable th) {
@@ -335,14 +340,14 @@
             th.printStackTrace(System.out);
             return targetClassBytes;
         }
-        // only insert the rule trigger call if there is a suitable line in the target method
+        // only insert the rule trigger call if there is a suitable location in the target method
         if (checkAdapter.isVisitOk()) {
             cr = new ClassReader(targetClassBytes);
             ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
             // PrintWriter pw = new PrintWriter(System.out);
             // ClassVisitor traceAdapter = new TraceClassVisitor(cw, pw);
-            // RuleAdapter adapter = new RuleAdapter(traceAdapter, rule, className, handlerMethod, handlerLine);
-            RuleAdapter adapter = new RuleAdapter(cw, rule, className, handlerMethod, handlerLine);
+            // RuleTriggerAdapter adapter = handlerLocation.getRuleAdapter(traceAdapter, rule, className, handlerMethod);
+            RuleTriggerAdapter adapter = handlerLocation.getRuleAdapter(cw, rule, className, handlerMethod);
             try {
                 cr.accept(adapter, 0);
             } catch (Throwable th) {
@@ -389,47 +394,6 @@
     private final HashMap<String, List<Script>> targetToScriptMap;
 
     /**
-     * information about a single rule derived from a rule script
-     */
-    
-    private static class Script
-    {
-        private String name;
-        private String targetClass;
-        private String targetMethod;
-        private int targetLine;
-        private String ruleText;
-
-        Script (String name, String targetClass, String targetMethod, int targetLine, String ruleText)
-        {
-            this.name = name;
-            this.targetClass = targetClass;
-            this.targetMethod = targetMethod;
-            this.targetLine = targetLine;
-            this.ruleText = ruleText;
-        }
-
-        public String getName() {
-            return name;
-        }
-
-        public String getTargetClass() {
-            return targetClass;
-        }
-
-        public String getTargetMethod() {
-            return targetMethod;
-        }
-
-        public int getTargetLine() {
-            return targetLine;
-        }
-
-        public String getRuleText() {
-            return ruleText;
-        }
-    }
-    /**
      *  switch to control dumping of generated bytecode to .class files
      */
     private final static boolean dumpGeneratedClasses = (System.getProperty(DUMP_GENERATED_CLASSES) != null);

Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/AccessCheckAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/AccessCheckAdapter.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/AccessCheckAdapter.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,141 @@
+/*
+* 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.jbossts.orchestration.agent.adapter;
+
+import org.objectweb.asm.*;
+import org.jboss.jbossts.orchestration.agent.Location;
+
+/**
+ * asm Adapter class used to check that the target method for a rule exists in a class
+ */
+public class AccessCheckAdapter extends RuleCheckAdapter
+{
+     public AccessCheckAdapter(ClassVisitor cv, String targetClass, String targetMethod, String ownerClass,
+                       String fieldName,  int flags, int count)
+    {
+        super(cv, targetClass, targetMethod);
+        this.ownerClass = ownerClass;
+        this.fieldName = fieldName;
+        this.flags = flags;
+        this.count = count;
+        this.visitedCount = 0;
+    }
+
+    public MethodVisitor visitMethod(
+        final int access,
+        final String name,
+        final String desc,
+        final String signature,
+        final String[] exceptions)
+    {
+        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+        if (matchTargetMethod(name, desc)) {
+            return new AccessCheckMethodAdapter(mv, access, name, desc, signature, exceptions);
+        }
+
+        return mv;
+    }
+
+    /**
+     * a method visitor used to add a rule event trigger call to a method
+     */
+
+    private class AccessCheckMethodAdapter extends MethodAdapter
+    {
+        private int access;
+        private String name;
+        private String descriptor;
+        private String signature;
+        private String[] exceptions;
+        private boolean visited;
+
+        AccessCheckMethodAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
+        {
+            super(mv);
+            this.access = access;
+            this.name = name;
+            this.descriptor = descriptor;
+            this.signature = signature;
+            this.exceptions = exceptions;
+            visitedCount = 0;
+        }
+
+        public void visitFieldInsn(
+            final int opcode,
+            final String owner,
+            final String name,
+            final String desc)
+        {
+            if (visitedCount < count && matchCall(opcode, owner, name, desc)) {
+                // a relevant invocation occurs in the called method
+                visitedCount++;
+                if (visitedCount == count) {
+                    // and we have enough occurences to match the count
+                    setVisitOk();
+                }
+            }
+            super.visitFieldInsn(opcode, owner, name, desc);
+        }
+
+        private boolean matchCall(int opcode, String owner, String name, String desc)
+        {
+            if (!fieldName.equals(name)) {
+                return false;
+            }
+            
+            switch (opcode) {
+                case Opcodes.GETSTATIC:
+                case Opcodes.GETFIELD:
+                {
+                    if ((flags & Location.ACCESS_READ) == 0) {
+                        return false;
+                    }
+                }
+                break;
+                case Opcodes.PUTSTATIC:
+                case Opcodes.PUTFIELD:
+                {
+                    if ((flags & Location.ACCESS_WRITE) == 0) {
+                        return false;
+                    }
+                }
+                break;
+            }
+            if (ownerClass != null) {
+                if (!ownerClass.equals(owner)) {
+                    // TODO check for unqualified names
+                    return false;
+                }
+            }
+            // TODO work out how to use desc???
+            return true;
+        }
+    }
+
+    private String ownerClass;
+    private String fieldName;
+    private int flags;
+    private int count;
+    private int visitedCount;
+}
\ No newline at end of file

Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/AccessTriggerAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/AccessTriggerAdapter.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/AccessTriggerAdapter.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,276 @@
+/*
+* 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.jbossts.orchestration.agent.adapter;
+
+import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.type.TypeHelper;
+import org.jboss.jbossts.orchestration.agent.Location;
+import org.objectweb.asm.*;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.Method;
+
+/**
+ * asm Adapter class used to add a rule event trigger call to a method of som egiven class
+ */
+public class AccessTriggerAdapter extends RuleTriggerAdapter
+{
+    public AccessTriggerAdapter(ClassVisitor cv, Rule rule, String targetClass, String targetMethod, String ownerClass,
+                       String fieldName, int flags, int count, boolean whenComplete)
+    {
+        super(cv, rule, targetClass, targetMethod);
+        this.ownerClass = ownerClass;
+        this.fieldName = fieldName;
+        this.flags = flags;
+        this.count = count;
+        this.whenComplete = whenComplete;
+        this.visitedCount = 0;
+    }
+
+    public MethodVisitor visitMethod(
+        final int access,
+        final String name,
+        final String desc,
+        final String signature,
+        final String[] exceptions)
+    {
+        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+        if (matchTargetMethod(name, desc)) {
+            if (name == "<init>") {
+                return new AccessTriggerConstructorAdapter(mv, access, name, desc, signature, exceptions);
+            } else {
+                return new AccessTriggerMethodAdapter(mv, access, name, desc, signature, exceptions);
+            }
+        }
+        return mv;
+    }
+
+    /**
+     * a method visitor used to add a rule event trigger call to a method
+     */
+
+    private class AccessTriggerMethodAdapter extends GeneratorAdapter
+    {
+        /**
+         * flag used by subclass to avoid inserting trigger until after super constructor has been called
+         */
+        protected boolean latched;
+        private int access;
+        private String name;
+        private String descriptor;
+        private String signature;
+        private String[] exceptions;
+        private Label startLabel;
+        private Label endLabel;
+
+        AccessTriggerMethodAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
+        {
+            super(mv, access, name, descriptor);
+            this.access = access;
+            this.name = name;
+            this.descriptor = descriptor;
+            this.signature = signature;
+            this.exceptions = exceptions;
+            startLabel = null;
+            endLabel = null;
+            visitedCount = 0;
+            latched = false;
+        }
+
+        // somewhere we need to add a catch exception block
+        // super.catchException(startLabel, endLabel, new Type("org.jboss.jbossts.orchestration.rule.exception.ExecuteException")));
+
+        public void visitFieldInsn(
+            final int opcode,
+            final String owner,
+            final String name,
+            final String desc)
+        {
+            if (whenComplete) {
+                // access the field before generating the trigger call
+                super.visitFieldInsn(opcode, owner, name, desc);
+            }
+            if (visitedCount < count && matchCall(opcode, owner, name, desc)) {
+                // a relevant invocation occurs in the called method
+                visitedCount++;
+                if (!latched && visitedCount == count) {
+                    rule.setTypeInfo(targetClass, access, name, descriptor, exceptions);
+                    String key = rule.getKey();
+                    Type ruleType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.Rule"));
+                    Method method = Method.getMethod("void execute(String, Object, Object[])");
+                    // we are at the relevant line in the method -- so add a trigger call here
+                    System.out.println("AccessTriggerMethodAdapter.visitFieldInsn : inserting trigger for " + rule.getName());
+                    startLabel = super.newLabel();
+                    endLabel = super.newLabel();
+                    super.visitLabel(startLabel);
+                    super.push(key);
+                    if ((access & Opcodes.ACC_STATIC) == 0) {
+                        super.loadThis();
+                    } else {
+                        super.push((Type)null);
+                    }
+                    super.loadArgArray();
+                    super.invokeStatic(ruleType, method);
+                    super.visitLabel(endLabel);
+                }
+            }
+            if (!whenComplete) {
+                // access the field after generating the trigger call
+                super.visitFieldInsn(opcode, owner, name, desc);
+            }
+        }
+
+        public void visitEnd()
+        {
+            /*
+             * unfortunately, if we generate the handler code here it comes too late for the stack size
+             * computation to take account of it. the handler code uses 4 stack slots so this causes and
+             * error when the method body uses less than 4. we can patch this by generating the handler
+             * code when visitMaxs is called
+            Type exceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ExecuteException"));
+            Type earlyReturnExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException"));
+            Type returnType =  Type.getReturnType(descriptor);
+            // add exception handling code subclass first
+            super.catchException(startLabel, endLabel, earlyReturnExceptionType);
+            if (returnType == Type.VOID_TYPE) {
+                // drop exception and just return
+                super.pop();
+                super.visitInsn(Opcodes.RETURN);
+            } else {
+                // fetch value from exception, unbox if needed and return value
+                Method getReturnValueMethod = Method.getMethod("Object getReturnValue()");
+                super.invokeVirtual(earlyReturnExceptionType, getReturnValueMethod);
+                super.unbox(returnType);
+                super.returnValue();
+            }
+            super.catchException(startLabel, endLabel, exceptionType);
+            super.throwException(exceptionType, rule.getName() + " execution exception ");
+            */
+            super.visitEnd();
+        }
+
+        public void visitMaxs(int maxStack, int maxLocals) {
+            /*
+             * this really ought to be in visitEnd but see above for why we do it here
+             */
+            Type exceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ExecuteException"));
+            Type earlyReturnExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException"));
+            Type throwExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ThrowException"));
+            Type throwableType = Type.getType(TypeHelper.externalizeType("java.lang.Throwable"));
+            Type returnType =  Type.getReturnType(descriptor);
+            // add exception handling code subclass first
+            super.catchException(startLabel, endLabel, earlyReturnExceptionType);
+            if (returnType == Type.VOID_TYPE) {
+                // drop exception and just return
+                super.pop();
+                super.visitInsn(Opcodes.RETURN);
+            } else {
+                // fetch value from exception, unbox if needed and return value
+                Method getReturnValueMethod = Method.getMethod("Object getReturnValue()");
+                super.invokeVirtual(earlyReturnExceptionType, getReturnValueMethod);
+                super.unbox(returnType);
+                super.returnValue();
+            }
+            super.catchException(startLabel, endLabel, throwExceptionType);
+            // fetch value from exception, unbox if needed and return value
+            Method getThrowableMethod = Method.getMethod("Throwable getThrowable()");
+            super.invokeVirtual(throwExceptionType, getThrowableMethod);
+            super.throwException();
+
+            super.catchException(startLabel, endLabel, exceptionType);
+            super.throwException(exceptionType, rule.getName() + " execution exception ");
+            // ok now recompute the stack size
+            super.visitMaxs(maxStack, maxLocals);
+        }
+
+        private boolean matchCall(int opcode, String owner, String name, String desc)
+        {
+            if (!fieldName.equals(name)) {
+                return false;
+            }
+
+            switch (opcode) {
+                case Opcodes.GETSTATIC:
+                case Opcodes.GETFIELD:
+                {
+                    if ((flags & Location.ACCESS_READ) == 0) {
+                        return false;
+                    }
+                }
+                break;
+                case Opcodes.PUTSTATIC:
+                case Opcodes.PUTFIELD:
+                {
+                    if ((flags & Location.ACCESS_WRITE) == 0) {
+                        return false;
+                    }
+                }
+                break;
+            }
+            if (ownerClass != null) {
+                if (!ownerClass.equals(owner)) {
+                    // TODO check for unqualified names
+                    return false;
+                }
+            }
+            // TODO work out how to use desc???
+            return true;
+        }
+    }
+
+    /**
+     * a method visitor used to add a rule event trigger call to a constructor -- this has to make sure
+     * the super constructor has been called before allowing a trigger call to be compiled
+     */
+
+    private class AccessTriggerConstructorAdapter extends AccessTriggerMethodAdapter
+    {
+        AccessTriggerConstructorAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
+        {
+            super(mv, access, name, descriptor, signature, exceptions);
+            // ensure we don't transform calls before the super constructor is called
+            latched = true;
+        }
+
+        public void visitMethodInsn(
+            final int opcode,
+            final String owner,
+            final String name,
+            final String desc)
+        {
+            super.visitMethodInsn(opcode, owner, name, desc);
+            // hmm, this probably means the super constructor has been invoked :-)
+            if (latched && opcode == Opcodes.INVOKESPECIAL) {
+                latched = false;
+            }
+
+        }
+    }
+
+    private String ownerClass;
+    private String fieldName;
+    private int flags;
+    private int count;
+    private boolean whenComplete;
+    private int visitedCount;
+}
\ No newline at end of file

Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/InvokeCheckAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/InvokeCheckAdapter.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/InvokeCheckAdapter.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,127 @@
+/*
+* 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.jbossts.orchestration.agent.adapter;
+
+import org.objectweb.asm.*;
+import org.jboss.jbossts.orchestration.rule.type.TypeHelper;
+
+/**
+ * asm Adapter class used to check that the target method for a rule exists in a class
+ */
+public class InvokeCheckAdapter extends RuleCheckAdapter
+{
+     public InvokeCheckAdapter(ClassVisitor cv, String targetClass, String targetMethod, String calledClass,
+                       String calledMethodName, String calledMethodDescriptor, int count)
+    {
+        super(cv, targetClass, targetMethod);
+        this.calledClass = calledClass;
+        this.calledMethodName = calledMethodName;
+        this.calledMethodDescriptor = calledMethodDescriptor;
+        this.count = count;
+        this.visitedCount = 0;
+    }
+
+    public MethodVisitor visitMethod(
+        final int access,
+        final String name,
+        final String desc,
+        final String signature,
+        final String[] exceptions)
+    {
+        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+        if (matchTargetMethod(name, desc)) {
+            return new InvokeCheckMethodAdapter(mv, access, name, desc, signature, exceptions);
+        }
+
+        return mv;
+    }
+
+    /**
+     * a method visitor used to add a rule event trigger call to a method
+     */
+
+    private class InvokeCheckMethodAdapter extends MethodAdapter
+    {
+        private int access;
+        private String name;
+        private String descriptor;
+        private String signature;
+        private String[] exceptions;
+        private boolean visited;
+
+        InvokeCheckMethodAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
+        {
+            super(mv);
+            this.access = access;
+            this.name = name;
+            this.descriptor = descriptor;
+            this.signature = signature;
+            this.exceptions = exceptions;
+            visitedCount = 0;
+        }
+
+        public void visitMethodInsn(
+            final int opcode,
+            final String owner,
+            final String name,
+            final String desc)
+        {
+            if (visitedCount < count && matchCall(owner, name, desc)) {
+                // a relevant invocation occurs in the called method
+                visitedCount++;
+                if (visitedCount == count) {
+                    // and we have enough occurences to match the count
+                    setVisitOk();
+                }
+            }
+            super.visitMethodInsn(opcode, owner, name, desc);
+        }
+
+        private boolean matchCall(String owner, String name, String desc)
+        {
+            if (!calledMethodName.equals(name)) {
+                return false;
+            }
+            if (calledClass != null) {
+                if (!calledClass.equals(owner)) {
+                    // TODO check for unqualified names
+                    return false;
+                }
+            }
+            if (calledMethodDescriptor.length() > 0) {
+                if (!TypeHelper.equalDescriptors(calledMethodDescriptor, desc)) {
+                    return false;
+                }
+            }
+            
+            return true;
+        }
+    }
+
+    private String calledClass;
+    private String calledMethodName;
+    private String calledMethodDescriptor;
+    private int count;
+    private int visitedCount;
+}
\ No newline at end of file

Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/InvokeTriggerAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/InvokeTriggerAdapter.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/InvokeTriggerAdapter.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,262 @@
+/*
+* 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.jbossts.orchestration.agent.adapter;
+
+import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.type.TypeHelper;
+import org.objectweb.asm.*;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.Method;
+
+/**
+ * asm Adapter class used to add a rule event trigger call to a method of som egiven class
+ */
+public class InvokeTriggerAdapter extends RuleTriggerAdapter
+{
+    public InvokeTriggerAdapter(ClassVisitor cv, Rule rule, String targetClass, String targetMethod, String calledClass,
+                       String calledMethodName, String calledMethodDescriptor, int count, boolean whenComplete)
+    {
+        super(cv, rule, targetClass, targetMethod);
+        this.calledClass = calledClass;
+        this.calledMethodName = calledMethodName;
+        this.calledMethodDescriptor = calledMethodDescriptor;
+        this.count = count;
+        this.whenComplete = whenComplete;
+        this.visitedCount = 0;
+    }
+
+    public MethodVisitor visitMethod(
+        final int access,
+        final String name,
+        final String desc,
+        final String signature,
+        final String[] exceptions)
+    {
+        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+        if (matchTargetMethod(name, desc)) {
+            if (name == "<init>") {
+                return new InvokeTriggerConstructorAdapter(mv, access, name, desc, signature, exceptions);
+            } else {
+                return new InvokeTriggerMethodAdapter(mv, access, name, desc, signature, exceptions);
+            }
+        }
+        return mv;
+    }
+
+    /**
+     * a method visitor used to add a rule event trigger call to a method
+     */
+
+    private class InvokeTriggerMethodAdapter extends GeneratorAdapter
+    {
+        /**
+         * flag used by subclass to avoid inserting trigger until after super constructor has been called
+         */
+        protected boolean latched;
+        private int access;
+        private String name;
+        private String descriptor;
+        private String signature;
+        private String[] exceptions;
+        private Label startLabel;
+        private Label endLabel;
+
+        InvokeTriggerMethodAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
+        {
+            super(mv, access, name, descriptor);
+            this.access = access;
+            this.name = name;
+            this.descriptor = descriptor;
+            this.signature = signature;
+            this.exceptions = exceptions;
+            startLabel = null;
+            endLabel = null;
+            visitedCount = 0;
+            latched = false;
+        }
+
+        // somewhere we need to add a catch exception block
+        // super.catchException(startLabel, endLabel, new Type("org.jboss.jbossts.orchestration.rule.exception.ExecuteException")));
+
+        public void visitMethodInsn(
+            final int opcode,
+            final String owner,
+            final String name,
+            final String desc)
+        {
+            if (whenComplete) {
+                // invoke the method before generating the trigger call
+                super.visitMethodInsn(opcode, owner, name, desc);
+            }
+            if (visitedCount < count && matchCall(owner, name, desc)) {
+                // a relevant invocation occurs in the called method
+                visitedCount++;
+                if (!latched && visitedCount == count) {
+                    rule.setTypeInfo(targetClass, access, name, descriptor, exceptions);
+                    String key = rule.getKey();
+                    Type ruleType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.Rule"));
+                    Method method = Method.getMethod("void execute(String, Object, Object[])");
+                    // we are at the relevant line in the method -- so add a trigger call here
+                    System.out.println("AccessTriggerMethodAdapter.visitMethodInsn : inserting trigger for " + rule.getName());
+                    startLabel = super.newLabel();
+                    endLabel = super.newLabel();
+                    super.visitLabel(startLabel);
+                    super.push(key);
+                    if ((access & Opcodes.ACC_STATIC) == 0) {
+                        super.loadThis();
+                    } else {
+                        super.push((Type)null);
+                    }
+                    super.loadArgArray();
+                    super.invokeStatic(ruleType, method);
+                    super.visitLabel(endLabel);
+                }
+            }
+            if (!whenComplete) {
+                // invoke the method before generating the trigger call
+                super.visitMethodInsn(opcode, owner, name, desc);
+            }
+        }
+
+        public void visitEnd()
+        {
+            /*
+             * unfortunately, if we generate the handler code here it comes too late for the stack size
+             * computation to take account of it. the handler code uses 4 stack slots so this causes and
+             * error when the method body uses less than 4. we can patch this by generating the handler
+             * code when visitMaxs is called
+            Type exceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ExecuteException"));
+            Type earlyReturnExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException"));
+            Type returnType =  Type.getReturnType(descriptor);
+            // add exception handling code subclass first
+            super.catchException(startLabel, endLabel, earlyReturnExceptionType);
+            if (returnType == Type.VOID_TYPE) {
+                // drop exception and just return
+                super.pop();
+                super.visitInsn(Opcodes.RETURN);
+            } else {
+                // fetch value from exception, unbox if needed and return value
+                Method getReturnValueMethod = Method.getMethod("Object getReturnValue()");
+                super.invokeVirtual(earlyReturnExceptionType, getReturnValueMethod);
+                super.unbox(returnType);
+                super.returnValue();
+            }
+            super.catchException(startLabel, endLabel, exceptionType);
+            super.throwException(exceptionType, rule.getName() + " execution exception ");
+            */
+            super.visitEnd();
+        }
+
+        public void visitMaxs(int maxStack, int maxLocals) {
+            /*
+             * this really ought to be in visitEnd but see above for why we do it here
+             */
+            Type exceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ExecuteException"));
+            Type earlyReturnExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException"));
+            Type throwExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ThrowException"));
+            Type throwableType = Type.getType(TypeHelper.externalizeType("java.lang.Throwable"));
+            Type returnType =  Type.getReturnType(descriptor);
+            // add exception handling code subclass first
+            super.catchException(startLabel, endLabel, earlyReturnExceptionType);
+            if (returnType == Type.VOID_TYPE) {
+                // drop exception and just return
+                super.pop();
+                super.visitInsn(Opcodes.RETURN);
+            } else {
+                // fetch value from exception, unbox if needed and return value
+                Method getReturnValueMethod = Method.getMethod("Object getReturnValue()");
+                super.invokeVirtual(earlyReturnExceptionType, getReturnValueMethod);
+                super.unbox(returnType);
+                super.returnValue();
+            }
+            super.catchException(startLabel, endLabel, throwExceptionType);
+            // fetch value from exception, unbox if needed and return value
+            Method getThrowableMethod = Method.getMethod("Throwable getThrowable()");
+            super.invokeVirtual(throwExceptionType, getThrowableMethod);
+            super.throwException();
+
+            super.catchException(startLabel, endLabel, exceptionType);
+            super.throwException(exceptionType, rule.getName() + " execution exception ");
+            // ok now recompute the stack size
+            super.visitMaxs(maxStack, maxLocals);
+        }
+
+        private boolean matchCall(String owner, String name, String desc)
+        {
+            if (!calledMethodName.equals(name)) {
+                return false;
+            }
+            if (calledClass != null) {
+                if (!calledClass.equals(owner)) {
+                    // TODO check for unqualified names
+                    return false;
+                }
+            }
+            if (calledMethodDescriptor.length() > 0) {
+                if (!TypeHelper.equalDescriptors(calledMethodDescriptor, desc)) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    }
+
+    /**
+     * a method visitor used to add a rule event trigger call to a constructor -- this has to make sure
+     * the super constructor has been called before allowing a trigger call to be compiled
+     */
+
+    private class InvokeTriggerConstructorAdapter extends InvokeTriggerMethodAdapter
+    {
+        InvokeTriggerConstructorAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
+        {
+            super(mv, access, name, descriptor, signature, exceptions);
+            // ensure we don't transform calls before the super constructor is called
+            latched = true;
+        }
+
+        public void visitMethodInsn(
+            final int opcode,
+            final String owner,
+            final String name,
+            final String desc)
+        {
+            super.visitMethodInsn(opcode, owner, name, desc);
+            // hmm, this probably means the super constructor has been invoked :-)
+            if (latched && opcode == Opcodes.INVOKESPECIAL) {
+                latched = false;
+            }
+
+        }
+    }
+
+    private String calledClass;
+    private String calledMethodName;
+    private String calledMethodDescriptor;
+    private int count;
+    private boolean whenComplete;
+
+    private int visitedCount;
+}
\ No newline at end of file

Copied: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineCheckAdapter.java (from rev 23806, labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/RuleCheckAdapter.java)
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineCheckAdapter.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineCheckAdapter.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,94 @@
+/*
+* 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.jbossts.orchestration.agent.adapter;
+
+import org.objectweb.asm.*;
+
+/**
+ * asm Adapter class used to check that the target method for a rule exists in a class
+ */
+public class LineCheckAdapter extends RuleCheckAdapter
+{
+    public LineCheckAdapter(ClassVisitor cv, String targetClass, String targetMethod, int targetLine)
+    {
+        super(cv, targetClass, targetMethod);
+        this.targetLine = targetLine;
+    }
+
+    public MethodVisitor visitMethod(
+        final int access,
+        final String name,
+        final String desc,
+        final String signature,
+        final String[] exceptions)
+    {
+        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+        if (matchTargetMethod(name, desc)) {
+            return new LineCheckMethodAdapter(mv, access, name, desc, signature, exceptions);
+        }
+
+        return mv;
+    }
+
+    /**
+     * a method visitor used to add a rule event trigger call to a method
+     */
+
+    private class LineCheckMethodAdapter extends MethodAdapter
+    {
+        private int access;
+        private String name;
+        private String descriptor;
+        private String signature;
+        private String[] exceptions;
+        private boolean visited;
+
+        LineCheckMethodAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
+        {
+            super(mv);
+            this.access = access;
+            this.name = name;
+            this.descriptor = descriptor;
+            this.signature = signature;
+            this.exceptions = exceptions;
+            this.visited = false;
+        }
+
+        public void visitLineNumber(final int line, final Label start) {
+            if (!visited && (targetLine <= line)) {
+                // the relevant line occurs in the called method
+                visited = true;
+                setVisitOk();
+                String name = targetClass + "." + targetMethodName + targetDescriptor;
+                if (targetLine >= 0) {
+                    name += targetLine;
+                }
+            }
+            mv.visitLineNumber(line, start);
+        }
+
+    }
+
+    private int targetLine;
+}
\ No newline at end of file


Property changes on: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineCheckAdapter.java
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineTriggerAdapter.java (from rev 23806, labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/RuleAdapter.java)
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineTriggerAdapter.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineTriggerAdapter.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,217 @@
+/*
+* 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.jbossts.orchestration.agent.adapter;
+
+import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.type.TypeHelper;
+import org.objectweb.asm.*;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.Method;
+
+/**
+ * asm Adapter class used to add a rule event trigger call to a method of som egiven class
+ */
+public class LineTriggerAdapter extends RuleTriggerAdapter
+{
+    public LineTriggerAdapter(ClassVisitor cv, Rule rule, String targetClass, String targetMethod, int targetLine)
+    {
+        super(cv, rule, targetClass, targetMethod);
+        this.targetLine = targetLine;
+        this.visitedLine = false;
+    }
+
+    public MethodVisitor visitMethod(
+        final int access,
+        final String name,
+        final String desc,
+        final String signature,
+        final String[] exceptions)
+    {
+        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+        if (matchTargetMethod(name, desc)) {
+            if (name == "<init>") {
+                return new LineTriggerConstructorAdapter(mv, access, name, desc, signature, exceptions);
+            } else {
+                return new LineTriggerMethodAdapter(mv, access, name, desc, signature, exceptions);
+            }
+        }
+        return mv;
+    }
+
+    /**
+     * a method visitor used to add a rule event trigger call to a method
+     */
+
+    private class LineTriggerMethodAdapter extends GeneratorAdapter
+    {
+        private int access;
+        private String name;
+        private String descriptor;
+        private String signature;
+        private String[] exceptions;
+        private Label startLabel;
+        private Label endLabel;
+
+        LineTriggerMethodAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
+        {
+            super(mv, access, name, descriptor);
+            this.access = access;
+            this.name = name;
+            this.descriptor = descriptor;
+            this.signature = signature;
+            this.exceptions = exceptions;
+            startLabel = null;
+            endLabel = null;
+        }
+
+        // somewhere we need to add a catch exception block
+        // super.catchException(startLabel, endLabel, new Type("org.jboss.jbossts.orchestration.rule.exception.ExecuteException")));
+
+        public void visitLineNumber(final int line, final Label start) {
+            if (!visitedLine && (targetLine <= line)) {
+                rule.setTypeInfo(targetClass, access, name, descriptor, exceptions);
+                String key = rule.getKey();
+                Type ruleType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.Rule"));
+                Method method = Method.getMethod("void execute(String, Object, Object[])");
+                // we are at the relevant line in the method -- so add a trigger call here
+                System.out.println("AccessTriggerMethodAdapter.visitLineNumber : inserting trigger for " + rule.getName());
+                startLabel = super.newLabel();
+                endLabel = super.newLabel();
+                super.visitLabel(startLabel);
+                super.push(key);
+                if ((access & Opcodes.ACC_STATIC) == 0) {
+                    super.loadThis();
+                } else {
+                    super.push((Type)null);
+                }
+                super.loadArgArray();
+                super.invokeStatic(ruleType, method);
+                super.visitLabel(endLabel);
+                visitedLine = true;
+            }
+            super.visitLineNumber(line, start);
+        }
+
+        public void visitEnd()
+        {
+            /*
+             * unfortunately, if we generate the handler code here it comes too late for the stack size
+             * computation to take account of it. the handler code uses 4 stack slots so this causes and
+             * error when the method body uses less than 4. we can patch this by generating the handler
+             * code when visitMaxs is called
+            Type exceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ExecuteException"));
+            Type earlyReturnExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException"));
+            Type returnType =  Type.getReturnType(descriptor);
+            // add exception handling code subclass first
+            super.catchException(startLabel, endLabel, earlyReturnExceptionType);
+            if (returnType == Type.VOID_TYPE) {
+                // drop exception and just return
+                super.pop();
+                super.visitInsn(Opcodes.RETURN);
+            } else {
+                // fetch value from exception, unbox if needed and return value
+                Method getReturnValueMethod = Method.getMethod("Object getReturnValue()");
+                super.invokeVirtual(earlyReturnExceptionType, getReturnValueMethod);
+                super.unbox(returnType);
+                super.returnValue();
+            }
+            super.catchException(startLabel, endLabel, exceptionType);
+            super.throwException(exceptionType, rule.getName() + " execution exception ");
+            */
+            super.visitEnd();
+        }
+
+        public void visitMaxs(int maxStack, int maxLocals) {
+            /*
+             * this really ought to be in visitEnd but see above for why we do it here
+             */
+            Type exceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ExecuteException"));
+            Type earlyReturnExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException"));
+            Type throwExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ThrowException"));
+            Type throwableType = Type.getType(TypeHelper.externalizeType("java.lang.Throwable"));
+            Type returnType =  Type.getReturnType(descriptor);
+            // add exception handling code subclass first
+            super.catchException(startLabel, endLabel, earlyReturnExceptionType);
+            if (returnType == Type.VOID_TYPE) {
+                // drop exception and just return
+                super.pop();
+                super.visitInsn(Opcodes.RETURN);
+            } else {
+                // fetch value from exception, unbox if needed and return value
+                Method getReturnValueMethod = Method.getMethod("Object getReturnValue()");
+                super.invokeVirtual(earlyReturnExceptionType, getReturnValueMethod);
+                super.unbox(returnType);
+                super.returnValue();
+            }
+            super.catchException(startLabel, endLabel, throwExceptionType);
+            // fetch value from exception, unbox if needed and return value
+            Method getThrowableMethod = Method.getMethod("Throwable getThrowable()");
+            super.invokeVirtual(throwExceptionType, getThrowableMethod);
+            super.throwException();
+
+            super.catchException(startLabel, endLabel, exceptionType);
+            super.throwException(exceptionType, rule.getName() + " execution exception ");
+            // ok now recompute the stack size
+            super.visitMaxs(maxStack, maxLocals);
+        }
+
+    }
+
+    /**
+     * a method visitor used to add a rule event trigger call to a constructor -- this has to make sure
+     * the super constructor has been called before allowing a trigger call to be compiled
+     */
+
+    private class LineTriggerConstructorAdapter extends LineTriggerMethodAdapter
+    {
+        private boolean superCalled;
+
+        LineTriggerConstructorAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
+        {
+            super(mv, access, name, descriptor, signature, exceptions);
+            this.superCalled = false;
+        }
+
+        // don't pass on line visits until we have seen an INVOKESPECIAL
+        public void visitLineNumber(final int line, final Label start) {
+            if (superCalled) {
+                super.visitLineNumber(line, start);
+            }
+        }
+
+        public void visitMethodInsn(
+            final int opcode,
+            final String owner,
+            final String name,
+            final String desc)
+        {
+            super.visitMethodInsn(opcode, owner, name, desc);
+            // hmm, this probably means the super constructor has been invoked :-)
+            superCalled &= (opcode == Opcodes.INVOKESPECIAL);
+        }
+    }
+
+    private int targetLine;
+    private boolean visitedLine;
+}
\ No newline at end of file


Property changes on: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineTriggerAdapter.java
___________________________________________________________________
Name: svn:mergeinfo
   + 

Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleAdapter.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleAdapter.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,52 @@
+/*
+* 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.jbossts.orchestration.agent.adapter;
+
+import org.jboss.jbossts.orchestration.rule.type.TypeHelper;
+import org.objectweb.asm.*;
+
+/**
+ * generic asm Adapter class specialised by both check adapters (RuleCheckAdapter) and trigger
+ * adapters (RuleTriggerAdapter)
+ */
+public class RuleAdapter extends ClassAdapter
+{
+    protected RuleAdapter(ClassVisitor cv, String targetClass, String targetMethod)
+    {
+        super(cv);
+        this.targetClass = targetClass;
+        this.targetMethodName = TypeHelper.parseMethodName(targetMethod);
+        this.targetDescriptor = TypeHelper.parseMethodDescriptor(targetMethod);
+    }
+
+    protected String targetClass;
+    protected String targetMethodName;
+    protected String targetDescriptor;
+
+    protected boolean matchTargetMethod(String name, String desc)
+    {
+        return (targetMethodName.equals(name) &&
+                (targetDescriptor.equals("") || TypeHelper.equalDescriptors(targetDescriptor, desc)));
+    }
+}
\ No newline at end of file


Property changes on: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleAdapter.java
___________________________________________________________________
Name: svn:mergeinfo
   + 

Copied: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleCheckAdapter.java (from rev 23806, labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/RuleCheckAdapter.java)
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleCheckAdapter.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleCheckAdapter.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,50 @@
+/*
+* 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.jbossts.orchestration.agent.adapter;
+
+import org.objectweb.asm.*;
+
+/**
+ * asm Adapter class used to check that the target method for a rule exists in a class
+ */
+public class RuleCheckAdapter extends RuleAdapter
+{
+    protected RuleCheckAdapter(ClassVisitor cv, String targetClass, String targetMethod)
+    {
+        super(cv, targetClass, targetMethod);
+        this.visitOk = false;
+    }
+
+    public boolean isVisitOk()
+    {
+        return visitOk;
+    }
+
+    protected void setVisitOk()
+    {
+        visitOk = true;
+    }
+
+    private boolean visitOk;
+}
\ No newline at end of file

Copied: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleTriggerAdapter.java (from rev 23806, labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/RuleAdapter.java)
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleTriggerAdapter.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleTriggerAdapter.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,41 @@
+/*
+* 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.jbossts.orchestration.agent.adapter;
+
+import org.jboss.jbossts.orchestration.rule.Rule;
+import org.objectweb.asm.*;
+
+/**
+ * asm Adapter class used to add a rule event trigger call to a method of some given class
+ */
+public class RuleTriggerAdapter extends RuleAdapter
+{
+    protected RuleTriggerAdapter(ClassVisitor cv, Rule rule, String targetClass, String targetMethod)
+    {
+        super(cv, targetClass, targetMethod);
+        this.rule = rule;
+    }
+
+    protected Rule rule;
+}

Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/SynchronizeCheckAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/SynchronizeCheckAdapter.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/SynchronizeCheckAdapter.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,96 @@
+/*
+* 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.jbossts.orchestration.agent.adapter;
+
+import org.objectweb.asm.*;
+import org.jboss.jbossts.orchestration.rule.type.TypeHelper;
+
+/**
+ * asm Adapter class used to check that the target method for a rule exists in a class
+ */
+public class SynchronizeCheckAdapter extends RuleCheckAdapter
+{
+     public SynchronizeCheckAdapter(ClassVisitor cv, String targetClass, String targetMethod, int count)
+    {
+        super(cv, targetClass, targetMethod);
+        this.count = count;
+        this.visitedCount = 0;
+    }
+
+    public MethodVisitor visitMethod(
+        final int access,
+        final String name,
+        final String desc,
+        final String signature,
+        final String[] exceptions)
+    {
+        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+        if (matchTargetMethod(name, desc)) {
+            return new SynchronizeCheckMethodAdapter(mv, access, name, desc, signature, exceptions);
+        }
+
+        return mv;
+    }
+
+    /**
+     * a method visitor used to add a rule event trigger call to a method
+     */
+
+    private class SynchronizeCheckMethodAdapter extends MethodAdapter
+    {
+        private int access;
+        private String name;
+        private String descriptor;
+        private String signature;
+        private String[] exceptions;
+        private boolean visited;
+
+        SynchronizeCheckMethodAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
+        {
+            super(mv);
+            this.access = access;
+            this.name = name;
+            this.descriptor = descriptor;
+            this.signature = signature;
+            this.exceptions = exceptions;
+            visitedCount = 0;
+        }
+
+        @Override
+        public void visitInsn(int opcode) {
+            if (opcode == Opcodes.MONITORENTER && visitedCount < count) {
+                // a synchronized block occurs in the called method
+                visitedCount++;
+                if (visitedCount == count) {
+                    // and we have enough occurences to match the count
+                    setVisitOk();
+                }
+            }
+            super.visitInsn(opcode);
+        }
+   }
+
+    private int count;
+    private int visitedCount;
+}
\ No newline at end of file

Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/SynchronizeTriggerAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/SynchronizeTriggerAdapter.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/SynchronizeTriggerAdapter.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -0,0 +1,198 @@
+/*
+* 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.jbossts.orchestration.agent.adapter;
+
+import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.type.TypeHelper;
+import org.objectweb.asm.*;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.Method;
+
+/**
+ * asm Adapter class used to add a rule event trigger call to a method of som egiven class
+ */
+public class SynchronizeTriggerAdapter extends RuleTriggerAdapter
+{
+    public SynchronizeTriggerAdapter(ClassVisitor cv, Rule rule, String targetClass, String targetMethod, int count, boolean whenComplete)
+    {
+        super(cv, rule, targetClass, targetMethod);
+        this.calledClass = calledClass;
+        this.calledMethodName = calledMethodName;
+        this.calledMethodDescriptor = calledMethodDescriptor;
+        this.count = count;
+        this.whenComplete = whenComplete;
+        this.visitedCount = 0;
+    }
+
+    public MethodVisitor visitMethod(
+        final int access,
+        final String name,
+        final String desc,
+        final String signature,
+        final String[] exceptions)
+    {
+        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+        // we can use the same adapter for methods and constructors
+        if (matchTargetMethod(name, desc)) {
+            return new SynchronizeTriggerMethodAdapter(mv, access, name, desc, signature, exceptions);
+        }
+        return mv;
+    }
+
+    /**
+     * a method visitor used to add a rule event trigger call to a method
+     */
+
+    private class SynchronizeTriggerMethodAdapter extends GeneratorAdapter
+    {
+        private int access;
+        private String name;
+        private String descriptor;
+        private String signature;
+        private String[] exceptions;
+        private Label startLabel;
+        private Label endLabel;
+
+        SynchronizeTriggerMethodAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
+        {
+            super(mv, access, name, descriptor);
+            this.access = access;
+            this.name = name;
+            this.descriptor = descriptor;
+            this.signature = signature;
+            this.exceptions = exceptions;
+            startLabel = null;
+            endLabel = null;
+            visitedCount = 0;
+        }
+
+        // somewhere we need to add a catch exception block
+        // super.catchException(startLabel, endLabel, new Type("org.jboss.jbossts.orchestration.rule.exception.ExecuteException")));
+
+        @Override
+        public void visitInsn(int opcode) {
+            if (whenComplete) {
+                super.visitInsn(opcode);
+            }
+            if (opcode == Opcodes.MONITORENTER && visitedCount < count) {
+                // a relevant invocation occurs in the called method
+                visitedCount++;
+                if (visitedCount == count) {
+                    rule.setTypeInfo(targetClass, access, name, descriptor, exceptions);
+                    String key = rule.getKey();
+                    Type ruleType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.Rule"));
+                    Method method = Method.getMethod("void execute(String, Object, Object[])");
+                    // we are at the relevant line in the method -- so add a trigger call here
+                    System.out.println("SynchronizeTriggerMethodAdapter.visitMethodInsn : inserting trigger for " + rule.getName());
+                    startLabel = super.newLabel();
+                    endLabel = super.newLabel();
+                    super.visitLabel(startLabel);
+                    super.push(key);
+                    if ((access & Opcodes.ACC_STATIC) == 0) {
+                        super.loadThis();
+                    } else {
+                        super.push((Type)null);
+                    }
+                    super.loadArgArray();
+                    super.invokeStatic(ruleType, method);
+                    super.visitLabel(endLabel);
+                }
+            }
+            if (!whenComplete) {
+                super.visitInsn(opcode);
+            }
+        }
+        
+        public void visitEnd()
+        {
+            /*
+             * unfortunately, if we generate the handler code here it comes too late for the stack size
+             * computation to take account of it. the handler code uses 4 stack slots so this causes and
+             * error when the method body uses less than 4. we can patch this by generating the handler
+             * code when visitMaxs is called
+            Type exceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ExecuteException"));
+            Type earlyReturnExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException"));
+            Type returnType =  Type.getReturnType(descriptor);
+            // add exception handling code subclass first
+            super.catchException(startLabel, endLabel, earlyReturnExceptionType);
+            if (returnType == Type.VOID_TYPE) {
+                // drop exception and just return
+                super.pop();
+                super.visitInsn(Opcodes.RETURN);
+            } else {
+                // fetch value from exception, unbox if needed and return value
+                Method getReturnValueMethod = Method.getMethod("Object getReturnValue()");
+                super.invokeVirtual(earlyReturnExceptionType, getReturnValueMethod);
+                super.unbox(returnType);
+                super.returnValue();
+            }
+            super.catchException(startLabel, endLabel, exceptionType);
+            super.throwException(exceptionType, rule.getName() + " execution exception ");
+            */
+            super.visitEnd();
+        }
+
+        public void visitMaxs(int maxStack, int maxLocals) {
+            /*
+             * this really ought to be in visitEnd but see above for why we do it here
+             */
+            Type exceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ExecuteException"));
+            Type earlyReturnExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException"));
+            Type throwExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ThrowException"));
+            Type throwableType = Type.getType(TypeHelper.externalizeType("java.lang.Throwable"));
+            Type returnType =  Type.getReturnType(descriptor);
+            // add exception handling code subclass first
+            super.catchException(startLabel, endLabel, earlyReturnExceptionType);
+            if (returnType == Type.VOID_TYPE) {
+                // drop exception and just return
+                super.pop();
+                super.visitInsn(Opcodes.RETURN);
+            } else {
+                // fetch value from exception, unbox if needed and return value
+                Method getReturnValueMethod = Method.getMethod("Object getReturnValue()");
+                super.invokeVirtual(earlyReturnExceptionType, getReturnValueMethod);
+                super.unbox(returnType);
+                super.returnValue();
+            }
+            super.catchException(startLabel, endLabel, throwExceptionType);
+            // fetch value from exception, unbox if needed and return value
+            Method getThrowableMethod = Method.getMethod("Throwable getThrowable()");
+            super.invokeVirtual(throwExceptionType, getThrowableMethod);
+            super.throwException();
+
+            super.catchException(startLabel, endLabel, exceptionType);
+            super.throwException(exceptionType, rule.getName() + " execution exception ");
+            // ok now recompute the stack size
+            super.visitMaxs(maxStack, maxLocals);
+        }
+    }
+
+    private String calledClass;
+    private String calledMethodName;
+    private String calledMethodDescriptor;
+    private int count;
+    private boolean whenComplete;
+
+    private int visitedCount;
+}
\ No newline at end of file

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Rule.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Rule.java	2008-11-20 17:20:26 UTC (rev 23999)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/Rule.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -36,6 +36,7 @@
 import org.jboss.jbossts.orchestration.rule.grammar.ParseNode;
 import org.jboss.jbossts.orchestration.synchronization.CountDown;
 import org.jboss.jbossts.orchestration.synchronization.Waiter;
+import org.jboss.jbossts.orchestration.agent.Location;
 import org.objectweb.asm.Opcodes;
 
 import java.io.StringWriter;
@@ -64,10 +65,9 @@
      */
     private String targetMethod;
     /**
-     * the line number at which to insert the trigger call in the target method for this rule
-     * supplied in the rule script
+     * the location at which the rule trigger point is attached
      */
-    private int targetLine;
+    private Location targetLocation;
     /**
      * the parsed event derived from the script for this rule
      */
@@ -134,7 +134,7 @@
      */
     private boolean checkFailed;
 
-    private Rule(String name, String targetClass, String targetMethod, int targetLine, String ruleSpec, ClassLoader loader)
+    private Rule(String name, String targetClass, String targetMethod, Location targetLocation, String ruleSpec, ClassLoader loader)
             throws ParseException, TypeException, CompileException
     {
         ParseNode ruleTree;
@@ -163,7 +163,7 @@
         checked = false;
         this.targetClass = targetClass;
         this.targetMethod = targetMethod;
-        this.targetLine = targetLine;
+        this.targetLocation = targetLocation;
         triggerClass = null;
         triggerMethod = null;
         triggerDescriptor = null;
@@ -192,8 +192,8 @@
         return targetMethod;
     }
 
-    public int getTargetLine() {
-        return targetLine;
+    public Location getTargetLocation() {
+        return targetLocation;
     }
 
     public Event getEvent()
@@ -209,10 +209,10 @@
         return action;
     }
 
-    public static Rule create(String name, String targetClass, String targetMethod, int targetLine, String ruleSpec, ClassLoader loader)
+    public static Rule create(String name, String targetClass, String targetMethod, Location targetLocation, String ruleSpec, ClassLoader loader)
             throws ParseException, TypeException, CompileException
     {
-            return new Rule(name, targetClass, targetMethod,  targetLine, ruleSpec, loader);
+            return new Rule(name, targetClass, targetMethod, targetLocation, ruleSpec, loader);
     }
 
     public void setEvent(String eventSpec) throws ParseException, TypeException
@@ -442,6 +442,14 @@
         stringWriter.write("RULE ");
         stringWriter.write(name);
         stringWriter.write("\n");
+        stringWriter.write("CLASS ");
+        stringWriter.write(targetClass);
+        stringWriter.write('\n');
+        stringWriter.write("METHOD ");
+        stringWriter.write(targetMethod);
+        stringWriter.write('\n');
+        stringWriter.write(targetLocation.toString());
+        stringWriter.write('\n');
         if (event != null) {
             event.writeTo(stringWriter);
         } else {

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/type/TypeHelper.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/type/TypeHelper.java	2008-11-20 17:20:26 UTC (rev 23999)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/type/TypeHelper.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -268,6 +268,95 @@
     }
 
     /**
+     * convert a method descriptor from the form used to represent it externally to canonical form
+     *
+     * @param desc the method descriptor which must be trimmed of any surrounding white space
+     * @return an internalised form for the descriptor
+     */
+    public static String internalizeDescriptor(String desc)
+    {
+        StringBuffer buffer = new StringBuffer();
+        String sepr = "";
+        buffer.append("(");
+        int max = desc.length();
+        int arrayCount = 0;
+
+        for (int idx = 0; idx < max;) {
+            buffer.append(sepr);
+            char next = desc.charAt(idx);
+            switch(next) {
+                case 'B':
+                {
+                    buffer.append("byte");
+                }
+                break;
+                case 'C':
+                {
+                    buffer.append("char");
+                }
+                break;
+                case 'S':
+                {
+                    buffer.append("short");
+                }
+                break;
+                case 'I':
+                {
+                    buffer.append("int");
+                }
+                break;
+                case 'J':
+                {
+                    buffer.append("long");
+                }
+                break;
+                case 'Z':
+                {
+                    buffer.append("boolean");
+                }
+                break;
+                case 'F':
+                {
+                    buffer.append("float");
+                }
+                break;
+                case 'D':
+                {
+                    buffer.append("double");
+                }
+                break;
+                case 'L':
+                {
+                    int tailIdx = idx+1;
+                    while (tailIdx < max && desc.charAt(tailIdx) != ';') {
+                        tailIdx++;
+                    }
+                    if (tailIdx < max) {
+                        buffer.append(desc.substring(idx + 1, tailIdx));
+                    }
+                    idx = tailIdx;
+                }
+                break;
+                case '[':
+                {
+                    arrayCount++;
+                }
+                break;
+            }
+            if (next != '[') {
+                while (arrayCount > 0) {
+                    buffer.append("[]");
+                    arrayCount--;
+                }
+            }
+            idx++;
+            sepr = ",";
+        }
+        
+        return buffer.toString();
+    }
+
+    /**
      * split off the method name preceding the signature and return it
      * @param targetMethod - the unqualified method name, possibly including signature
      * @return

Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/test/TestScript.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/test/TestScript.java	2008-11-20 17:20:26 UTC (rev 23999)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/test/TestScript.java	2008-11-20 17:28:48 UTC (rev 24000)
@@ -28,6 +28,8 @@
 import org.jboss.jbossts.orchestration.rule.exception.ParseException;
 import org.jboss.jbossts.orchestration.rule.exception.TypeException;
 import org.jboss.jbossts.orchestration.rule.exception.CompileException;
+import org.jboss.jbossts.orchestration.agent.LocationType;
+import org.jboss.jbossts.orchestration.agent.Location;
 import org.objectweb.asm.Opcodes;
 
 import java.util.List;
@@ -114,7 +116,8 @@
                 String[] lines = script.split("\n");
                 String targetClassName;
                 String targetMethodName;
-                int targetLine = -1;
+                LocationType locationType = null;
+                Location targetLocation = null;
                 String text = "";
                 String sepr = "";
                 int idx = 0;
@@ -150,9 +153,13 @@
                 while (lines[idx].trim().equals("") || lines[idx].trim().startsWith("#")) {
                     idx++;
                 }
-                if (lines[idx].startsWith("LINE ")) {
-                    String targetLineString = lines[idx].substring(5).trim();
-                    targetLine = Integer.valueOf(targetLineString);
+                locationType = LocationType.type(lines[idx]);
+                if (locationType != null) {
+                    String parameters = LocationType.parameterText(lines[idx]);
+                    targetLocation = Location.create(locationType, parameters);
+                    if (targetLocation == null) {
+                        throw new ParseException("Invalid parameters for location specifier " + locationType.specifierText() + " in rule " + ruleName);
+                    }
                     idx++;
                 }
                 for (;idx < len; idx++) {
@@ -165,10 +172,7 @@
                     text += sepr + lines[idx];
                     sepr = "\n";
                 }
-                if (targetMethodName.startsWith("<init>") && (targetLine < 0)) {
-                    throw new ParseException("constructor method " + targetMethodName + " must specify target line in rule " + ruleName);
-                }
-                Rule rule = Rule.create(ruleName, targetClassName, targetMethodName, targetLine, text, loader);
+                Rule rule = Rule.create(ruleName, targetClassName, targetMethodName, targetLocation, text, loader);
                 System.err.println("TestScript: parsed rule " + rule.getName());
                 System.err.println(rule);
                 




More information about the jboss-svn-commits mailing list