Spring AOP - How to get annotation of parent(caller) method - aop

#Before(value="#annotation(com.aspect.Loggable)",argNames="taskId")
public void logEmail(JoinPoint joinPoint) {
System.out.println("#Before is running!");
System.out.println("hijacked : " + joinPoint.getSignature().getName());
System.out.println("******");
}
i have a pointCut on method sendEmail() with custom annotation.
This method sendEmail() is called from differnt location in our application .
Like we call sendEmail from paymentApproved () method of paymentManager when payment is approved.
We call sendEmail from taskComplete() method of taskManger when task is completed.
i have to find out the event for which sendEmail is triggered.
I applied custom annotation #EVENT("PAYMENT") on paymentApproved () of paymentManager and #EVENT("TASK") on taskComplete() method of taskManger.
How can i get the value of #EVENT in logEmail(JoinPoint joinPoint) aspect.

Scaffolding:
Sorry, I do not like all-caps class names and I also used my own package names as an example because my template already generates them.
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Loggable {}
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Event {
String value();
}
Driver application:
This is pure Java because I am not a Spring user. Just imagine it is one or more #Components.
Please also note that in one case sendEmail() is called from a method not annotated by #Event. This should not trigger the aspect, only the two calls from the annotated methods.
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
Application application = new Application();
application.doSomething();
application.paymentApproved();
application.taskComplete();
}
public void doSomething() {
sendEmail();
}
#Event("paymentApproved")
public void paymentApproved() {
sendEmail();
}
#Event("taskComplete")
public void taskComplete() {
sendEmail();
}
#Loggable
public void sendEmail() {}
}
Aspect:
Your pointcut wants to express: Catch methods annotated with #Loggable within the control flow of methods annotated by #Event. Control flow can be expressed by cflow() or cflowbelow() pointcuts.
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import de.scrum_master.app.Event;
#Aspect
public class LogAspect {
#Before(
"#annotation(de.scrum_master.app.Loggable) &&" +
"execution(* *(..)) &&" + // only needed for AspectJ, not for Spring AOP
"cflow(#annotation(event))"
)
public void logEmail(JoinPoint thisJoinPoint, Event event) {
System.out.println(thisJoinPoint + " -> " + event);
}
}
Console log:
execution(void de.scrum_master.app.Application.sendEmail()) -> #de.scrum_master.app.Event(value=paymentApproved)
execution(void de.scrum_master.app.Application.sendEmail()) -> #de.scrum_master.app.Event(value=taskComplete)
Update: If you were using full AspectJ (e.g. via load-time weaving) instead of Spring AOP, you just could have used a call() pointcut and from there get the enclosing joinpoint's static information. Then the #Event annotation would not have been necessary. But Spring AOP is just "AOP lite" and does not support call().

You can access to the annotation receiving it as a parameter. Something like this:
#Before(value="#annotation(EVENT)",argNames="taskId")
public void logEmail(JoinPoint joinPoint, Event event) {
// do what you need with event. For example, if the field is called value you can do this:
if ("PAYMENT".equals(event.value())) {
// do sth
}
System.out.println("#Before is running!");
System.out.println("hijacked : " + joinPoint.getSignature().getName());
System.out.println("******");
}

Related

How to define pointcut for class initialization

