My if() strategy is not working on more complex processes, because there seem 
to be nested calls to hasNextIncoming() and getNextIncoming() which make it 
impossible for me to know when to clear my cached XQEnvelope.  I was ending up 
with either a null or an infinite loop, so I'm going to have to try to make the 
pointcut work.

Here are my logs from a run where two calls to getNextIncoming() came 
back-to-back, causing the first one to succeed and the second one to retrieve 
null (because I clear the ThreadLocal after returning it):


[XQServiceAspect] In the around() advice before call to void 
com.sonicsw.xq.XQService.service(XQServiceContext)
In beforeCallToService: calling hasNextIncoming:  <-- call to the real Sonic 
method
In beforeCallToService: hasNextIncoming returned true
In beforeCallToService: getNextIncoming returned 
com.sonicsw.xqimpl.envelope.Envelope@14cbd50  <-- call to the real Sonic method
In beforeCallToService: stored in tlEnv: 
com.sonicsw.xqimpl.envelope.Envelope@14cbd50
[XQServiceAspect] beforeCallToService returned true
env=com.sonicsw.xqimpl.envelope.Envelope@14cbd50
msg=com.sonicsw.xq.connector.jms.XQJMSMessage@120f4c8
cmd=null
[XQServiceAspect] analyzeMessage returned true, calling service()
[XQServiceAspect] In the around() advice before call to boolean 
com.sonicsw.xqimpl.service.XQServiceChain.XQServiceContextWrapper.hasNextIncoming()
[XQServiceAspect] In the around() advice after call to boolean 
com.sonicsw.xqimpl.service.XQServiceChain.XQServiceContextWrapper.hasNextIncoming()
result=true

[XQServiceAspect] In the around() advice before call to XQEnvelope 
com.sonicsw.xqimpl.service.XQServiceChain.XQServiceContextWrapper.getNextIncoming()
[XQServiceAspect] In the around() advice after call to XQEnvelope 
com.sonicsw.xqimpl.service.XQServiceChain.XQServiceContextWrapper.getNextIncoming()
result=com.sonicsw.xqimpl.envelope.Envelope@14cbd50  <-- returned the 
XQEnvelope as expected

[XQServiceAspect] In the around() advice before call to XQEnvelope 
com.sonicsw.xq.service.xcbr.context.impl.InvocationContextImpl.getNextIncoming()
[XQServiceAspect] In the around() advice after call to XQEnvelope 
com.sonicsw.xq.service.xcbr.context.impl.InvocationContextImpl.getNextIncoming()
result=null  <-- because of a second call to getNextIncoming(), the ThreadLocal 
is now empty

[11/02/03 13:15:24] ID=dev_ESBCore (severe) [Dispatch] Exception calling 
service dev.CBR: message rejected
[11/02/03 13:15:24] ID=dev_ESBCore (severe) Trace follows...
java.lang.NullPointerException
        at com.sonicsw.xq.service.xcbr.XCBRService.service(Unknown Source)
        at com.sonicsw.xq.service.xcbr.XCBRService.service(Unknown Source)
        at com.sonicsw.xq.service.cbr.CBRService.service_aroundBody0(Unknown 
Source)
        at com.sonicsw.xq.service.cbr.CBRService.service(Unknown Source)
        at 
com.sonicsw.xqimpl.service.debug.DebugServiceInterceptor.intercept(Unknown 
Source)
        at 
com.sonicsw.xqimpl.service.XQServiceChain$XQInterceptorServiceWrapper.intercept(Unknown
 Source)
        at 
com.sonicsw.xqimpl.service.XQServiceChain$XQInterceptorServiceWrapper.service(Unknown
 Source)
        at 
com.sonicsw.xqimpl.service.XQServiceChain.service_aroundBody0(Unknown Source)
        at 
com.sonicsw.xqimpl.service.XQServiceChain$AjcClosure1.run(<Unknown>:1)
        at 
com.ncr.eai.esb.aop.XQServiceAspect.ajc$around$com_ncr_eai_esb_aop_XQServiceAspect$1$f783e081proceed(XQServiceAspect.java:1)
        at 
com.ncr.eai.esb.aop.XQServiceAspect.ajc$around$com_ncr_eai_esb_aop_XQServiceAspect$1$f783e081(XQServiceAspect.java:72)
        at com.sonicsw.xqimpl.service.XQServiceChain.service(Unknown Source)
        at com.sonicsw.xqimpl.service.ServiceMessageHandler.callService(Unknown 
Source)
        at 
