Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Examining a destructive read in an aspect

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-bounces@xxxxxxxxxxx [mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Andy Clement
Sent: Thursday, February 03, 2011 1:28 PM
To: aspectj-users@xxxxxxxxxxx
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.Grey@xxxxxxx> 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-bounces@xxxxxxxxxxx
> [mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Grey, Lee
> Sent: Wednesday, February 02, 2011 11:45 PM
> To: aspectj-users@xxxxxxxxxxx
> 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-bounces@xxxxxxxxxxx
> [mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Ramnivas
> Laddad
> Sent: Monday, January 31, 2011 8:50 PM
> To: aspectj-users@xxxxxxxxxxx
> 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.Grey@xxxxxxx> 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@xxxxxxxxxxx
>> https://dev.eclipse.org/mailman/listinfo/aspectj-users
>>
>
>
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/aspectj-users
>
>
_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/aspectj-users


Back to the top