I'm a newbie to AspectJ, and trying to understand joinpoint model
Now i have class like this
public class Account {
private static Map<String, PaymentMethod> supportedPayments = new HashMap<>();
static {
supportedPayments.add("COD", new CodPaymentMethod());
supportedPayments.add("ATM", new ATMPaymentMethod());
}
}
as i read from AspectJ In Action, there is a way to define pointcut when class is intialization, but i could not find syntax.
Anyone help me?
This one does not work:
#Pointcut("initialization(com.jas.aop.bean.Payment"))
it say
ERROR] Syntax error on token "initialization(com.jas.aop.bean.Payment)", "name pattern" expected
/Users/admin/eclipse-workspace/aop/src/main/java/com/jas/aop/aspect/ClassInitializationAspect.java:9
#Pointcut("initialization(com.jas.aop.bean.Payment)")
Your pointcut has several problems:
There is a missing closing parenthesis ).
initialization intercepts constructors (i.e. object initialisation) rather than static class initialisation, which is not what you want and also would require a constructor pattern, not a class name pattern.
If your aspect does not happen to be in the exact same package as the target class, you must use a fully qualified class name such as my.package.Account in order to make the pointcut match.
By the way, your code snippets are just pseudo code because a hash map does not have an add method, rather a put method. The sample class does not even compile. Don't just invent code when posting questions here. Make life easier for the people trying to help you.
Now here is an MCVE, something I always suggest you to specify in your question in order to help people reproduce your situation. I did it for you this time, this was your free shot. Next time, please do it yourself.
Dependency classes used by the main class:
package de.scrum_master.app;
public interface PaymentMethod {}
package de.scrum_master.app;
public class ATMPaymentMethod implements PaymentMethod {}
package de.scrum_master.app;
public class CodPaymentMethod implements PaymentMethod {}
Target class with driver application:
package de.scrum_master.app;
import java.util.HashMap;
import java.util.Map;
public class Account {
private static Map<String, PaymentMethod> supportedPayments = new HashMap<>();
static {
System.out.println("Static initialiser block");
supportedPayments.put("COD", new CodPaymentMethod());
supportedPayments.put("ATM", new ATMPaymentMethod());
}
public Account() {
System.out.println("Creating account");
}
public void doSomething() {
System.out.println("Doing something");
}
public static void main(String[] args) {
new Account().doSomething();
}
}
Aspect:
The aspect shows both initialization and staticinitialization in order to show the difference in both syntax and functionality. You can find all of this explained with examples in the AspectJ manual, which I warmly recommend you to read.
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class AccountAspect {
#Before("initialization(de.scrum_master.app.Account.new(..))")
public void interceptObjectInitialisation(JoinPoint joinPoint) {
System.out.println(joinPoint);
}
#Before("staticinitialization(de.scrum_master.app.Account)")
public void interceptClassInitialisation(JoinPoint joinPoint) {
System.out.println(joinPoint);
}
}
Console log:
staticinitialization(de.scrum_master.app.Account.<clinit>)
Static initialiser block
initialization(de.scrum_master.app.Account())
Creating account
Doing something

Intercept Error constructor with bytebuddy

For some reason I can't work out yet, my agent doesn't intercept java LinkageError instances.
Agent code:
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.instrument.Instrumentation;
public class MyAgent {
public static void premain(String arguments, Instrumentation instrumentation) {
new AgentBuilder.Default()
.type(ElementMatchers.isSubTypeOf(LinkageError.class))
.transform((builder, type, classLoader, module) ->
builder.constructor(ElementMatchers.isDefaultConstructor())
.intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.to(MyInterceptor.class)))
).installOn(instrumentation);
}
}
Interceptor code:
public class MyInterceptor {
#RuntimeType
public static void intercept(#Origin Constructor<?> constructor) throws Exception {
System.out.println("Intercepted: " + constructor.getName());
}
}
Test code:
public static void main(String[] args) {
new NoClassDefFoundError("should be intercepted!!!").toString();
new Foo("oh").toString();
}
What is puzzling is that replacing ElementMatchers.isSubTypeOf(LinkageError.class) with ElementMatchers.nameContains("Foo") gives the expected result and Foo constructor is intercepted.
The NoClassDefFoundError is loaded by the bootstrap loader. It willnot be able to see your interceptor class which is why it is never triggered.
Try using the Advice class (as a visitor) to add bytecode to matched classes which should resolve this problem.

How can I find all singletons on Guice which implement a specific type?

