The first part covered adapting and packaging extensible Java EE applications.
Introducing Plug-ins
This part will demonstrate how Java EE application can be extended via plug-ins.
To do so we will have to define Service provider interface(s) (SPI).
[java]
public interface CorePlugin {
public String getName();
…
}
[/java]
The applications SPI should be provided in a separate JAR decoupling plug-ins from the core application and avoid cyclic dependency issues (see the previous post for more details).
Implementing a Plugin
It is a simple matter of implementing the defined SPI…
[java]
public class MyPlugin implements CorePlugin {
public String getName() {
…
}
…
}
[/java]
…and packaging it into a bean-archive (see CDI 1.1/1.2 Im-/Ex-plicit bean archives).
Plugin Discovery
Plugin discovery can be implemented using CDI Instance. It is important to note that CDI Instance was not intended for this purpose. As explained by Romain Manni-Bucau “CDI and Instance: 3 pitfalls you need to know”, there are a couple of caveats that have to be taken care of.
- Slow – Instance forces the container to resolve the beans for each invocation.
- Can Leak – dependent scoped beans will get created per invocation.
As suggested, both problems can be resolved by caching the resolved instances.
[java]
@javax.ejb.Startup
@javax.ejb.Singleton
public class Plugins {
private final Set<Plugin> plugins = new HashSet<>();
@Inject
private Instance<Plugin> pluginInstances;
@PostConstruct
public void postConstruct() {
for (Plugin plugin : pluginInstances) {
plugins.add(plugin);
}
}
@Lock(LockType.READ)
public Set<Plugin> getAvailablePlugins() {
return Collections.unmodifiableSet(plugins);
}
}
[/java]
In the example above the plugins are discovered on start-up and cached in a @Singleton EJB (not JSR-330 @javax.inject.Singleton).
Packaging
The plugins have to be included as dependency of the customized application. This can be achieved either by using maven-overlay in case of a WAR…
[text gutter=”false”]
war
├── …
└── WEB-INF
| └── …
| └── lib
| └── core-spi.jar
| └── custom-module-a.jar
| └── custom-module-b.jar
| └── …
└── …
[/text]
…or building a customized EAR file to provide plugins to EJB-JAR’s.
[text gutter=”false”]
ear
├── lib
| └── core-spi.jar
| └── custom-module-a.jar
| └── custom-module-b.jar
| └── …
└── core-ejb-jar
└── …
[/text]
Packaging is explained in more detail the previous post.