com.sonicsw.xqimpl.service.ServiceMessageHandler.handleMessage(Unknown Source)
        at 
com.sonicsw.xqimpl.service.ProcessMessageHandler.doHandleMessage(Unknown Source)
        at 
com.sonicsw.xqimpl.service.ProcessMessageHandler.handleMessage(Unknown Source)
        at com.sonicsw.xqimpl.service.XQDispatcher.onMessage(Unknown Source)
        at 
com.sonicsw.xqimpl.endpoint.container.EndpointContextContainer.onMessage(Unknown
 Source)
        at 
com.sonicsw.xq.connector.jms.JMSEndpoint$JMSEndpointListener.onMessage(Unknown 
Source)
        at progress.message.jimpl.Session.deliver(Session.java:2952)
        at progress.message.jimpl.Session.run(Session.java:2358)
        at progress.message.jimpl.Session$SessionThread.run(Session.java:2743)
com.sonicsw.xq.XQServiceException:
        at com.sonicsw.xq.service.xcbr.XCBRService.service(Unknown Source)
        at com.sonicsw.xq.service.xcbr.XCBRService.service(Unknown Source)
        at com.sonicsw.xq.service.cbr.CBRService.service_aroundBody0(Unknown 
Source)
        at com.sonicsw.xq.service.cbr.CBRService.service(Unknown Source)
        at 
com.sonicsw.xqimpl.service.debug.DebugServiceInterceptor.intercept(Unknown 
Source)
        at 
com.sonicsw.xqimpl.service.XQServiceChain$XQInterceptorServiceWrapper.intercept(Unknown
 Source)
        at 
com.sonicsw.xqimpl.service.XQServiceChain$XQInterceptorServiceWrapper.service(Unknown
 Source)
        at 
com.sonicsw.xqimpl.service.XQServiceChain.service_aroundBody0(Unknown Source)
        at 
com.sonicsw.xqimpl.service.XQServiceChain$AjcClosure1.run(<Unknown>:1)
        at 
com.ncr.eai.esb.aop.XQServiceAspect.ajc$around$com_ncr_eai_esb_aop_XQServiceAspect$1$f783e081proceed(XQServiceAspect.java:1)
        at 
com.ncr.eai.esb.aop.XQServiceAspect.ajc$around$com_ncr_eai_esb_aop_XQServiceAspect$1$f783e081(XQServiceAspect.java:72)
        at com.sonicsw.xqimpl.service.XQServiceChain.service(Unknown Source)
        at com.sonicsw.xqimpl.service.ServiceMessageHandler.callService(Unknown 
Source)
        at 
com.sonicsw.xqimpl.service.ServiceMessageHandler.handleMessage(Unknown Source)
        at 
com.sonicsw.xqimpl.service.ProcessMessageHandler.doHandleMessage(Unknown Source)
        at 
com.sonicsw.xqimpl.service.ProcessMessageHandler.handleMessage(Unknown Source)
        at com.sonicsw.xqimpl.service.XQDispatcher.onMessage(Unknown Source)
        at 
com.sonicsw.xqimpl.endpoint.container.EndpointContextContainer.onMessage(Unknown
 Source)
        at 
com.sonicsw.xq.connector.jms.JMSEndpoint$JMSEndpointListener.onMessage(Unknown 
Source)
        at progress.message.jimpl.Session.deliver(Session.java:2952)
        at progress.message.jimpl.Session.run(Session.java:2358)
        at progress.message.jimpl.Session$SessionThread.run(Session.java:2743)
Caused by...
java.lang.NullPointerException
        at com.sonicsw.xq.service.xcbr.XCBRService.service(Unknown Source)
        at com.sonicsw.xq.service.xcbr.XCBRService.service(Unknown Source)
        at com.sonicsw.xq.service.cbr.CBRService.service_aroundBody0(Unknown 
Source)
        at com.sonicsw.xq.service.cbr.CBRService.service(Unknown Source)
        at 
com.sonicsw.xqimpl.service.debug.DebugServiceInterceptor.intercept(Unknown 
Source)
        at 
com.sonicsw.xqimpl.service.XQServiceChain$XQInterceptorServiceWrapper.intercept(Unknown
 Source)
        at 
com.sonicsw.xqimpl.service.XQServiceChain$XQInterceptorServiceWrapper.service(Unknown
 Source)
        at 