Imagine I have a type Disposable which some classes implement:
class FactoryImpl implements Disposable {}
I can bind this class as a singleton:
bind(Factory.class)
.to(FactoryImpl.class)
.in(Singleton.class);
or as an eager singleton:
bind(Factory.class)
.to(FactoryImpl.class)
.asEagerSingleton();
Note that the implementation has the type, not the interface.
How can I find all singletons which Guice has actually created and which implement the type Disposable?
Note that I don't want to blindly call get() in the provider to avoid to create stuff which I don't need (especially since I'm destroying singletons, so creating new ones might cause problems).
This is the opposite of questions like How can I get all singleton instances from a Guice Injector? which only work then the interface contains the keys that you need.
[EDIT] This is how far I got. Is this code correct?
First, I need my interface.
public interface Disposable {
public void dispose();
}
The magic happens here:
import java.util.Collections;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.beust.jcommander.internal.Lists;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.InjectionListener;
import com.google.inject.spi.TypeEncounter;
import com.google.inject.spi.TypeListener;
import com.google.inject.util.Modules;
/** Support for disposable beans. */
#Singleton
public class DisposableListener implements InjectionListener<Object> {
private static final Logger log = LoggerFactory.getLogger(DisposableListener.class);
/** Use this method to create the injector */
public static Module createModule(Module ...modules) {
/* Create a new module with ourself at the start. That way, our listeners will see all bindings. */
List<Module> list = Lists.newArrayList(new DisposingModule());
Collections.addAll(list, modules);
return Modules.combine(list);
}
/** To dispose all disposables, call this method.
*
* <p>Good places to call this is at the end of {#code main()},
* in an destroy listener of a {#link javax.servlet.ServletContext}, or after a test.
*/
public static void dispose(Injector injector) {
injector.getInstance(DisposableListener.class).disposeAll();
}
/** Everything that is disposable */
private List<Disposable> beans = Lists.newArrayList();
private void disposeAll() {
log.debug("Disposing {} beans", beans.size());
for(Disposable bean: beans) {
try {
bean.dispose();
} catch(Exception e) {
log.warn("Error disposing {}", bean, e);
}
}
}
#Override
public void afterInjection(Object injectee) {
if(injectee instanceof Disposable) {
log.debug("Noticed disposable bean {}", injectee);
beans.add((Disposable) injectee);
}
}
/** Module which creates the {#link DisposableListener} for the injector and sets everything up. */
private static class DisposingModule extends AbstractModule {
#Override
protected void configure() {
DisposableListener disposableListener = new DisposableListener();
/* Attach a type listener to Guice which will add disposableListener to all types which extend Disposable */
bindListener(TypeMatchers.subclassesOf(Disposable.class), new TypeListener() {
#Override
public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
Class<?> clazz = type.getRawType();
log.debug("Found disposable: {}", clazz);
encounter.register(disposableListener);
}
});
/* Add the listener instance to the module, so we can get it later */
bind(DisposableListener.class)
.toInstance(disposableListener);
}
}
}
The code wraps the other modules and makes sure the DisposableListener is installed in the injector early on. Then it listens for new instances which are created and collects them in a list.
The code probably should check that these are all singletons but I don't know how to do that.
Here are the unit tests:
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.beust.jcommander.internal.Lists;
import com.google.common.base.Joiner;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Singleton;
public class DisposableListenerTest {
private static List<String> events = Lists.newArrayList();
#Before
public void clearEvents() {
events.clear();
}
#Test
public void testEagerNoGetInstance() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestEagerSingleton()));
// No call to getInstance()
DisposableListener.dispose(injector);
assertEvents("Foo created", "Foo disposed");
}
#Test
public void testEagerGetInstance() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestEagerSingleton()));
Foo inst1 = injector.getInstance(Foo.class);
Foo inst2 = injector.getInstance(Foo.class);
DisposableListener.dispose(injector);
assertSame(inst1, inst2); // validate singleton
assertEvents("Foo created", "Foo disposed");
}
#Test
public void testLazyNoGetInstance() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestLazySingleton()));
// No call to getInstance()
DisposableListener.dispose(injector);
assertEvents();
}
#Test
public void testLazyGetInstance() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestLazySingleton()));
Foo inst1 = injector.getInstance(Foo.class);
Foo inst2 = injector.getInstance(Foo.class);
DisposableListener.dispose(injector);
assertSame(inst1, inst2); // validate singleton
assertEvents("Foo created", "Foo disposed");
}
#Test
public void testAnnotation() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestLazySingleton()));
FooWithAnnotation inst1 = injector.getInstance(FooWithAnnotation.class);
FooWithAnnotation inst2 = injector.getInstance(FooWithAnnotation.class);
DisposableListener.dispose(injector);
assertSame(inst1, inst2); // validate singleton
assertEvents("FooWithAnnotation created", "FooWithAnnotation disposed");
}
private void assertEvents(String...expectedEvents) {
Joiner joiner = Joiner.on('\n');
String expected = joiner.join(expectedEvents);
String actual = joiner.join(events);
assertEquals(expected, actual);
}
public static class Foo implements Disposable {
public Foo() {
events.add("Foo created");
}
#Override
public void dispose() {
events.add("Foo disposed");
}
}
#Singleton
public static class FooWithAnnotation implements Disposable {
public FooWithAnnotation() {
events.add("FooWithAnnotation created");
}
#Override
public void dispose() {
events.add("FooWithAnnotation disposed");
}
}
public static class TestLazySingleton extends AbstractModule {
#Override
protected void configure() {
bind(Foo.class).in(Singleton.class);
}
}
public static class TestEagerSingleton extends AbstractModule {
#Override
protected void configure() {
bind(Foo.class).asEagerSingleton();
}
}
// TODO test when bean isn't a singleton
}
Don't re-invent scopes
First off, manually "disposing" of singleton Guice bindings is somewhat putting the cart before the horse. Instead of binding objects as singletons and then needing to regularly clean them up, you should use a more appropriate scope (or define your own) so that these objects have natural life cycles for the duration of time that they're expected to exist, such as for a single request or test.
This is evidenced by the documentation on DisposableListener.dispose():
Good places to call this is at the end of main(), in an destroy listener of a ServletContext, or after a test
None of those are place you should need something like this:
When .main() terminates the JVM will soon terminate too (and presumably your injector will go out of scope) so there's generally no need to do any such cleanup before letting the binary terminate.
Similarly when a ServletContext has been destroyed you're generally just about to terminate the JVM, so just let it exit normally.
In tests you should normally be constructing isolated injectors for each test, thereby avoiding any cross-test pollution. When the test ends the injector and all its bindings goes out of scope, and there should be nothing to clean up.
Manage resources separately from Guice
Of course, you could be creating objects that need to be cleaned up, such as an AutoCloseable instance, but that shouldn't be the responsibility of Guice. Generally the .getInstance() call site that obtains the closeable resource should be responsible for cleaning it up. Alternatively the module(s) could be responsible for creating and managing these resources. Then you construct the injector inside a try-with-resources block that manages the lifecycle of the resources module(s).
If those options aren't sufficient and you really need more powerful life cycle semantics use a proper life cycle framework such as Guava's ServiceManager, rather than co-opting Guice into one.
That said, having objects that require cleanup in Guice is itself generally not a good idea. Consider instead binding a wrapper type that allows the caller to open (and close) resources as needed, rather than binding a long-lived stateful resource object directly.
Prefer explicit bindings over Guice listeners
If you really, really need to collect several unrelated objects bound in a Guice injector, do so explicitly at .configure() time, rather than implicitly via introspection. Using a Multibinder allows your modules to explicitly declare which objects need to be disposed of, by binding them to a Multibinder<Disposable> instance which aggregates them all. Then your cleanup step is simply:
for (Disposable resource : injector.getInstance(new Key<Set<Disposable>>() {}) {
resource.dispose();
}
This avoids the "magic" of a listener that silently comes in and cleans up after you, instead allowing module authors to determine how best to handle the resources they bind, and optionally taking advantage of this cleanup functionality if necessary.

How do I load and store global variables in Jersey/Glassfish

I am creating a RESTful Web Service that wraps an antiquated vendor API. Some external configuration will be required and will be stored on the server either in a file or rdbms. I'm using Jersey 1.11.1 in Glassfish 3.1.2. This configuration data is all in String key/value format.
My first question is this - where can I store global/instance variables in Jersey so that they will be persisted between requests and available to all resources? If this was a pure Servlet application I would use the ServletContext to accomplish this.
The second part to the question is how can I load my configuration once the Jersey server has loaded? Again, my Servlet analogy would be to find the equivalent to the init() method.
#Singleton #Startup EJB matches your requirements.
#Singleton
#Startup // initialize at deployment time instead of first invocation
public class VendorConfiguration {
#PostConstruct
void loadConfiguration() {
// do the startup initialization here
}
#Lock(LockType.READ) // To allow multiple threads to invoke this method
// simultaneusly
public String getValue(String key) {
}
}
#Path('/resource')
#Stateless
public class TheResource {
#EJB
VendorConfiguration configuration;
// ...
}
EDIT: Added annotation as per Graham's comment
You can use a listener for init the variables and set to the context as attribute before the web application start, something like the following:
package org.paulvargas.shared;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class LoadConfigurationListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
// read file or rdbms
...
ServletContext context = sce.getServletContext();
// set attributes
...
}
public void contextDestroyed(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
// remove attributes
...
}
}
This listener is configured in the web.xml.
<listener>
<listener-class>org.paulvargas.shared.LoadConfigurationListener</listener-class>
</listener>
You can use the #Context annotation for inject the ServletContext and retrieving the attribute.
package org.paulvargas.example.helloworld;
import java.util.*;
import javax.servlet.ServletContext;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
#Path("/world")
public class HelloWorld {
#Context
private ServletContext context;
#GET
#Produces("text/plain; charset=UTF-8")
public String getGreeting() {
// get attributes
String someVar = (String) context.getAttribute("someName")
return someVar + " says hello!";
}
}

