12 Replies Latest reply on Jan 28, 2016 9:14 AM by Andrew Dinn

    problems with org.jboss.as package names in Wildfly

    Richard Achmatowicz Novice

      Hello Byteman support

       

      I'm writing rules which are loaded into a Wildfly 10 server at startup using the following JVM parameters:

       

      "-Dorg.jboss.byteman.verbose -Dorg.jboss.byteman.transform.all -Dorg.jboss.byteman.compile.to.bytecode -javaagent:/home/rachmatowicz/byteman.jar=script:/home/rachmatowicz/script-client.btm,boot:/home/rachmatowicz/byteman.jar"


      I find that rules with org.wildfly.* package names, like this:


      RULE InfinispanBeanManager_start
      CLASS org.wildfly.clustering.ejb.infinispan.InfinispanBeanManager
      METHOD start
      AT ENTRY
      IF TRUE
      DO  <something>
      ENDRULE
      

       

      get installed and work, but rules with the org.jboss.* package names, like this:

       

      RULE ManagedExecutorService_execute
      INTERFACE org.jboss.as.clustering.concurrent.ManagedExecutorService
      METHOD execute
      AT ENTRY
      IF TRUE
      DO   <something>
      ENDRULE
      

      do not. Other package names from supporting libraries, such as org.infinispan.* also seem to work fine.

       

      I expect that this has something to do with classloading. Am I leaving out some special parameters when starting the server, or is this a known problem? (or not a problem and i'm doing something stupid)

       

      Richard

        • 1. Re: problems with org.jboss.as package names in Wildfly
          Andrew Dinn Master

          Hi Richard,

           

          I don't know for sure what is happening here but I suspect that the problem is indeed to do with module loaders. If you could run with verbose output that might help diagnose the problem. You need to add -Dorg.jboss.byteman.verbose to the command line and then look to see if there are any messages in the AS log which refer to rule ManagedExecutorService_execute.

           

          What I suspect to be the root of the problem here is that the jar which defines interface ManagedExecutorService is in a different module to the jar containing the class (or classes) which implements it. That might very well cause a problem trying to resolve a reference to the interface class either at injection time or at rule typecheck time.

           

          If you can provide me with a simple set of instructions for reproducing the failure I will be very happy to investigate this further.

           

          regards,

           

           

          Andrew DInn

          • 2. Re: problems with org.jboss.as package names in Wildfly
            Richard Achmatowicz Novice

            Hi Andrew

             

            In trying to set up a simple example for you, I found that what I was claiming is not true in general.

            Here is the script I used:

            RULE org.jboss.as package example
            CLASS org.jboss.as.clustering.infinispan.subsystem.InfinispanSubsystemServiceHandler
            METHOD installServices
            AT ENTRY
            IF TRUE
            DO  System.out.println("[BYTEMAN] Activating Infinispan subsystem") 
            ENDRULE
            
            RULE org.wildfly package example
            CLASS org.wildfly.extension.undertow.UndertowService
            METHOD start
            AT ENTRY
            IF TRUE
            DO  System.out.println("[BYTEMAN] Undertow starting") 
            ENDRULE
            

            These rules just duplicate some standard startup logging in the server which is going to be seen in any case.

             

            Here are the results of starting Wildfly with the standalone-ha.xml configuration with the script: http://pastebin.com/TZdyatGu

            I see that both the org.jboss.as rule and the org.wildfly rule both were executed as expected.

             

            The earlier examples I mentioned involve instrumenting code in packages org.jboss.as which are started as on-demand services. These on-demand services are started upon deployment of an application. I'll try and concoct a better example. :-(

            • 3. Re: problems with org.jboss.as package names in Wildfly
              Richard Achmatowicz Novice

              I tried a second example, using this script, which has one rule added at the end:

               

              RULE org.jboss.as package example
              CLASS org.jboss.as.clustering.infinispan.subsystem.InfinispanSubsystemServiceHandler
              METHOD installServices
              AT ENTRY
              IF TRUE
              DO  System.out.println("[BYTEMAN] Activating Infinispan subsystem")
              ENDRULE
              
              RULE org.wildfly package example
              CLASS org.wildfly.extension.undertow.UndertowService
              METHOD start
              AT ENTRY
              IF TRUE
              DO  System.out.println("[BYTEMAN] Undertow starting")
              ENDRULE
              
              RULE org.jboss.as on-demand package example
              CLASS org.jboss.as.ejb3.remote.protocol.versionone.VersionOneProtocolChannelReceiver
              METHOD startReceiving
              AT ENTRY
              IF TRUE
              DO  System.out.println("[BYTEMAN] VersionOne receiving")
              ENDRULE
              

               

              and starting the server by hand, we get this console output: http://pastebin.com/SCGHfMXc

               

              We can see at the very end of the console output that the new rule has been activated. Which surprised me, as in all previous testing I was doing, using Arquillian based tests and SmartFrog based tests, those rules were not getting activated.

               

              One more example to come.

              • 4. Re: problems with org.jboss.as package names in Wildfly
                Richard Achmatowicz Novice

                Well, there's good news and there's bad news. The good news is that after further testing, I have been able to show that instrumenting classes with org.jboss.as packages in Wildfly does work as expected, including from jobs controlled by Arquillian. The bad news is that the scripts I used originally, which "didn't work", now "work". Can't explain at the moment, other than I may have been running a test which did no pass through the code path which the rule applies to. But I seem to remember the Transformer statements in verbose mode just not being there for the rules that I thought were not working.

                 

                Anywaty,..., this case is closed. Thanks for your attention, Andrew.

                • 5. Re: problems with org.jboss.as package names in Wildfly
                  Andrew Dinn Master

                  No problem, Richard. If you manage to get this problem to recur enable verbose trace and let me know what it shows.

                   

                  regards,

                   

                   

                  Andrew Dinn

                  • 6. Re: problems with org.jboss.as package names in Wildfly
                    Richard Achmatowicz Novice

                    Hi Andrew, back again :-(

                     

                    I now have most of my rules set up (for instrumenting Wildfly classes) and I am running into another problem: getting access to method invocation parameters.

                    Here is a concrete example:

                    Rule:

                    RULE StatefulSessionComponent_destroyInstance
                    CLASS org.jboss.as.ejb3.component.stateful.StatefulSessionComponent
                    METHOD destroyInstance
                    BIND
                      id:String =  $1.getId();
                    AT ENTRY
                    IF TRUE
                    DO
                    #  System.out.println("[BYTEMAN-StatefulSessionComponent] destroy instance, id: ")
                      System.out.println("[BYTEMAN-StatefulSessionComponent] destroy instance, id: " + id)
                    ENDRULE
                    

                     

                    The actual method code in the class:

                        @Override
                        public void destroyInstance(StatefulSessionComponentInstance instance) {
                            instance.setRemoved(true);
                            if(!instance.isSynchronizationRegistered()) {
                                instance.destroy();
                            }
                        }
                    

                     

                    The error message when verbose is turned on:

                     

                    14:45:42,224 INFO  [stdout] (ServerService Thread Pool -- 17) Rule.execute called for SimpleCache_stop_5

                    14:45:42,224 INFO  [stdout] (ServerService Thread Pool -- 17) SimpleCache_stop execute

                    14:45:42,224 INFO  [stdout] (ServerService Thread Pool -- 17) [BYTEMAN-SimpleCache] stop cache

                    14:45:42,224 INFO  [stdout] (ServerService Thread Pool -- 17) Rule.execute called for StatefulSessionComponent_destroyInstance_1

                    14:45:42,224 INFO  [stdout] (ServerService Thread Pool -- 23) Rule.execute called for DistributableCache_stop_13

                    14:45:42,224 INFO  [stdout] (ServerService Thread Pool -- 23) DistributableCache_stop execute

                    14:45:42,224 INFO  [stdout] (ServerService Thread Pool -- 23) [BYTEMAN-DistributableCache] stop cache

                    14:45:42,225 INFO  [org.jboss.as.clustering.infinispan] (ServerService Thread Pool -- 4) WFLYCLINF0003: Stopped stateful-failover.war cache from web container

                    14:45:42,225 INFO  [stdout] (ServerService Thread Pool -- 17) Rule.ensureTypeCheckedCompiled : error type checking rule StatefulSessionComponent_destroyInstance

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) org.jboss.byteman.rule.exception.TypeException: MethodExpression.typeCheck : ambiguous method signature getId for target class org.jboss.as.ejb3.component.stateful.StatefulSessionComponentInstance file /home/nrla/byteman-scripts/script-server-cache.btm line 140

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.expression.MethodExpression.findMethod(MethodExpression.java:325)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.expression.MethodExpression.typeCheck(MethodExpression.java:188)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.binding.Binding.typeCheck(Binding.java:131)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.Event.typeCheck(Event.java:114)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.Event.typeCheck(Event.java:106)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.Rule.typeCheck(Rule.java:521)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.Rule.ensureTypeCheckedCompiled(Rule.java:449)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.Rule.execute(Rule.java:672)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.Rule.execute(Rule.java:653)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.as.ejb3.component.stateful.StatefulSessionComponent.destroyInstance(StatefulSessionComponent.java)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.as.ejb3.component.stateful.StatefulSessionComponent.destroyInstance(StatefulSessionComponent.java:75)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.as.ejb3.cache.simple.SimpleCache.stop(SimpleCache.java:91)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.as.ejb3.component.stateful.StatefulSessionComponent.done(StatefulSessionComponent.java:369)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.as.ejb3.component.EJBComponent.stop(EJBComponent.java:553)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.as.ee.component.ComponentStartService$2.run(ComponentStartService.java:78)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at java.util.concurrent.FutureTask.run(FutureTask.java:266)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at java.lang.Thread.run(Thread.java:745)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.threads.JBossThread.run(JBossThread.java:320)

                    14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17)

                     

                    The class StatefulSessionComponentInstance is as follows:

                     

                    public class StatefulSessionComponentInstance extends SessionBeanComponentInstance implements Identifiable<SessionID>, Contextual<Object> {
                        private static final long serialVersionUID = 3803978357389448971L;
                        private final SessionID id;
                    
                       [snip]
                    
                    
                        @Override
                        public SessionID getId() {
                            return id;
                        }
                    
                        [snip]
                    
                    }
                    

                     

                    I'm having similar problems with getting access to method parameters in other rules, but this is a typical example.

                     

                    Any ideas on what i'm doing wrong?

                    • 7. Re: problems with org.jboss.as package names in Wildfly
                      James Livingston Apprentice

                      What is going wrong for you is an artifact of generic type erasure.

                       

                      Simplified to the relevant parts, there is:

                      interface StatefulObjectFactory<T> {

                        void destroyInstance(T instance)

                      }

                       

                      class StatefulSessionComponent implements StatefulObjectFactory<StatefulSessionComponentInstance> {

                       

                        void destroyInstance(StatefulSessionComponentInstance instance) {...}

                       

                      }

                       

                      For StatefulObjectFactory, the T is erased to Object since there is no upper bound, so at the JVM class/bytecode method, the method's parameter is Object.

                       

                      StatefulSessionComponent has a concrete type rather than a generic one for the type parameter, so the compiled version of the method written in the source code takes a StatefulSessionComponentInstance as a parameter. If you think about it, that means as-is StatefulSessionComponent does not implement the StatefulObjectFactory interface, because it does not implement the "void destroyInstance(Object)" method.

                       

                      What happens is that the Java compiler inserts a synthetic bridge method, which forwards to the actual implementation after a cast:

                      void destroyInstance(Object o) { destroyInstance((StatefulSessionComponentInstance)o);}

                       

                       

                      So the compiled class actually has two destroyInstance methods, not one. Your rule does not specify any parameter types, so ByteMan intercepts both of them. When it triggers for the Object-parameter method, it fails to check because Object does not have a getId() method. Triggering for the StatefulSessionComponentInstance-parameter method would work.

                       

                       

                      So what you need to do is to change your rule to have "METHOD destroyInstance(StatefulSessionComponentInstance)", so it only triggers for the specialised one with the real implementation. If that ends up being called via the Object-parameter version, that is fine since it will trigger when it forwards to the other one.

                      • 8. Re: problems with org.jboss.as package names in Wildfly
                        Richard Achmatowicz Novice

                        Hi James

                         

                        Thanks very much for the comprehensive answer!


                        I made the changes and unless i'm again messing up, the same problem arises:

                         

                        RULE StatefulSessionComponent_destroyInstance
                        CLASS org.jboss.as.ejb3.component.stateful.StatefulSessionComponent
                        METHOD destroyInstance(StatefulSessionComponentInstance)
                        BIND
                          appName:String = "<" + $this.getApplicationName() + "." + $this.getModuleName() + "." + $this.getDistinctName() + ">";
                        AT ENTRY
                        IF TRUE
                        DO
                          System.out.println("[BYTEMAN-StatefulSessionComponent] destroy instance, id: " + $1.getId())
                        ENDRULE
                        

                         

                        In the logs:

                         

                        18:42:58,789 INFO  [stdout] (ServerService Thread Pool -- 22) Rule.execute called for StatefulSessionComponent_destroyInstance_1

                        18:42:58,789 INFO  [stdout] (ServerService Thread Pool -- 6) [BYTEMAN-DistributableCache] stop cache

                        18:42:58,791 INFO  [org.infinispan.eviction.impl.PassivationManagerImpl] (ServerService Thread Pool -- 71) ISPN000029: Passivating all entries to disk

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) Rule.ensureTypeCheckedCompiled : error type checking rule StatefulSessionComponent_destroyInstance

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) org.jboss.byteman.rule.exception.TypeException: MethodExpression.typeCheck : ambiguous method signature getId for target class org.jboss.as.ejb3.component.stateful.StatefulSessionComponentInstance file /home/nrla/byteman-scripts/script-server-cache.btm line 142

                        18:42:58,791 INFO  [org.infinispan.eviction.impl.PassivationManagerImpl] (ServerService Thread Pool -- 71) ISPN000030: Passivated 0 entries in 0 milliseconds

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.byteman.rule.expression.MethodExpression.findMethod(MethodExpression.java:325)

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.byteman.rule.expression.MethodExpression.typeCheck(MethodExpression.java:188)

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.byteman.rule.expression.StringPlusExpression.typeCheck(StringPlusExpression.java:52)

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.byteman.rule.expression.MethodExpression.findMethod(MethodExpression.java:293)

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.byteman.rule.expression.MethodExpression.typeCheck(MethodExpression.java:188)

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.byteman.rule.Action.typeCheck(Action.java:106)

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.byteman.rule.Rule.typeCheck(Rule.java:523)

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.byteman.rule.Rule.ensureTypeCheckedCompiled(Rule.java:449)

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.byteman.rule.Rule.execute(Rule.java:672)

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.byteman.rule.Rule.execute(Rule.java:653)

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.as.ejb3.component.stateful.StatefulSessionComponent.destroyInstance(StatefulSessionComponent.java)

                        18:42:58,791 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.as.ejb3.component.stateful.StatefulSessionComponent.destroyInstance(StatefulSessionComponent.java:75)

                        18:42:58,792 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.as.ejb3.cache.simple.SimpleCache.stop(SimpleCache.java:91)

                        18:42:58,792 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.as.ejb3.component.stateful.StatefulSessionComponent.done(StatefulSessionComponent.java:369)

                        18:42:58,792 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.as.ejb3.component.EJBComponent.stop(EJBComponent.java:553)

                        18:42:58,792 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.as.ee.component.ComponentStartService$2.run(ComponentStartService.java:78)

                        18:42:58,792 INFO  [stdout] (ServerService Thread Pool -- 22) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)

                        18:42:58,792 INFO  [stdout] (ServerService Thread Pool -- 22) at java.util.concurrent.FutureTask.run(FutureTask.java:266)

                        18:42:58,792 INFO  [stdout] (ServerService Thread Pool -- 22) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

                        18:42:58,792 INFO  [stdout] (ServerService Thread Pool -- 22) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

                        18:42:58,792 INFO  [stdout] (ServerService Thread Pool -- 22) at java.lang.Thread.run(Thread.java:745)

                        18:42:58,792 INFO  [stdout] (ServerService Thread Pool -- 22) at org.jboss.threads.JBossThread.run(JBossThread.java:320)

                        18:42:58,792 INFO  [stdout] (ServerService Thread Pool -- 22)

                        18:42:58,792 INFO  [stdout] (ServerService Thread Pool -- 22) Rule.execute called for StatefulSessionComponentInstance_setRemoved_10

                        18:42:58,794 INFO  [org.jboss.as.clustering.infinispan] (ServerService Thread Pool -- 18) WFLYCLINF0003: Stopped stateful-failover.war cache from web container

                        18:42:58,794 INFO  [stdout] (ServerService Thread Pool -- 22) HelperManager.install for helper class org.jboss.byteman.rule.helper.Helper

                        18:42:58,794 INFO  [stdout] (ServerService Thread Pool -- 22) calling installed(StatefulSessionComponentInstance_setRemoved) for helper classorg.jboss.byteman.rule.helper.Helper

                        18:42:58,794 INFO  [stdout] (ServerService Thread Pool -- 22) Installed rule using default helper : StatefulSessionComponentInstance_setRemoved

                        18:42:58,794 INFO  [stdout] (ServerService Thread Pool -- 22) StatefulSessionComponentInstance_setRemoved execute

                        18:42:58,794 INFO  [stdout] (ServerService Thread Pool -- 22) [BYTEMAN-StatefulSessionComponentInstance] setRemoved, sessionID: UnknownSessionID [7050545754535765525152575252684957525555507054695450535565534953]

                        18:42:58,794 INFO  [stdout] (ServerService Thread Pool -- 22) Rule.execute called for StatefulSessionComponent_destroyInstance_1

                        18:42:58,795 INFO  [stdout] (ServerService Thread Pool -- 22) Rule.execute called for StatefulSessionComponentInstance_setRemoved_10

                        18:42:58,795 INFO  [stdout] (ServerService Thread Pool -- 22) StatefulSessionComponentInstance_setRemoved execute

                         

                        This occurs with or without the package name on the method parameter class.

                        • 9. Re: problems with org.jboss.as package names in Wildfly
                          James Livingston Apprentice

                          That's just the same problem in a different form.

                           

                          StatefulSessionComponentInstance has the method "SessionID getId()", which is the implementation of Identifiable's "K getId()" where K is fixed to SessionID. The Java compiler inserts a synthetic bridge "Object getId() { return getId(); }" calling the one that returns SessionID. Java does not let you directly write methods overloaded purely on the return type, and I believe (but are not sure) that if there is only one non-bridge method it assumes that they all point to it, so it does not warn about the ambiguity.

                           

                          ByteMan's MethodExpression.findMethod() and bestMatchCandidate() have logic for determining which one should be used, and that error is printed when it return multiple candidates. The current code only looks at the argument types, not return types. To handle covariant return types, I think it would need to be changed so that if there are multiple candidates with identical arguments, then it checks whether there is one which is strictly more specific than the others. I don't think there is JIRA issue for  that yet.

                           

                          adinn does that sound right?

                          • 10. Re: problems with org.jboss.as package names in Wildfly
                            Andrew Dinn Master

                            Hi James/Richard,

                             

                            James' first post is correct in what it says about the compiler inserting bridge methods. This occurs when you have a class which implements a specific instantiation of a template class. However, the rest of that first account does not correctly diagnose the problem in the corresponding (first) example.

                             

                            The ambiguity there is not to do with the target method destroyInstance. Byteman does not attempt to inject into synthetic methods (look at TransformContext.matchTargetMethod to see where this check happens). So we can be sure that the type check is indeed being performed for the rule injected into the version of the method with signature destroyInstance(StatefulSessionComponentInstance).

                             

                            So, let's move on to the error itself. If you look at the stack trace and error message in the first example you can see that the ambiguity occurs when type-checking the call to getId() in the BIND clause.

                             

                            . . .
                            14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) org.jboss.byteman.rule.exception.TypeException: MethodExpression.typeCheck : ambiguous method signature getId for target class org.jboss.as.ejb3.component.stateful.StatefulSessionComponentInstance file /home/nrla/byteman-scripts/script-server-cache.btm line 140
                            14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.expression.MethodExpression.findMethod(MethodExpression.java:325)
                            14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.expression.MethodExpression.typeCheck(MethodExpression.java:188)
                            14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.binding.Binding.typeCheck(Binding.java:131)
                            14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.Event.typeCheck(Event.java:114)
                            14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.Event.typeCheck(Event.java:106)
                            14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.Rule.typeCheck(Rule.java:521)
                            14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.Rule.ensureTypeCheckedCompiled(Rule.java:449)
                            14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.Rule.execute(Rule.java:672)
                            14:45:42,226 INFO  [stdout] (ServerService Thread Pool -- 17) at org.jboss.byteman.rule.Rule.execute(Rule.java:653)
                            . . .
                            
                            

                             

                            The type check is looking for a method with no arguments. You might expect it to use the variable type declaration to impose the additional constraint that the return type has to be String.However, since the method expression is being used as a BIND var initializer that is not the full story.

                             

                            Byteman typechecks an initializer expression X:T = M(E,.1..En)  by type checking the expression M(E1,..En) with an unconstrained return type (it passes expected tupe = Unknown to the typeCheck call). If the type checker can derive a unique method from the method name and the types of the input expressions it then goes on to check the return type R to ensure

                             

                              1) R == T  or 2) R < T or 3) T < R where C1 < C2 indicates that C1 extends C2 OR C1 implements C2.

                             

                            It also allows three other cases to support type inference

                             

                              4) R == Numeric/Object AND T is primitive or 5) R is primitive and T is Numeric or 6) R == String

                             

                            in which case(s) Byteman's type inferrer is willing either to box/unbox a number or Stringify an object by inserting a toString call.

                             

                            The surprising case is the 3rd one. It is included because Byteman is willing to downcast expressions in initializer expressions i.e. if a method M(x1,...xn) returns an Object then Byteman is willing to assign it to a BIND variable X of type String. If it returns a Foo then Byteman will assign to a variable of type FooBar extends Foo. Of course Byteman also inserts a checkcast which will generate a runtime exception if the assignment is invalid.

                             

                            Ironically, downcasting was introduced explicitly to allow generic data from template classes to be accessed using the template type rather than as generic objects. e.g. if a template type X<T> has a field f of type <T> which is actually stored as an Object then Byteman will allow you to write BIND s:String = x1.f which is fine (modulo a checkcast) if you know that x1 is an instance of X<String>.

                             

                            What is happening here is that the type check for the getId call is encountering two version of getId(), a synthetic one which returns an Object and a non-synthetic one which returns a String.Two versions exist because the class in question implements an instantiated template; the implementation method which returns a String has to be wrapped with a generic method which returns an Object. Since the check cannot use the downcast type to select the desired implementation the call is ambiguous.

                             

                            I'll need to think about whether this can be fixed. A simple fix is to special case and push the BIND var type as an expected type when the intiializer is a method expression. That would ensure that when a String is required the method returning a String is picked (it would still leave things ambiguous if the bind var type was Object).  Indeed, there is a precedent for special casing. I already special case iniitalizer type checks  when the initializer is an array literal  as in, say o:Object[] = like {1, 2, 3} . This type strictness is needed because although you could legitimately create an int[] and assign it to an Object[] you risk getting a type error if the rule subsequently tries to assign the int[] e.g. DO o[0] = "hello".

                             

                            However, special-casing is really only a sticking-plaster solution. Not only does it  merely deal with one side of initializer problem (only fixing the case where the bind vartype is the subtype) it also fails to deal with manifestations of the same problem in other contexts. Assume that we have an expression like x.m().name anywhere in the rule and that we infer that the field expression has type F and that expression x has type X. Knowing F and X does not help to select the method return type R. Once we identify a method m then we can check whether R has a field name of type F. But if  X  has both a synthetic implementation of m with type T1 and a non-synthetic implementation with type T2 extends T1 we are still left with an ambiguous method type irrespective of the fact that we know both input and return types for the original expression.

                             

                            Another tack which looks like an option is to ignore the synthetic method. However, I am not sure that is actually the correct move either. Since application code can legitimately access at the object level who is ot say that the rule is not intended to access at the same level. I'll need to think further before making a decision on this point.

                            • 11. Re: problems with org.jboss.as package names in Wildfly
                              Richard Achmatowicz Novice

                              Hi James/Andrew

                               

                              FYI, if I remove the bind clause completely, leaving the rule thus:

                               

                              RULE StatefulSessionComponent_destroyInstance
                              CLASS org.jboss.as.ejb3.component.stateful.StatefulSessionComponent
                              METHOD destroyInstance(StatefulSessionComponentInstance)
                              #BIND
                              #  appName:String = "<" + $this.getApplicationName() + "." + $this.getModuleName() + "." + $this.getDistinctName() + ">";
                              AT ENTRY
                              IF TRUE
                              DO
                                System.out.println("[BYTEMAN-StatefulSessionComponent] destroy instance, id: " + $1.getId())
                              ENDRULE
                              

                               

                              I see this error appearing in the logs:

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) Rule.ensureTypeCheckedCompiled : error type checking rule StatefulSessionComponent_destroyInstance

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) org.jboss.byteman.rule.exception.TypeException: MethodExpression.typeCheck : ambiguous method signature getId for target class org.jboss.as.ejb3.component.stateful.StatefulSessionComponentInstance file /home/nrla/byteman-scripts/script-server-cache.btm line 145

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.byteman.rule.expression.MethodExpression.findMethod(MethodExpression.java:325)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.byteman.rule.expression.MethodExpression.typeCheck(MethodExpression.java:188)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.byteman.rule.expression.StringPlusExpression.typeCheck(StringPlusExpression.java:52)

                              m08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.byteman.rule.expression.MethodExpression.findMethod(MethodExpression.java:293)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.byteman.rule.expression.MethodExpression.typeCheck(MethodExpression.java:188)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.byteman.rule.Action.typeCheck(Action.java:106)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.byteman.rule.Rule.typeCheck(Rule.java:523)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.byteman.rule.Rule.ensureTypeCheckedCompiled(Rule.java:449)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.byteman.rule.Rule.execute(Rule.java:672)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.byteman.rule.Rule.execute(Rule.java:653)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.as.ejb3.component.stateful.StatefulSessionComponent.destroyInstance(StatefulSessionComponent.java)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.as.ejb3.component.stateful.StatefulSessionComponent.destroyInstance(StatefulSessionComponent.java:75)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.as.ejb3.cache.simple.SimpleCache.stop(SimpleCache.java:91)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.as.ejb3.component.stateful.StatefulSessionComponent.done(StatefulSessionComponent.java:369)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.as.ejb3.component.EJBComponent.stop(EJBComponent.java:553)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.as.ee.component.ComponentStartService$2.run(ComponentStartService.java:78)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at java.util.concurrent.FutureTask.run(FutureTask.java:266)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at java.lang.Thread.run(Thread.java:745)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20) at org.jboss.threads.JBossThread.run(JBossThread.java:320)

                              08:17:16,770 INFO  [stdout] (ServerService Thread Pool -- 20)

                              • 12. Re: problems with org.jboss.as package names in Wildfly
                                Andrew Dinn Master

                                Hi Richard,

                                 

                                FYI, if I remove the bind clause completely, leaving the rule thus:

                                . . .

                                I see this error appearing in the logs:

                                . . .

                                 

                                 

                                Hmm, yes, it seems the problem will always occur with the current release even if, as with this example, the expected return type is supplied. The method filtering algorithm currently in uses employs the argument types to filter the set of available methods looking for a candidate implementaion. However, it does not use the return type.

                                 

                                That's something we can and should fix: BYTEMAN-310