Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
RE: [aspectj-users] Excluding Particular Joinpoints

Wes - you have waaay to much time on your hands man!  ;-)

-----Original Message-----
From: aspectj-users-bounces@xxxxxxxxxxx
[mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Wes Isberg
Sent: 01 December 2005 09:44
To: aspectj-users@xxxxxxxxxxx
Subject: RE: [aspectj-users] Excluding Particular Joinpoints


Hi all -

(To combine Ron and Bo Yi's answers...)

This is a vote for a client-visible API rather than annotations where
the subject is not an annotation target (method or class).

Getting annotations off the enclosing-static-part only works if the 
handler is in the annotated method, not in a called method.  Instead of
saying, "Don't log this exception," this approach says, "Don't advise
handlers in this method" (optionally conditioned on an exception class).

But the developer might also want to say, "This code throws exceptions
{of class E} that don't need to be logged" (regardless of where the
handler is).  Or they might want to say, "When you log exceptions
thrown, include [this interesting bit of context]."  To say it, they
shouldn't have to refactor methods, e.g., to make the annotation 
work for some handlers but not others.  Once the client is not only not
oblivious but also participating, then think carefully about how to
communicate with the aspect.

One way is directly:

  Logging.aspectOf().ignore(MyError.class);

That has the benefit of clarity, but commits to the aspect 
implementation.  You can hide behind a static method:

  public static void ignore(Class exceptionClass) {
     LoggingImpl.aspectOf().ignore(c);
  }

For code that not only hides but also compiles without aspectJ, use
stubs

  public static void ignore(Class exceptionClass) {
     // advise me
  }

implemented with ITD's (if non-static in subtypes) or advice:

  before(Class c) : execution(void Logging.ignore(Class)) && args(c) {
     LoggingImpl.aspectOf().ignore(c);
     // or...
     ignore(c);
  }

A ThreadLocal is another way to maintain this kind of mode-status that
works whether the subject code in question runs later in time, in the
context of something, or specific snippets of code. The hard part in
Java is clearing the thread-local context which means boilerplate like

   myLocal.get().ignore(MyError.class);
   try {
      ... do stuff
   } finally {
     myLocal.get().dontIgnore(MyError.class);
   }

That's easy in AspectJ; just have the threadlocal class keep the 
context in a stack, and clear the stack to the same level on exiting a
join point as it was on entering the join point:

   Object around() : stackPoints() {
      int stackIndex = LogContext.stackIndex();
      try {
         return proceed();
      } finally {
         LogContext.setStackIndex(stackIndex);
      }
   }

Then any logging system, AspectJ or otherwise, can inspect the context
stack for instructions, additional context information to log, etc.

Using AspectJ to terminate means "this code" ends with the next
enclosing 
join point picked out by stackPoints().  That has its own problems.  
When some code deep in the bowels that was invoked by "... do stuff" 
expects MyError to be logged and it isn't, it might not
be easy to find where it was suppressed (absent a facility to log when
exception logging is suppressed :)  Then you go down the path of
unsuppressing it, which might not be valid for other callers...

For a handler-specific call, you can terminate directly, just as you
would in Java:

   myLocal.get().ignore(MyError.class);
   ... do stuff
   myLocal.get().dontIgnore(MyError.class);

So the client is managing the context directly (and needs 
cleaner API's).

The power of stashing additional context in case you end up logging 
something later is that it avoids pessimistic logging - logging in case
something happens later and you want to know more about 
what happened before that happened.  Instead of always 
logging it, it logs only when something actually happens, as relevant
context (and in the same message?).

So for this logging-context pattern, you typically

- define API's for publishing clients,

class LogContext {
  void suppress(Class exceptionClass) { ... }
  void dontSuppress(Class exceptionClass) { ... }
  void addLogSupplement(String info) { ... }
  ...
}

- for subscribing clients,

    Class[] suppressedExceptions() { ... }
    String[] getLogSupplements() { ... }

- and for managing clients, 

    int position() { ... }
    void setPosition(int p) { ... }

- and then implement using threadlocals if not static convenience
methods class LogContext {
  static ThreadLocal<LogContext> sfLocal;
  public static LogContext current()  { return sfLocal.get(); }
  public static void suppress(Class exceptionClass) {
    current().suppress(exceptionClass);
  }
  ...
}
.. and AspectJ to pop the context stack...

This solution adapts to most any blend of AspectJ/Java logging, from 
no-AspectJ (with the context-clearing boilerplate above) to everything-
done-in-aspects (e.g., automatically adding public method String
parameters to the context when in verbose mode ...).  It makes other
coders and managers happy if they can decide how much of the 
implementation is in AspectJ, which is good for logging as an entry app.

Most applications of AspectJ for logging/tracing get hung up on this 
divide of aspect/client, particularly when trying to tailor output. In
most real systems, the aspect does some top-down tracing, and the 
client does some bottom-up logging.

Separating the two can make it hard to correlate the information and you
lose the opportunity for the aspects to make things easier for the
client.  By contrast, if you make a common facility (i.e., if your
clients are not all oblivious), your aspects can support some simple but
powerful API's for clients.  Beyond suppressing exception logging and
supplementing logs, you can

o get context known to advice, e.g., source location
   String getSourceLocation() {
      ... stub, implemented by advice on caller
   }

o tailor verbosity to particular contexts or modes

o serialize logging operations out to separate threads,
  or defer logging until after client-specified critical sections
  have completed

and so on...

So my rule would be if you're using annotations as a way for the 
client to guide the work of an aspect, consider using an API instead
unless what's being said is strongly related to the form of the
annotation target (class or method) or to the content of the annotation
- e.g., a verbosity flag:

   @Verbosity(INFO)
   String doSomething() {..}

Wes

> ------------Original Message------------
> From: "Ron Bodkin" <rbodkin@xxxxxxxxxxxxxx>
> To: aspectj-users@xxxxxxxxxxx
> Date: Wed, Nov-30-2005 10:19 PM
> Subject: RE: [aspectj-users] Excluding Particular Joinpoints
>
> Just to clarify my original posting, I was showing how to match
> exception
> handler join points that are enclosed inside annotated methods (or 
> other
> sources). The only way to do that is with code like I posted (you
could 
> put
> it in an if pointcut designator if you like).
> 
> Dean's code is the right way to match join points (such as method
> execution)
> that exit by an exception from an annotated method.
> 
> -----Original Message-----
> From: aspectj-users-bounces@xxxxxxxxxxx 
> [mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Dean Wampler
> Sent: Wednesday, November 30, 2005 9:57 PM
> To: aspectj-users@xxxxxxxxxxx
> Subject: Re: [aspectj-users] Excluding Particular Joinpoints
> 
> You can exclude the method annotation in the PCD itself. Here is a 
> complete example:
> 
> TestExcludeExceptions.aj: Aspect that declares a nested method 
> annotation "DontLog". Note the PCD that excludes methods with this 
> annotation.
> 
> import java.lang.annotation.ElementType;
> import java.lang.annotation.Target;
> 
> public aspect ExcludeExceptions {
> 	@Target(ElementType.METHOD)
> 	public static @interface DontLog {}
> 	
> 	pointcut watch(): execution (!@DontLog * *.*(..));
> 	
> 	after() throwing(Throwable th): watch() {
> 		System.err.println("Oops! "+thisJoinPointStaticPart+":
"+th);
> 	}
> }
> 
> TestExcludeExceptions.aj: Test routine. You'll see the advice "Oops!" 
> message only after calls to "failUnexpected()", because 
> "failExpected()" has the marker annotation "DontLog". (The "okay()" 
> method is for "background subtraction" - that's a bone for you other 
> physicists out there... ;)
> 
> public class TestExcludeExceptions {
> 	public void okay() {
> 		System.out.println ("TestExcludeExceptions.okay():");
> 	}
> 	
> 	@ExcludeExceptions.DontLog
> 	public void failExpected() {
> 		System.out.println
("TestExcludeExceptions.failExpected():");
> 		throw new RuntimeException();
> 	}
> 	
> 	public void failUnexpected() {
> 		System.out.println
("TestExcludeExceptions.failUnexpected():");
> 		throw new RuntimeException();
> 	}
> 	
> 	public static void main(String[] args) {
> 		TestExcludeExceptions tee = new TestExcludeExceptions();
> 		tee.okay();
> 		try {
> 			tee.failExpected();
> 		} catch (Throwable th) {}
> 		try {
> 			tee.failUnexpected();
> 		} catch (Throwable th) {}
>        }
> }
> 
> dean
> 
> On 11/30/05, Ron Bodkin <rbodkin@xxxxxxxxxxxxxx> wrote:
> >
> >
> >
> > You can use the signature at the enclosing join point static part to
> get
> the
> > right Java reflective object (a Method or Constructor). For example,
> >
> ((MethodSignature)thisEnclosingJoinPointStaticPart.getSignature()).get
> Method
> ().getAnnotation(myAnnotationType);
> >
> >
> >
> > You probably want to have at least 2 cases for method and
> constructor. To
> be
> > totally complete there are 6 cases (for advice, initialization, 
> > pre-initialization and static initialization). To support static 
> > initialization you'd want to have annotations on the class too.
> >
> >
> >
> > http://dev.eclipse.org/mhonarc/lists/aspectj-dev/msg00655.html
> >
> >
> >
> >  ________________________________
> >
> >
> > From: aspectj-users-bounces@xxxxxxxxxxx 
> > [mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Tobias 
> > Dunn-Krahn
> >  Sent: Wednesday, November 30, 2005 4:13 PM
> >
> >  To: aspectj-users@xxxxxxxxxxx
> >  Subject: RE: [aspectj-users] Excluding Particular Joinpoints
> >
> >
> >
> >
> > Hi Ron,
> >
> >
> >
> > I agree that annotating the method is the cleanest proposal so far.
> One
> > problem though. I can't figure out how to examine annotations from 
> > thisEnclosingJoinpointStaticPart (or the JoinPoint interface in 
> > general).  Any hints?
> >
> >
> >
> > Tobias
> >
> >
> >
> >  ________________________________
> >
> >
> > From: aspectj-users-bounces@xxxxxxxxxxx 
> > [mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Ron Bodkin
> >  Sent: Wednesday, November 30, 2005 2:32 PM
> >  To: aspectj-users@xxxxxxxxxxx
> >  Subject: RE: [aspectj-users] Excluding Particular Joinpoints
> >
> >
> >
> > Hi Tobias,
> >
> >
> >
> > You can use annotations at the method level to address this: you
> could
> then
> > look at thisEnclosingJoinPointStaticPart to see if there is an 
> > appropriate annotation. If you find that the same exception is
> handled
> > differently in the same method, I'd suggest extracting a method to
> deal
> with
> > this. This would be a lot cleaner than using a naming convention on
> the
> > methods.
> >
> >
> >
> > As you noted, it isn't possible to use variable annotations both
> because
> > they are not retained in the binary representation and AspectJ 
> > relies
> on
> > binary representations for weaving. Also AspectJ doesn't in general
> expose
> > information about local variables (e.g., there is way to match
> pointcuts
> or
> > expose join point information based on local variables). By the same
> token,
> > you can't determine the name of the local variable being used in the
> catch
> > block, so a naming convention like this wouldn't help with AspectJ.
> This
> is
> > a good thing IMHO: it would be too brittle if renaming local
> variables
> would
> > change pointcut matching.
> >
> >
> >
> >  ________________________________
> >
> >
> > From: aspectj-users-bounces@xxxxxxxxxxx 
> > [mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Tobias 
> > Dunn-Krahn
> >  Sent: Wednesday, November 30, 2005 2:03 PM
> >  To: gregor@xxxxxxxxx; aspectj-users@xxxxxxxxxxx
> >  Subject: RE: [aspectj-users] Excluding Particular Joinpoints
> >
> >
> >
> > Gregor and Ron,
> >
> >
> >
> > Thanks for your suggestions.  Unfortunately in my case, I can't
> determine
> > from just the Throwable whether or not it should be logged.  For
> example,
> a
> > FooBarException should be logged in some cases but not others,
> depending
> on
> > the surrounding application logic.  Really the only way to determine
> this
> is
> > a decision on the part of developer, which is why I was 
> > experimenting
> with
> > annotations.
> >
> >
> >
> > Perhaps I could use thisJoinPoint in combination with a naming
> convention
> > for the throwable, i.e. any throwable named "expectedThrowable" 
> > would
> not
> be
> > logged.  It would be nice if I could do something more explicit 
> > (like
> an
> > annotation) but perhaps it's not possible.  Please let me know if
> I've
> > misunderstood something about your suggestions.
> >
> >
> >
> > Thanks,
> >
> > Tobias
> >
> >
> >
> >  ________________________________
> >
> >
> > From: aspectj-users-bounces@xxxxxxxxxxx 
> > [mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Gregor 
> > Kiczales
> >  Sent: Wednesday, November 30, 2005 1:26 PM
> >  To: aspectj-users@xxxxxxxxxxx
> >  Subject: RE: [aspectj-users] Excluding Particular Joinpoints
> >
> >
> >
> >  ________________________________
> >
> >
> > From: aspectj-users-bounces@xxxxxxxxxxx 
> > [mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Tobias 
> > Dunn-Krahn
> >
> >
> >
> > I am using AspectJ in a project to log all handled exceptions.  In
> general
> > this is what I want, but in a small number of cases such exceptions
> are
> > "expected" and I do not wish to log them.
> >
> >
> >
> > aspect FooBarExceptionLoggingStrategy {
> >
> >
> >
> >   before(Throwable t): handler(Throwable) && args(t) {
> >
> >     if( shouldLog(t) )
> >
> >        log(t);
> >
> >   }
> >
> >
> >
> >   private boolean shouldLog(Throwable t) {
> >
> >     <<test whatever needs testing here>>
> >
> >   }
> >
> >
> >
> >   private void log(Throwable t) {
> >
> >     ...
> >
> >   }
> >
> > }
> >
> >
> >
> > The point being that you can test the exception in any way you want
> before
> > logging it.
> >
> > You could also pass thisJoinPoint or thisJoinPointStaticPart. If you
> want,
> > you could
> >
> > move shouldLog into the actual pointcut, using if(shouldLog(t)).
> >
> >
> >
> >
> >
> >
> >
> >  ________________________________
> >
> >
> > From: aspectj-users-bounces@xxxxxxxxxxx 
> > [mailto:aspectj-users-bounces@xxxxxxxxxxx] On Behalf Of Tobias 
> > Dunn-Krahn
> >  Sent: Wednesday, November 30, 2005 11:42 AM
> >  To: aspectj-users@xxxxxxxxxxx
> >  Subject: [aspectj-users] Excluding Particular Joinpoints
> >
> > Hello All,
> >
> >
> >
> > I am using AspectJ in a project to log all handled exceptions.  In
> general
> > this is what I want, but in a small number of cases such exceptions
> are
> > "expected" and I do not wish to log them.  My pointcut definition is

> > currently very simple; it matches all exception handlers except 
> > those
> that
> > handle SocketTimeoutExceptions:
> >
> >
> >
> >   pointcut exceptionHandlers(Throwable t) : handler(Throwable+) &&
> (args(t)
> >
> >       && !args(java.net.SocketTimeoutException));
> >
> >
> >
> > However, now I need to exclude matching of particular exception
> handlers
> > that are not distinguishable by type.  I tried creating a custom
> annotation
> > with target type LOCAL_VARIABLE and using this annotation to 
> > decorate
> the
> > exception, but unfortunately annotations of this type are not
> retained for
> > runtime (and are therefore inaccessible).  Does anyone have any
> suggestions?
> >
> >
> >
> > Thanks in advance,
> >
> > Tobias
> >
> >
> > _______________________________________________
> > aspectj-users mailing list
> > aspectj-users@xxxxxxxxxxx 
> > https://dev.eclipse.org/mailman/listinfo/aspectj-users
> >
> >
> >
> 
> 
> --
> Dean Wampler
> http://www.aspectprogramming.com
> http://www.newaspects.com
> http://www.contract4j.org
> 
> _______________________________________________
> 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


* ** *** ** * ** *** ** * ** *** ** * 
This email and any files transmitted with it are confidential and 
intended solely for the use of the individual or entity to whom they 
are addressed. 
Any views or opinions presented are solely those of the author, and do not necessarily 
represent those of ESB. 
If you have received this email in error please notify the sender. 
 
Although ESB scans e-mail and attachments for viruses, it does not guarantee 
that either are virus-free and accepts no liability for any damage sustained 
as a result of viruses. 
 
* ** *** ** * ** *** ** * ** *** ** *



Back to the top