How to access the SVNClientAdapter that subclipse is using during runtime?

I am using the Subclipse API and I would like to implement the ISVNNotifyListener so that I can find out about the subclipse events as they happen during runtime. I believe I need to add (subscribe) my instance of the notify listener to the set of listeners that the Client Adapter will notify, but I am at a loss for how to get access to the Client Adapter that is being used by Subclipse at runtime. Is there a way to access it so that I can add my listener to the set?
Sorry, but unfortunately Subclipse has not been coded in such a way to provide access to the internals. Subclipse constructs a new ISVNClientAdapter object for each API call it needs to make into Subversion and it adds its ISVNNotifyListener to this object on the fly as needed. So there is no way for you to interject your own listener.
Perhaps you could write a class that implements IConsoleListener and have it act as a proxy for the Subclipse class. You could then call SVNProviderPlugin.getConsoleListener to get the current console listener and store a reference to it in your class. Then call SVNProviderPlugin.setConsoleListener to replace the class held in Subclipse with your class. As the events are fired in your class, you could just forward them on to the Subclipse class and do whatever you want with the events in your code. Something like this:
import java.io.File;
import org.tigris.subversion.subclipse.core.client.IConsoleListener;
import org.tigris.subversion.svnclientadapter.SVNNodeKind;
public class ProxyListener implements IConsoleListener {
private IConsoleListener subclipseListener;
public ProxyListener(IConsoleListener subclipseListener) {
super();
this.subclipseListener = subclipseListener;
}
public void setCommand(int command) {
subclipseListener.setCommand(command);
// TODO add your code
}
public void logCommandLine(String commandLine) {
subclipseListener.logCommandLine(commandLine);
// TODO add your code
}
public void logMessage(String message) {
subclipseListener.logMessage(message);
// TODO add your code
}
public void logError(String message) {
subclipseListener.logError(message);
// TODO add your code
}
public void logRevision(long revision, String path) {
subclipseListener.logRevision(revision , path);
// TODO add your code
}
public void logCompleted(String message) {
subclipseListener.logCompleted(message);
// TODO add your code
}
public void onNotify(File path, SVNNodeKind kind) {
subclipseListener.onNotify(path, kind);
// TODO add your code
}
}