[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
RE: [aspectj-users] passing an extra parameter to existing method s
|
For now I'm experimenting with being able to pass a "context" object to
all methods of my session beans. I got your suggestion to work.
Thanks again! I've included the aspect code below. It's amazing how
simple this turned out to be!
First some background.
I have a class called Demo that produces the "context" data I want to
make available to my session bean methods. I have a class called Account
that represents a session bean ... even though it's just a plain Java object in
my prototype.
I add a field to my Demo class called context by making it implement an
interface I call ContextPasser.
I add a method to my Account class called invoke by making it implement
an interface I call ContextReceiver. The invoke method dumps out data in
the Context object that is passed to it and then uses reflection to invoke the
real method.
All calls to the real methods in the Account class are intercepted and
made to go through the invoke method.
---
package com.agedwards.aspects;
import com.agedwards.bank.Account;
import
com.agedwards.bank.Context;
import com.agedwards.bank.Demo;
import
java.lang.reflect.*;
import
org.aspectj.lang.reflect.MethodSignature;
aspect ContextAspect {
//-------------------------------------------------------------------------
// Specify ContextPasser interface.
//-------------------------------------------------------------------------
public interface ContextPasser {}
private Context
ContextPasser.context;
//-------------------------------------------------------------------------
// Specify ContextReceiver interface.
//-------------------------------------------------------------------------
public interface ContextReceiver
{}
private Object
ContextReceiver.invoke
(Context
context, String methodName, Class[] types, Object[] args)
{
Class clazz =
getClass();
System.out.println("Context: " + clazz.getName()
+
" method
" + methodName + " called, context = " + context);
Object result =
null;
try
{
Method
method = clazz.getMethod(methodName,
types);
result = method.invoke(this,
args);
} catch
(IllegalAccessException e)
{
handleException(e);
} catch
(InvocationTargetException e)
{
handleException(e);
} catch
(NoSuchMethodException e)
{
handleException(e);
}
return
result;
}
private void ContextReceiver.handleException(Exception
e) {
e.printStackTrace();
System.exit(1);
}
//-------------------------------------------------------------------------
// Modify the Demo class to support the ContextHolder
interface.
//-------------------------------------------------------------------------
declare parents: Demo implements
ContextPasser;
pointcut demoSetup(Demo
demo):
execution(void
Demo.setup()) && this(demo);
after(Demo demo): demoSetup(demo)
{
demo.context = new
Context(demo.getBank(), demo.getTeller());
}
//-------------------------------------------------------------------------
// Modify the Account class to provide logging with Context
info.
//-------------------------------------------------------------------------
declare parents: Account implements
ContextReceiver;
pointcut accountDeposit(ContextPasser
passer):
call(*
Account.deposit(..)) && this(passer);
void around(ContextPasser passer):
accountDeposit(passer) {
ContextReceiver receiver = (ContextReceiver)
thisJoinPoint.getTarget();
MethodSignature signature
=
(MethodSignature)
thisJoinPoint.getSignature();
String methodName =
signature.getName();
Class[] types
= signature.getParameterTypes();
Object[] args =
thisJoinPoint.getArgs();
receiver.invoke(passer.context, methodName, types, args);
}
}
Mark - you'll have to let us know how it works out. I'm curious what
concern(s) you're implementing for these distributed calls (security?
logging?).
Ron
"Volkmann, Mark"
<Mark.Volkmann@xxxxxxxxxxxxx> wrote:
Your first suggestion (using reflection) is excellent! I'll try
it.
I had considered your other two suggestions (piggybacking the extra
data onto a common parameter and making a priming call on a stateful session
bean) but couldn't use them because there is no common parameter in the
calls and the project I'm on isn't open to using stateful session
beans. I think those solutions are preferable though when they can be
used.
Mark,
I've been planning to implement something very similar. I think the
best way to achieve this goal with the current version of AspectJ is to
implement an extra "wrapper" method instead of the actual method.
I.e.,
1) define a marker interface (e.g., Recipient) with an
invokeOperation(...) method, and use declare parents to add this interface
to the EJB interface and to the EJB implementation class
2) write around advice in a client-side aspect that has access to the
context, casts the target into a Recipient, then calls
invokeOperation(...) on it. This will need to package up all the relevant
information (what method, what parameters, etc.)
3) write Recipient.invokeOperation(...) in a server-side aspect that
stuffs the required context away (e.g., in Recipient.context), then uses
reflection to invoke the original operation.
4) use advice to access the information wherever it is needed (in
your case, this could be written immediately after the reflective call in
invokeOperation)
This can be simplified if there is a common parameter to the calls.
In that case, an aspect can extend this parameter for use as a
carrier (by adding the extra context information when calling and then
unpacking it in around advice when receiving).
If you were willing to use a stateful session bean somewhere, you
could invoke a "handshake" operation (call Recipient.setContext(...)
before calling the object itself. This could be a single stateful "context
manager" bean that keeps track of context (which would be a more
complex implementation than making the recipient stateful).
I'd be interested in collaborating with you (and/or others) to build
reusable code to do this. It could be a great example code snippet to post
in Wes's recently proposed addition to the AspectJ site.
This kind of use case would greatly benefit from a macro facility
integrated with AspectJ. However, that would do a lot to make AspectJ more
complicated to use, so it's not clear that this is a feature worth adding.
In general, if there is an alternative to using compile-time macros it's
to use runtime reflection.
Ron
"Volkmann, Mark"
<Mark.Volkmann@xxxxxxxxxxxxx> wrote:
The reason I need to pass an extra parameter is that I'm
passing it to a stateless session bean running in a different VM.
My idea was to
1) Use AspectJ to add additional methods to my session
beans.
The additional methods would take the same
parameters as the exising ones and add a new parameter to carry
additional data. They would invoke the original method that they
wrap and then do something with the additional data.
2) Use AspectJ to change calls to the session bean
methods in client classes to pass the new parameter in addition to the
existing parameters.
Step 2 seems easy. Step 1 however seems impossible
with the current implementation of AspectJ.
What I'd love is for someone to tell me that step 1 is
not impossible or suggest an alternate approach that doesn't involve
making the session beans stateful.
> -----Original Message-----
> From: Wes Isberg [mailto:wes@xxxxxxxxxxxxxx]
> Sent: Thursday, July 10, 2003 12:34 PM
> To: aspectj-users@xxxxxxxxxxx
> Subject: Re: [aspectj-users] passing an extra parameter to
existing
> method s
>
>
>
AspectJ won't do that, but it's an interesting enough
> subcase of proxying that you might want to submit it
as
> a compiler RFE in the bug database so it
can be discussed
> with other 1.2 language
design issues.
>
>
But I'm less convinced that you want to add the methods
> as you describe, particularly since they d on't seem
to
> need to be visible to any clients other
than the aspect.
> Might you do the same with
advice in the aspect?
>
> -----
> aspect A {
>
> pointcut someCalls(Context
context) : {bind context}
> &&
execution({methods});
>
> Object around(Context context)
: someCalls(context) {
> Object
result = proceed();
> // do
something with context
> }
>
}
>
> -----
>
> If you need to do
things with the invoked instance, then
>
surface that as well:
>
> Object around(Context context,
MyClass targ) :
>
someCalls(context) && target(targ) {
> Object
result = proceed();
> // do
something with context and targ
> }
>
> If the "do something with ..." code differs
by type
> or method, then it seems like
you're back to specific
> method delegate,
which could be in the aspect or declared
> in
the target class.
>
> Wes
>
> Volkmann, Mark wrote:
>
> > I think what I want is a pattern-based
form of method
> introduction ...
> > unless there is another approach that would
provide this same thing.
> >
> > -----Original Message-----
> > From: Volkmann, Mark
> > Sent: Wednesday, July 09, 2003 2:11 PM
> > To: 'aspectj-users@xxxxxxxxxxx'
> > Subject: [aspectj-users] passing an extra parameter to
> existing methods
> >
> >
> >
> > Is there a way I
could do the following with AspectJ?
> >
> > I want to add methods to several
classes that wrap existing
> methods and
add
> > an additional parameter.
> > Then I want to use around advice to
make calls to the
> original methods go
to
> > the new methods and add the new
parameter.
> >
> > For example, the deposit method in my Account class
looks
> like this.
> >
> > public void
deposit(double amount) {
>
> balance += amount;
> > }
> >
> > I want to add the following.
> >
> > public void
deposit(Context context, double amount) {
>
> deposit(amount);
> > // Do something with the
context parameter here.
> > }
> >
> > Then
all calls to the original deposit method should go to
> the new one.
> >
> > I know how to do this for individual
methods, but I'm
> looking for a way
to
> > do this to many methods in the
Account class without having
> to write
the
> > code for each of them in my
aspect.
> >
>
>
> >
> >
>
**************************************************************
> **************
> >
*******
> > WARNING: All e-mail sent to
and from this address will be
> received
or
> > otherwise recorded by the A.G.
Edwards corporate e-mail
> system and
is
> > subject to archival, monitoring or
review by, and/or disclosure to,
> >
someone other than the recipient.
> >
>
**************************************************************
> **************
> >
********
> >
>
>
> >
>
>
_______________________________________________
> aspectj-users mailing list
>
aspectj-users@xxxxxxxxxxx
> http://dev.eclipse.org/mailman/listinfo/aspectj-users
>
***********************************************************************************
WARNING:
All e-mail sent to and from this address will be received
or
otherwise recorded by the A.G. Edwards corporate e-mail system and
is
subject to archival, monitoring or review by, and/or disclosure
to,
someone other than the
recipient.
************************************************************************************