3 Replies Latest reply on Oct 21, 2015 10:05 AM by Ondra Chaloupka

    Rule of child class triggered for a method implemented in a parent class

    Ondra Chaloupka Expert

      Hi,

       

      I'm struggling with the topic and I would like ask for help as I'm not able to find the right way.

       

      I would like have this kind of rule

      RULE commit_faultinjection
      CLASS org.jboss.jca.core.tx.jbossts.LocalConnectableXAResourceImpl
      METHOD commit
      AT ENTRY
      IF true
      DO debug("firing commit_faultinjection", $0);
      throw new org.jboss.jca.core.spi.transaction.local.LocalXAException("Byteman expected exception", 8);
      ENDRULE

      My trouble is that the class LocalConnectableXAResourceImpl does not implement method commit which is implemented in its super class LocalXAResourceImpl. The rule as I wrote it is not executed.

       

      If I change the rule in way that class is defined as

      RULE commit_faultinjection

      CLASS org.jboss.jca.core.tx.jbossts.LocalXAResourceImpl

      ...

      then the rule is triggered and exception is thrown. But I would like to be sure that the class LocalConnectableXAResourceImpl is really used in execution and I would like to bind the rule to it.

       

      Please, is there chance or some easy solution (that I've overlooked) to define the rule on child class even the child class does not implement the method?

       

      I've finished with this kind of solution but seems to me clumsy

      RULE commit_faultinjection
      CLASS ^org.jboss.jca.core.tx.jbossts.LocalXAResourceImpl
      METHOD commit
      AT ENTRY
      BIND className:String = $this.getClass().getName();
      IF className.equals("org.jboss.jca.core.tx.jbossts.LocalConnectableXAResourceImpl")
      DO debug("firing commit_faultinjection", $0);
      throw new org.jboss.jca.core.spi.transaction.local.LocalXAException("Byteman expected exception", 8);
      ENDRULE

       

      Thanks for any idea

      Ondra

        • 1. Re: Rule of child class triggered for a method implemented in a parent class
          Ondra Chaloupka Expert

          Hi adinn,

           

          I'm sorry to bothering you by pushing this up just wouldn't you have some tip for me?

           

          Or in case could you confirm that this is behavior by design and I need to apply some workaround?

           

          Thanks a lot

          ondra

          • 2. Re: Rule of child class triggered for a method implemented in a parent class
            Andrew Dinn Master

            Hi Ondra,

             

            Sorry for not replying sooner -- I have been off sick for a few days.

             

            The short answer is that this is by design -- at least according to the current design. Which means that for the moment your work-around is about as near as it is possible to get to the desired functionality.

             

            n.b. I think you don't actually need the ^ in the CLASS clause though. If LocalConnectableXAResourceImpl inherits its commit method directly from LocalXAResourceImpl then there is no reason to inject into other subclasses of LocalXAResourceImpl. If it inherits from some intermediate class then you need to inject direct into that intermediate class and still don't need the ^.

             

            The long answer (in case you or someone else wants to know why) is as follows:

             

            What you are asking for is to be able to specify a rule on CLASS X METHOD m and have the Byteman agent recognise the situation where X < Y X and X inherits Y.m rather than implementing it. Byteman is only in a posiiton to recognise that there is no X.m when class X is loaded and handed over to the agent for transformation. At that point it is passed a byte[] holding the bytecode for class X and is allowed to return a modified byte[] which specifies a dfiferent version of class X.

             

            That's all the JVMTI Java agent API allows Byteman to do. It cannot at that point transform class Y. Indeed, it cannot even rely on class Y having already been loaded. That sounds odd but transformation is triggered at class loadi time not at class resolve time. So, when a method which refers to X is resolved that will force loading and transformation of X even if Y is not yet loaded. After X has been loaded then Y will be loaded and after Y is reosolved then X will be resolved. Which means Byteman can be sure that X does not implement m but cannot be sure whether a parent class does so.

             

            So, what if Byteman just loaded class Y itself during transformation of X. Unfortunately, this would mean that any rules defined on class Y will not be injected because the JVM will not re-enter the transformer code whne loading code from with an agent transformer. If Byteman loads classes it misses chances ot inject rules. So, Byteman does its very best to avoid loading classes during transformation. Of course, if it cannot load Y while transforming X then it cannot transform Y while transforming X.

             

            To work around this Byteman could just note that X.m does not exist and schedule a separate thread to look up the supers chain for a target method for the rule. That would still not be good enough for several reasons.

             

            Firstly, the transformation would not happen immediately which means Y.commit could be called on an instance of calss X before the tarnsform happened i.e. the semantics of transformation become more fuzzy.

             

            Secondly, scheduling transformation in a separate thread is potentially slow and needs to be careful to avoid deadlocks: the dedicated thread may initiate a load while it has the transform queue locked and that load may be locked out by another thread which wants to schedule a thread for transformation.

             

            The third problem is that the trigger code injected into Y.m needs to include a guard and skip so that the trigger region is only entered when $this is an instanxce of X. That's ok if X is visible in the classloader of Y -- you just plant the bytecode sequence aload0, instanceof "X", if_eq before the normal injected code. However, if X is not visible thne you have to plant code to obtain the classname of $this and compare it against the relevant String name for X. This is feasible but clumsy.

             

            The fourth problem is that you have to type check the rule on the assumption that $this is an X not a Y. If X and Y are defined in different loaders then this mean using the loader of Y not X to do the checking. Byteman does not currently do that (although it is possible to make this work).

            • 3. Re: Rule of child class triggered for a method implemented in a parent class
              Ondra Chaloupka Expert

              I see. Thanks for the explanation.

               

              I really appreciate your "answer kind of articles" in any of your replies. It's really nice way how to understand how the things work. Thanks again for it!