com.sonicsw.xqimpl.service.XQServiceChain.service_aroundBody0(Unknown Source)
        at 
com.sonicsw.xqimpl.service.XQServiceChain$AjcClosure1.run(<Unknown>:1)
        at 
com.ncr.eai.esb.aop.XQServiceAspect.ajc$around$com_ncr_eai_esb_aop_XQServiceAspect$1$f783e081proceed(XQServiceAspect.java:1)
        at 
com.ncr.eai.esb.aop.XQServiceAspect.ajc$around$com_ncr_eai_esb_aop_XQServiceAspect$1$f783e081(XQServiceAspect.java:72)
        at com.sonicsw.xqimpl.service.XQServiceChain.service(Unknown Source)
        at com.sonicsw.xqimpl.service.ServiceMessageHandler.callService(Unknown 
Source)
        at 
com.sonicsw.xqimpl.service.ServiceMessageHandler.handleMessage(Unknown Source)
        at 
com.sonicsw.xqimpl.service.ProcessMessageHandler.doHandleMessage(Unknown Source)
        at 
com.sonicsw.xqimpl.service.ProcessMessageHandler.handleMessage(Unknown Source)
        at com.sonicsw.xqimpl.service.XQDispatcher.onMessage(Unknown Source)
        at 
com.sonicsw.xqimpl.endpoint.container.EndpointContextContainer.onMessage(Unknown
 Source)
        at 
com.sonicsw.xq.connector.jms.JMSEndpoint$JMSEndpointListener.onMessage(Unknown 
Source)
        at progress.message.jimpl.Session.deliver(Session.java:2952)
        at progress.message.jimpl.Session.run(Session.java:2358)
        at progress.message.jimpl.Session$SessionThread.run(Session.java:2743)


My new strategy is to continue to return the same message from 
getNextIncoming() and only clear it if hasNextIncoming() returns nothing.  I'm 
concerned that may result in an infinite loop, but perhaps if I can get the 
pointcut to distinguish between calls within my advice and calls from Sonic 
classes, maybe I can make it works.

I tried adviceexecution(), but that didn't seem to work as expected.

Why won't a simple expression like !within(com.sonicsw..*) work?  Is my syntax 
wrong?  Shouldn't I be able to distinguish between their calls from the 
container and my own from within my aspect using something that simple?

Thanks,
Lee

-----Original Message-----
From: aspectj-users-boun...@eclipse.org 
[mailto:aspectj-users-boun...@eclipse.org] On Behalf Of Andy Clement
Sent: Thursday, February 03, 2011 1:28 PM
To: aspectj-users@eclipse.org
Subject: Re: [aspectj-users] Examining a destructive read in an aspect

I think you really should be able to single out the ones you are interested in 
at compile time.  I probably would have used
withincode() to scope exactly the one I'm interested in:

// Select the call to getNextIncoming() made within the method
XQServiceEx.service()
pointcut getIncoming(XQServiceContext ctx) : call(XQEnvelope
XQServiceContext.getNextIncoming()) && target(ctx) && withincode(* 
XQServiceEx.service());

But I can't immediately see why your within() (which is just a broader form of 
withincode really) isn't working for you.

Andy

