alicjasalamon
alicjasalamon

Reputation: 4301

How to move methods to AspectJ class?

In a simple RMI program I managed to pass Context between two Threads. Now I need to move setting/reporting from Context to AspectJ class.

My problem is: How to move Context if I need to use it as an argument in greeting(Context)

HelloIF

public interface HelloIF extends Remote {
    String greeting(Context c) throws RemoteException;
}

Hello

public class Hello extends UnicastRemoteObject implements HelloIF {

    public Hello() throws RemoteException {
    }

    public String greeting(Context c) throws RemoteException {
        c.report();
        return "greeting";
    }
}

RMIServer

public class RMIServer {

    public static void main(String[] args) throws RemoteException, MalformedURLException {
        LocateRegistry.createRegistry(1099);
        HelloIF hello = new Hello();
        Naming.rebind("server.Hello", hello);
        System.out.println("server.RMI Server is ready.");
    }
}

RMIClient

public class RMIClient {
    public static void main(String[] args) throws RemoteException, MalformedURLException, NotBoundException {

        Context context = new Context("request1", Thread.currentThread().getName()+System.currentTimeMillis());

        Registry registry = LocateRegistry.getRegistry("localhost");
        HelloIF hello = (HelloIF) registry.lookup("server.Hello");
        System.out.println(hello.greeting(context));

        context.report();

    }
}

Context

public class Context implements Serializable
{
    private String requestType;
    private String distributedThreadName;

    public Context(String requestType, String distributedThreadName)
    {
        this.requestType = requestType;
        this.distributedThreadName = distributedThreadName;
    }

    (...)

    public void report() {
        System.out.println("thread : "
                + Thread.currentThread().getName() + " "
                + Thread.currentThread().getId());

        System.out.println("context : "
                + this.getDistributedThreadName() + " " + this.getRequestType());
    }
}

and finally an empty AspectJ class

@Aspect
public class ReportingAspect {
    @Before("call(void main(..))")
    public void beforeReportClient(JoinPoint joinPoint) throws Throwable {
    }

    @After("call(void main(..))")
    public void afterReportClient(JoinPoint joinPoint) throws Throwable {
    }

    @Before("call(String greeting(..))")
    public void beforeReportGreeting(JoinPoint joinPoint) throws Throwable {
    }

    @After("call(String greeting(..))")
    public void afterReportGreeting(JoinPoint joinPoint) throws Throwable {
    }

}

How can I move from Hello and RMIClient Context() constructor and c/context.report()s to ReportingAspect?

Upvotes: 0

Views: 208

Answers (1)

slim
slim

Reputation: 41271

You can pass the arguments to a function, and the underlying object, to Advice, thus:

@Before("execution(* greeting(..)) && target(target) && " +
        "args(context)")
public void beforeReportGreeting(HelloIF target, Context context) {
       context.doSomething();
       target.doSomething();
}

Study the AspectJ annotation documentation for the full details. It can be done for all the advice types.

Edit Reading the question in more details, it sounds as if you want to make the Context object something constructed and controlled by the aspect, while still passing it as an argument to Hello.greeting().

That's not something that makes sense. Your underlying system ought to work OK without any AOP going on. So if the Context object is part of that underlying domain, then it's not a good idea for the Aspect to be in charge of its construction and management.

If the Context is only relevant to the Aspect, then you would remove all reference to the context from the domain classes (so greeting() would take no parameters) and build the Context object(s) in the Aspect.

Upvotes: 1

Related Questions