5 Replies Latest reply on Jun 11, 2007 6:12 AM by kabirkhan

    How to avoid intercepting recursive calls

    system.out

      I have a class with some methods to be intercepted:

      methodOne()
      methodTwo()
      methodThree()

      I want to intercept any external calls to these 3 methods, i.e. If methodOne is calling the methodTwo(), that would be internal call and methodTwo shouldn't be intercepted.

      Is it possible?

        • 1. Re: How to avoid intercepting recursive calls
          kabirkhan

          You can use cflow http://labs.jboss.org/jbossaop/docs/1.5.0.GA/docs/aspect-framework/examples/cflow/cflow.html

          CFlow does have some limitations though.We cannot do the full wildcard matching that we do in normal method expressions since we are limited to what is output by the stack trace.

          Also, there is an overhead since we need to throw an exception for every joinpoint to evaluate the stack trace.

          • 2. Re: How to avoid intercepting recursive calls
            system.out

            <cflow-stack> is not the one I am looking for. There is no stack requirement in my case. I think solution would be in <!within> keyword.
            here is another example:

            Pointcuts:
             prepare()
             authorize()
             post()

            User/Client calls:
            client ==> prepare() -> intercept it
            client ==> authorize() -> intercept it

            but if prepare() internally is calling authorize(), then:
            client ==> prepare() -> intercept it
            prepare ==> authorize() // don't intercept it, as this call has been intercepted before within prepare method


            • 3. Re: How to avoid intercepting recursive calls
              kabirkhan

               


              <cflow-stack> is not the one I am looking for.

              The purpose of cflow is exactly what you mention in the original problem - you need something along the lines of:

              <aop>
               <cflow-stack name="NotRecursivePOJO">
               <not-called expr="* POJO->*(..)"/>
               </cflow-stack>
              
               <bind pointcut="execution(public * POJO->*(..))" cflow="NotRecursivePOJO">
               <interceptor class="Blah"/>
               </bind>
              </aop>
              


              I cannot remember if wildcards are allowed in cflow-stack/not-called, if not you will need to explicitly list all methods in not-called elements:
               <cflow-stack name="NotRecursivePOJO">
               <not-called expr="void POJO->authenticate(..)"/>
               <not-called expr="void POJO->prepare(..)"/>
               <not-called expr="void POJO->post(..)"/>
               </cflow-stack>
              


              Please let me know which of these two approaches work, and I can try to update the docs

              "within" is only usable with "call()" pointcuts

              • 4. Re: How to avoid intercepting recursive calls
                system.out

                Thanks Kabir, I think it can be an option.
                I have 2 questions now:

                1. How can I exclude the first method call from <not-called> list. i.e. in my previous example, prepare() won't be intercepted if I have all 3 methods in <not-called> list? Is that correct?

                2. Can <not-called> be applied at class level/package name?

                • 5. Re: How to avoid intercepting recursive calls
                  kabirkhan

                  1) Incorrect

                  <aop>
                   <cflow-stack name="NotRecursivePOJO">
                   <not-called expr="* POJO->prepare(..)"/>
                   </cflow-stack>
                  
                   <bind pointcut="execution(public * POJO->prepare(..))" cflow="NotRecursivePOJO">
                   <interceptor class="Blah"/>
                   </bind>
                  </aop>
                  


                  Will allow the method to be called. The not-called part makes sure it has not been called *previously*. Take a look at the "cflow" tutorial that comes with the dist.

                  2) I updated our tests and you can use wildcards so the following is valid
                  <aop>
                   <cflow-stack name="NotRecursivePOJO">
                   <not-called expr="* org.blah.POJO->*(..)"/>
                   </cflow-stack>
                  
                   <bind pointcut="execution(public * org.blah.POJO->*(..))" cflow="NotRecursivePOJO">
                   <interceptor class="Blah"/>
                   </bind>
                  </aop>
                  


                  You can also do more advanced things with the classname such as
                  <aop>
                   <cflow-stack name="NotRecursivePOJO">
                   <not-called expr="* @org.blah.SomeAnnotation->*(..)"/>
                   <not-called expr="* $instanceof(org.blah.Base}->get*(..)"/>
                   <not-called expr="* $typedef(someDef}->*(..)"/>
                   <not-called expr="* org.blah.Value*->*(..)"/>
                   </cflow-stack>
                  


                  Note that the access specifiers, return type and parameters are not used during the matching stage since this info is not avialble in StackTraceElement, all we have are the class and the method name.
                  http://java.sun.com/j2se/1.4.2/docs/api/java/lang/StackTraceElement.html