Thinking about plugins in a Java EE webapp, I wanted a way to have an interface that my code would call to notify listeners of events.
As a POC, I created an annotation and interface to implement this pattern.
First, we create an interface for a simple Java EE plugin. This is a simple POJO with one event method:
public interface IAfterComplete {
public void afterComplete(String someValue);
}
We will call the afterComplete() method when the action is complete. For simplicity it takes one String argument.
Next, we create the Java annotation. This lets us determine which beans implement our interface at runtime:
Retention(RUNTIME)
@Target(TYPE)
@Qualifier
public @interface AfterComplete {
}
If we create the EJB we want to discover and annotate it with AfterComplete, we will see how easily we can locate it in the web application context.
Now, we create the plugin implementation. The implmentation is a simple Stateles EJB with our custom annotation implementing our custom interface:
@AfterComplete
@Stateless
public class AfterCompletePrinter implements IAfterComplete {
public void afterComplete(String someValue) {
System.out.println("After complete printer: " + someValue);
}
We declare it stateless so it will get created by our container and put into the applicaton’s Java EE context.
Now, in our Java EE app, we can locate all beans with our @AfterComplete
annotation and call the plugin’s afterComplete
method:
Set<Bean<?>> beans = beanManager
.getBeans(Object.class, new AnnotationLiteral<AfterComplete>() {
});
for (Bean<?> bean : beans) {
response.getWriter().print(bean.getBeanClass());
IAfterComplete iac = (IAfterComplete) beanManager.getReference(bean, IAfterComplete.class, beanManager.createCreationalContext(bean));
iac.afterComplete("After complete called on " + iac);
}
We can use this method in a Servlet, REST endpoint, or whatever else we want to create callbacks for different methods.
There is an example Servlet and 2 beans that have a discover-able annotation at https://github.com/mikebski/ejb-custom-annotations that is a Maven project that can be used for a demonstration.
Check it out and run mvn package
to generate a war file, then deploy it and go to:
http://localhost:8080/ejb-custom-annotations-1.0/
The output should be:
class net.mikeski.ejb_annotations.AfterCompletePrinter class net.mikeski.ejb_annotations.AfterCompleteErrPrinter
and your console should have 2 log messages like this:
18:45:51,937 INFO stdout After complete printer: After complete called on Proxy for view class: net.mikeski.ejb_annotations.IAfterComplete of EJB: AfterCompletePrinter
18:45:51,939 ERROR stderr After complete called on Proxy for view class: net.mikeski.ejb_annotations.IAfterComplete of EJB: AfterCompleteErrPrinter