On 3 February 2011 10:07, Grey, Lee <lee.g...@ncr.com> wrote:
> I think I have a solution, but I'm not sure whether it violates a best
> practice (or is just beneath a good aspect developer):
>
> I created a ThreadLocal<Boolean> to determine which invocations should
> be advised and which should not:
>
>  private static final ThreadLocal<Boolean> tlAdvise = new
> ThreadLocal<Boolean>() {
>   @Override protected Boolean initialValue() { return true; }
>  };
> Then I set the ThreadLocal to false when I want to run the real
> methods and to true when I want them to be short-circuited with my own advise:
>
>     ...
>   tlAdvise.set(false);
>   if( ctx.hasNextIncoming() ) {    // call the real Sonic code
>    System.out.println("In beforeCallToService: hasNextIncoming
> returned true");
>    XQEnvelope env = ctx.getNextIncoming();    // call the real Sonic
> code
>    tlAdvise.set(true);
>     ...
> My pointcuts use if:
>
>     pointcut hasIncoming() :
>      execution(boolean XQServiceContext.hasNextIncoming()) &&
>      if(tlAdvise.get());
> and
>
>     pointcut getIncoming() :
>      execution(XQEnvelope XQServiceContext.getNextIncoming()) &&
>      if(tlAdvise.get());
> Is this a brute-force solution to something that could be done far
> more elegantly and efficiently with just a little more pointcut
> knowledge?  Is there anything that makes this a bad idea?
>
> Thanks for your insights,
> Lee
> ________________________________
> From: aspectj-users-boun...@eclipse.org
> [mailto:aspectj-users-boun...@eclipse.org] On Behalf Of Grey, Lee
> Sent: Wednesday, February 02, 2011 11:45 PM
> To: aspectj-users@eclipse.org
> Subject: Re: [aspectj-users] Examining a destructive read in an aspect
>
> I've done what you suggested, and I think it would work fine, except
> that I can't get the pointcut right for the two calls I need to
> intercept.  I seem to be getting all or nothing.
>
> What pointcut would intercept the calls to ctx.hasNextIncoming() and
> ctx.getNextIncoming() when they come from the actual
> XQServiceEx.service() method but would still make the real,
> unadulterated calls when made from inside my aspect?
>
> My failed attempts include
>
> pointcut hasIncoming() : call(boolean
> XQServiceContext.hasNextIncoming()) && !within(com.sonicsw..*);
>
> pointcut getIncoming(XQServiceContext ctx) : call(XQEnvelope
> XQServiceContext.getNextIncoming()) && target(ctx) &&
> (within(XQService) || within(XQServiceEx));
>
> and other unsuccessful flailing.  I find creating successful pointcuts
> to be black magic.
>
> Thanks,
> Lee
> ________________________________
> From: aspectj-users-boun...@eclipse.org
> [mailto:aspectj-users-boun...@eclipse.org] On Behalf Of Ramnivas
> Laddad
> Sent: Monday, January 31, 2011 8:50 PM
> To: aspectj-users@eclipse.org
> Subject: Re: [aspectj-users] Examining a destructive read in an aspect
>
> You could do something along the following lines:
> 1. In your before advice read destructively as needed and store away
> the result 'env' in a ThreadLocal.
> 2. Advise ctx.getNextIncoming() with an around advice to return the
> stored result (and don't call proceed() in it).
> -Ramnivas
>
> On Mon, Jan 31, 2011 at 2:59 PM, Grey, Lee <lee.g...@ncr.com> wrote:
>>
>> I've been working on intercepting the service() method invocation in
>> a Sonic ESB container.  I had just started to write my before()
>> advice when the bad news dawned on me.  Just about every ESB
>> service() method starts with the following...
>>
>>    public void service(XQServiceContext ctx) throws
>> XQServiceException {
>>         XQEnvelope env = null;
>>         while (ctx.hasNextIncoming()) {
>>             env = ctx.getNextIncoming();
>>             if (env != null) {
>>                 XQMessage msg = env.getMessage(); That call to
>> ctx.getNextIncoming() is a destructive read that returns a different
>> XQEnvelope every time it's called.  The problem is that I need to
>> evaluate the contents of the message that comes from
>> ctx.getNextIncoming() in my before() advice.  What that means is that
>> the call to
>> ctx.getNextIncoming() in the service() method is not going to get the
>> message, because the before() advice already got it.
>>
>> Now I'm wondering if there's a way to put an aspect around
>> ctx.getNextIncoming() to make it deliver the message again.  Or if I
>> can somehow clone ctx so that I can read the cloned message in
>> before() and then read it from the real XQServiceContext object in service().
>> XQServiceContext doesn't offer any way to peek or browse, and it
>> doesn't have a method to put a message, either.
>>
>> I would imagine I'm not the first person to run into this kind of
>> issue with AOP before.  I'm hoping that there's a pattern to address it.
>>
>> Thanks,
>> Lee Grey
>> _______________________________________________
>> aspectj-users mailing list
>> aspectj-users@eclipse.org
>> https://dev.eclipse.org/mailman/listinfo/aspectj-users
>>
>
>
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@eclipse.org
> https://dev.eclipse.org/mailman/listinfo/aspectj-users
>
>
_______________________________________________
aspectj-users mailing list
aspectj-users@eclipse.org
https://dev.eclipse.org/mailman/listinfo/aspectj-users
_______________________________________________
aspectj-users mailing list
aspectj-users@eclipse.org
https://dev.eclipse.org/mailman/listinfo/aspectj-users

Reply via email to