Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-dev] around advice & exceptions

> I dont know what you mean by "...close over the proceed(..) invocation
> and pass that to the method, perhaps using a nested class that
> permits the callee to modify the context used to proceed." 

Sorry.  I'm slightly misusing the term closure:

 http://en.wikipedia.org/wiki/Closure_%28computer_science%29

The point for proceed(..) is that it encapsulates all the join
point context, even though only the join point context that is
declared is required in the parameter list.  To "close over" the
proceed means to invoke proceed in a class constructed in the 
method. The object can then be passed to a delegate method, 
implicitly along with all the join point context.  This can 
even be invoked later, after the join point returns.  

Here's the simplest example:

  void around() : something() {
     check(new Runnable() { public void run()  { proceed(); }});
  }
  void check(Runnable proceed) {
    ...
    proceed.run();
    ...
  }

Here's one that permits clients to change the context:

  abstract public static class StringProceed implements Runnable {
    protected String context;
    public void setContext(String input) { context = input; }
  }
    
  void around(String message) : something(message) {
     check(new StringProceed() {
        public void run()  { proceed(context); }
     });
  }
  void check(StringProceed proceed) {
    proceed.setContext("Hello, World!");
    proceed.run();
    ...
  }

Since you can use this to permit delegates to do anything that
around does, there's no limit to what you can do with this.  I
used it in the AOSD "Good AOP" presentation to implement fully
dynamic advice that changes at runtime using pluggable delegates.
Ramnivas popularized another use of this technique in an "AspectJ
in Action" section on the worker pattern.  It's better than
reflection, because in reflection you have to know everything
about what you're invoking; here you only need to surface the
context that should be variable.  However, since proceed(..)
invokes all less-precedent advice and the join point itself,
misuse can lead to extremely weird behavior and memory leaks.

Wes

> ------------Original Message------------
> From: Rafal Krzewski <Rafal.Krzewski@xxxxxxxxx>
> To: aspectj-dev@xxxxxxxxxxx
> Date: Thu, Mar-24-2005 2:56 AM
> Subject: Re: [aspectj-dev] around advice & exceptions
>
> Wes Isberg wrote:
> 
> > First, a side note: your proxy pattern invokes the method directly,
> > rather than using proceed(..). As a result, any less-precedent advice
> > will not run. It's better to close over the proceed(..) invocation
> > and pass that to the method, perhaps using a nested class that
> > permits the callee to modify the context used to proceed.  Doing
> > that will cause other advice to run properly and also works for
> > join points besides method-execution.
> 
> Aha. You helped me to realize that I didnt' need to use reflection 
> alltogether! The following handles my use case (except the exceptions, 
> so to speak)
> 
>    Object around(Object o) : proxyOperations(o)
>    {
>      return proceed(delegate == null ? o : delegate);
>    }
> 
> I dont know what you mean by "...close over the proceed(..) invocation
> and pass that to the method, perhaps using a nested class that
> permits the callee to modify the context used to proceed." Please 
> explain if you have a moment to spare.
> 
> > In theory, your proposal doesn't 
> > expand what the join point can throw, so any advice or code that gets 
> 
> > control in an exception handler should be expecting the exception.
> > I'd want to verify that. 
> 
> This was exactly my intention: unwrap the exceptions that are expected 
> in the join point context and nothing more. An attempt to unwrap 
> unexpected exception raises an Error.
> 
>  > (I'm less happy about using "throws
> > UnwrappableException" to mean "this advice unwraps any 
> > UnwrappableException it can" but I think that's a separate issue.)
> 
> I'm not too happy about the name either. It was the first thing that 
> came to my mind. I'll let native english speakers come up with a name 
> that suits the idea better ;-)
> 
> > Also, doing this exception macro thingy at each join point would 
> entail 
> > every implementation of AspectJ doing the same thing, so we might
> > be committing them to a particular implementation of around advice.
> 
> First, I think the contract could be expanded to before and after 
> advice 
> too. Second, I don't see obvious implemention constraints (maybe 
> because 
> I don't know the implementation). Of course it is an extension of the 
> language, and if an implementation does not support it, the 
> UnwrappedException will be treaded as an ordinary exception and the 
> compiler will complain that the piece of advice declares an exception 
> that is not excpected in the join point context (if I understand 
> correctly).
> 
> > I'm not sure yet why you need to catch and rethrow the exceptions.
> > You seem to be using reflection (and having to unwrap things like
> > InvocationTargetException) rather than just changing the context
> > using proceed.  E.g.,
> > 
> >     Object around(Object original)  : proxied(original) {
> >         Object result = originalToProxy.get(original);
> >         return proceed(null == result ? original : result);
> >     }
> 
> Umm, that's exactly what I wrote after reading the first paragraph!
> Well, maybe I was under a false impression that I need to catch/rethrow 
> 
> any checked exceptions that may be thrown in the proxied method. I 
> would 
> have to do that in reflection scenario, but you made me realize I don't 
> 
> need it.
> 
> I made a quick test on my modified code and I found out that around 
> advice work seamlesly with the various checked exceptions that the 
> advised mehtods are throwing! Yipee! I can go on with my toy project 
> instead of commiting to AspectJ development ;-)
> 
> > (Note that you can get a lot of benefit from using the supertype of
> > some context object, because it enables you to pick out join points
> > whose context objects are different types but share the same 
> supertype.
> > However, you will cause a ClassCastException if your replacement 
> object
> > is not the right type for this join point.)
> 
> Understood. In my particular scenario, I will be using replacements 
> that 
> are always the same type as the original object, created using clone() 
> method.
> 
>  > If your NPE is reproducible in the latest version of AspectJ,
>  > please submit it as a bug.
> 
> I'll whip up a minimal test case and submit it tomorrow morning.
> 
> Thanks for the explainations!
> 
> Rafal
> _______________________________________________
> aspectj-dev mailing list
> aspectj-dev@xxxxxxxxxxx
> http://dev.eclipse.org/mailman/listinfo/aspectj-dev
> 



Back to the top