Tutorial

Tips for Writing Pluggable Java EE Applications

JasonLee
plugs

From JAX Magazine: Jason Lee, Senior Member Technical Staff at Oracle, explains how Java EE makes extensible applications easier than you think.

Chances are good, if you’ve been writing complex systems long
enough, that you’ve had either the need or desire to implement some
sort of plug-in support for your system. Unfortunately, it can be a
daunting task that is often left undone. The existence of plug-in
systems in the various major IDEs and continuous integration
servers such as Hudson show that it is possible.

However, these systems are usually either overly complex
or tailored to their specific problem domain. The lack of an
existing off-the-shelf solution need not cause you to abandon your
efforts. As it turns out, Java EE delivers technologies, such as
JSF, CDI, and JAX-RS, that make it surprisingly simple.

In this article, we’ll take a brief look at how you might
apply these technologies to build your own lightweight plug-in
system, with a minimum of external dependencies.

Step 1: Loading the Plug-ins

Perhaps the first question one should ask is: “How do I load the
plug-in data?” After all, if you can’t load the plug-ins, who cares
if you can write them? There are many, many options, of course, but
we’ll take a look at three, to keep things simple: repackaging,
manual class loading, and OSGi.

Repackaging

Perhaps the simplest, safest approach is simply to repackage the
application. This is exactly what it sounds like: you take the
original application archive, and .war, for example, and
add the plug-in jars. This avoids some of the potential problems
we’ll see in other approaches, as well as pushing the heavy lifting
on to your container. You can do this through some sort of Ant- or
Maven-based system, or a simple shell script.

#!/bin/bash
DIST=$1
if [ "$DIST" == "" ] ; then
    echo "You must specify the distribution .war"
    exit 1
fi
BASE=`echo $DIST | sed -e 's/.war//'`
rm -rf work
mkdir work
cd work
jar xf ../$DIST
cp ../plugins/*jar WEB-INF/lib
jar cf ../$BASE-repackaged.war *
cd ..
rm -rf work

The upside to this is that you maintain access to all of the
technologies provided by your container: EJB, JMS, etc. The
downside is that deployment/upgrade takes a bit more work, and
means that if you forget to run this process, you’ve suddenly lost
all of your plug-ins. It is not a major concern, but certainly
something to be aware of.

Manual ClassLoading

From a technical perspective, this is my favourite approach,
simply because of the pure hardcode geekiness of it. In a nutshell,
we read the bytecode from the jar file(s), and
load it into the context ClassLoader. Fraught with
peril, sure, but fun nonetheless.

As a proof of concept for this approach, I have a small project
called Plummer, so called
because it provides some of the plumbing for the
plug-in system. Before we dive into what Plummer provides, we
should note that the plug-in approach we’ll look at is based very
heavily on CDI, a new specification in Java EE 6. What we need to
do in this part of plug-in equation is to provide these plug-in
classes to the CDI runtime. In Plummer, this happens in
the PluginLoader class.

public class PluginLoader implements Extension {
    protected static final String SERVICES_NAME =
    "com.steeplesoft.plummer.finders";
    private static final Logger logger =
    Logger.getLogger(PluginLoader.class.getName());
    private static List<PluginFinder> pluginFinders;
    List<Class<? extends PluginFinder>> pluginFinderClasses;




    public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd,
          BeanManager beanManager) {
        for (PluginFinder pluginFinder : getPluginFinders()) {
            try {
                for (Class<?> clazz : pluginFinder.getClasses()) {
                    final AnnotatedType<?> annotatedType =
        beanManager.createAnnotatedType(clazz);
                    logger.log(Level.INFO, "Adding AnnotatedType for {0}",
        annotatedType.toString());
                    bbd.addAnnotatedType(annotatedType);
                }
            } catch (Exception ex) {
                Logger.getLogger(PluginLoader.class.getName())
      .log(Level.SEVERE, null, ex);
            }
        }
    }
    // ... 
}

Here we see CDI show up for the first time. What we have here is
a CDI portable extension (for more information, see the
CDI RI (Weld) documentation
). We also see another CDI concept
that we’ll revisit in the next section, Events. Since this is a
portable extension, the class is loaded by the runtime very early
in the application startup process. In this case,
our Extension observes
the BeforeBeanDiscovery event, as you can
see in the aptly-named method. This method asks the system for a
list of the PluginFinder instances
configured in the system (I got a little over-excited and added in
the ability to have more than one, just in case). It then asks
each PluginFinder for a list of the
classes it found. For each class, it creates
an AnnotatedType, which it then adds to
the BeforeBeanDiscovery instance. When
this method exits, the CDI runtime will, eventually, scan our
plug-in classes for CDI annotations, and, voila! Our plug-ins are
registered with the
system.

The bytecode loading is handled, in this case,
by FilesystemPluginFinder. This class iterates over a
list of jar files found in, by default, ~/.plugins.
For each .class file in each jar,
the bytes are read and the class is defined in
the ContextClassLoader. We’ll not show how that
happens here, but I will say that it seems to work pretty well.
I’ve not found any issues with it so far, but I also have not been
able to drive it very hard yet.

When using this approach, it’s important to note some of its
restrictions.
Given how and when the
classes are loaded, certain Java EE technologies are
likely not available. Namely, this
includes EJB, JMS, etc., as the related containers are unable to
scan the classes for annotations. I have not tested JPA support
yet. CDI seems to be completely and well supported.

OSGi

It seems that any discussion of plug-ins (or modules, if you
will) would be incomplete without talking about OSGi. As I started
thinking about this topic, Web Application Bundles came to mind
pretty quickly. I will admit that I am far from an OSGi expert, but
it seems that WABs aren’t quite what we want. In fact, they seem to
be designed to solve different issues. WABs and Plummer are not
mutually exclusive, however. In fact, I have very young, incomplete
code in Plummer to allow a system to deliver plug-ins as OSGi
bundles.

Plummer assists in this by providing,
in plummer-api,
the PluginActivator class. This bundle activator
runs, of course, when the bundle is started. You can look at the
code for details, but it passes the Bundle to
Plummer’s PluginTracker, which
calls Bundle.findEntries() to find the class
files in the bundle. The information is stored, and ultimately
passed to the PluginLoader mentioned above.

In terms of drawbacks, this one has the most severe of the
approaches we’ve discussed. In addition to having the same
limitations (most likely) as the manual class loading approach, it
has one even more significant one: It does not currently work. I
think the theory/approach is sound, but I have not had the chance
to finish and test the code to date. For those interested, you know
what to do.

Step 2: Application Design

Now that we’ve answered any questions anyone would have –?ever
–?about plug-in loading, let’s spend some time on the more
interesting part: How do I design the plug-ins? I would like to
note that it may not be possible (or, at the very least, extremely
difficult) to write a complete, generally useful plug-in system
that works across applications and problem domains. If someone were
determined enough to prove me wrong and actually did just that, I’d
be willing to bet that it would be difficult to use, heavy, etc. If
this person were truly determined, gifted, etc. to prove me wrong
yet again, well… good for him.) For the rest of us (or, in this
case, just me), Java EE makes this so easy that you really don’t
need any extra frameworks. To attempt to prove my assertion, we’ll
take a look at three Java EE technologies: JSF, CDI, and
JAX-RS.

View Extensibility

Let’s start by taking a look at view extensibility, as, after
all, even if you have the greatest plug-in system in the world, if
it can’t affect the view, then it’s not worth much. To demonstrate
this technique, we’re going to use JavaServer Faces, as it is the
Java EE standard for web applications. You may prefer another
framework, such as Spring MVC, Wicket, or GWT, or you may even be
using desktop technologies such as Swing, SWT, or JavaFX to build
views for your Java EE application. The technique here should work
the same regardless of framework, more or less. You’ll just have to
determine how to integrate it into your technology of choice.

For a plug-in to add content to the view, it will have to
provide what we will call viewfragments.
These fragments are exactly what they sound like, small pieces of
UI widgets that are added at specific points in
the view. These fragments are categorized, by the plug-in, into
types, as defined by the consuming application. This means that the
app might declare the
types tabtreeNode,
and widget. A plug-in, then, might add a tab to a
configuration page, a treeNode to the navigation
system, and a recent tweets widget to the sidebar. As we’ll see,
how complex or simple the categorization/differentiation exposed by
the application is is completely up to you as the application
author/architect.

Having defined the terms, then, how might one implement this?
First off, let’s take a look
at ViewFragment.java in
the plummer-api module.

public @interface ViewFragment {
    String type();
    String parent() default "";
}

This simple interface
defines type and parent properties.
A plug-in author would use it like this:

public class SamplePlugin implements Plugin {
@ViewFragment(type="foo")
public static String sample1 = "sample1.xhtml";
@Override
public int getPriority() {
return 500;
}}

There are several things to note here. First, let’s look at the
annotation. Here, we are defining
ViewFragment of type foo. It is
attached to a public static final String, whose value
is sample.xhtml. When the system processes this
annotation, it will store the
value sample.xhtml in a Map, keyed
by the value foo. When the view asks for view
fragments of type foo, this piece of markup will be
included. That file, by the way, is a simple JSF 2 Facelets file
(listing 5).

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h1>Plugin Fragment</h1>
This text comes from a fragment. Shiny!
</ui:fragment>

Very simple. The question that should come to mind now is, “How
does the system find this annotation, and then how do I tell the
system to insert this into my view?” The answer to the first half
of that question is the Plugin interface. Those
interested in the nitty gritty can read the code
(PluginService.java in plummer-kernel),
but for those not that curious, CDI again saves
the day. In a nutshell, we ask CDI for all the beans that
implement Plugin, scan them for fields annotated
with ViewFragment, and store the metadata. On the
view side, we use the pl:viewFragment custom
component that Plummer offers:

 <pl:viewFragment type="foo"/>

The system does the rest. What you put in your view fragments is
completely up to you. We’ve put everything from simple markup to
`h:form`s with no known issues. One note with regard to resources:
since the resources are stored in JARs and not in the application’s
document root, you will need to use JSF 2’s resource mechanism to
reference images, javascript, CSS, etc.:

<h:graphicImage value="#{resource['myImage.JPG']}" height="200"
title="Here's a picture of something really cool!"/>

You can see a complete example of this
in plummer-sample2. One final note before we
move on: The code in Plummer
is mostly standards-compliant, but some
Mojarra-specific classes needed to be used to get access to
the FaceletFactory needed to insert the
view fragments into the component tree. MyFaces users can still use
Plummer, but someone will need to implement the MyFaces-specific
code to reproduce this functionality. Maybe someday the spec could
expose this kind of functionality, but, for now, we have to address
this on a per-implementation
basis.

Application Extensibility

The real work, of course, is done at lower levels. Here we’ll
see just how simple Java EE makes things. Specifically, we’ll look
at two parts of CDI, events, and what we’ll simply refer to as
programmatic bean lookup.

CDI events is, conceptually, just a simple pub/sub system. One
part of the system fires, or publishes, events, and another
observes (subscribes). This makes it very easy to loosely couple
parts of the system: the core of your application need not worry
about what, if anything handles, the event. It also easily allows
multiple recipients to respond to the event fired. Again, the
system doesn’t care. In Ron Popeil style, you just “set it and forget
it”
.

So what does this look like in practice? To demonstrate that in
a meaningful way, we need a sample application, so we’ll write a
very simple blogging system. If you’ve ever interacted with a blog,
either as an author or a reader, you’ve likely seen the option by
which a user can subscribe and get notifications of new posts.
Let’s implement that. First up, we’ll need a way to create blog
entries. You can find this BlogBean.java in the
webapp, but here are the interesting parts:

//... 
@Inject
private Event<BlogPostedEvent> blogPostedEvents;

public String addEntry() {
   entries.add(entry);
   blogPostedEvents.fire(new BlogPostedEvent(entry));
   entry = null;
   return null;
}
//...

For the sake of brevity here, you can find the view
in examples/webapp/src/main/webapp/blog.xhtml. First,
notice the @Inject. Here, we’re asking CDI to inject
an Event that takes
BlogPostEvent payload. We use this
in addEntry(), when we
call blogPostedEvents.fire(new
BlogPostedEvent(entry))
. The code, simple as it is, should be
pretty self-explanatory: We’re firing an event of
type BlogPostedEvent, which looks like this:

public class BlogPostedEvent {
    private String blogEntry;
public BlogPostedEvent(String blogEntry) { this.blogEntry = blogEntry; } public String getBlogEntry() { return blogEntry; } }

In this example, our payload is very simple. In a real world,
this could be much more complex if your application’s needs
warrant. Responding to this event is just as simple as firing
it:

public void sendEmail(@Observes BlogPostedEvent event) {
    emailService.sendEmail(event.getBlogEntry());
}

That’s really all there is to it. By using CDI events, we
are able to push data into our plug-ins in a loosely coupled
manner. Again, in a real world application, the data push and the
processing required to handle will likely be more complex, but the
means of pushing it will not be. CDI for the win!

Perhaps you need to allow a plug-in to process data in the
system. For example, in our system we want allow plug-ins to
translate the blog entry into another language. To do so, we first
need to define the interface by which the plug-in will be
called:

public interface BlogEntryProcessor extends Serializable {
    String getName();
    String process(String text);
}

From our blogging system, we can get a list of all of
the BlogEntryProcessor instances, if any, with
this CDI injection:

@Inject @Translator
Instance<BlogEntryProcessor> translators;

This gives us
an Instance instance that contains
any BlogEntryProcessors defined in the
system. We’ll come back to @Translator in
a bit. Next, we can provide a way for the user to pick a language
with this code, using both JSF
markup:

<h:form>
<h:selectOneMenu value="#{blogBean.translator}" converter="#{translatorConvertor}">
<f:ajax render=":entries" event="change" execute="@form"/>
<f:selectItems value="#{blogBean.translators}" var="t" itemLabel="#{t.name}" />
</h:selectOneMenu>
</h:form>

And also managed bean code:

public List<BlogEntryProcessor> getTranslators() {
List<BlogEntryProcessor> list = new ArrayList<BlogEntryProcessor>();
for (BlogEntryProcessor t : translators) {
list.add(t);
}
return list;}

This lets us change the language, but how do we get a default?
Let’s define a Qualifier.

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface English { }

This simple class lets us differentiate at injection time:

@Inject
@English
private BlogEntryProcessor translator;

Instead of injecting Instance, we’re injecting a
single…instance. Since there might be more
than BlogEntryProcessor on the system, we have
to qualify which one we mean.

@English
@Singleton
@Translator
public class EnglishTranslator implements BlogEntryProcessor {
// ...
}

EnglishTranslator is
BlogEntryProcessor, and it has been marked
as @English, which means this instance, which is also
a singleton, will satisfy the injection above. We could have
annotated this with @Default, both here and at the
injection point, but the creation of a
custom @Qualifier is a good exercise.

But what’s up with that @Translator? That’s
another @Qualifier, which must be applied to
any BlogEntryProcessor that is intended to act
as a translator (and which we document clearly in our system
documentation, right?). Why is that important? In a simple system,
we wouldn’t need that, but we’re going to intentionally muddy
things a bit and introduce a different type
of BlogEntryProcessor, one which allows for tags.

One common type of plug-in in systems like WordPress allows a
user to wrap certain text in a tag. This entry, for example, uses
the code tag to get syntax highlighting. In our
system, we’ll implement a tag that creates links to Google Maps.
For example:

Disneyland can be found at [map]1313 North Harbor Boulevard, Anaheim, CA[/map].

How is this implemented? Just like the translators:

@Tagpublic class GoogleMapsProcessor implements BlogEntryProcessor {
@Override
public String getName() {
return "Google Maps Processor";
}

@Override
public String process(String text) {
Pattern pattern = Pattern.compile("\[map\](.*?)\[\/map\]");
String replaceStr = "<a href=\"https://maps.google.com/maps?q=$1\">$1</a>";
Matcher matcher = pattern.matcher(text);
String result = matcher.replaceAll(replaceStr);
return result;
}
}

This looks just like the translators, right?
The only difference is the @Tag qualifier:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface Tag {
}

In BlogBean, we access it and the translators
in getEntries():

@Inject
@Tag
Instance<BlogEntryProcessor> tags;
public List<string> getEntries() {
    List<String> list = new ArrayList<String>();
    for (String text : entries) {
        for (BlogEntryProcessor tag : tags) {
            text = tag.process(text);
        }
        text = translator.process(text);
        list.add(text);
    }
    return list;
}

You can build and deploy the system to see this in action. Very
simple, but very effective.

REST Resources

We’ve seen how to expose functionality to plug-ins loaded in the
system, but what if we want to allow these plug-ins to expose this
functionality to external clients, say, via REST? Again, Java EE
makes this incredibly simple, using two specs in concert, CDI and
JAX-RS.

One of the ways one might configure a JAX-RS application is to
provide a custom Application class, one which
extends javax.ws.rs.core.Application. Plummer
provides such an Application, so all Plummer users
need do is configure it in the web application (listing 16).

<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>
javax.ws.rs.Application
</param-name>
<param-value>
com.steeplesoft.plummer.kernel.rest.RestApplication
</param-value>
</init-param>
</servlet>

Oddly, note that the Application class is
standardized, but the REST servlet is not (unlike, for example,
JSF’s FacesServlet), so if you’re not using Jersey like we are here, then
you’ll need to use the Servlet appropriate for
your JAX-RS implementation.

So how does RestApplication work? It uses
CDI, but since it’s not handled by the CDI runtime, we can’t rely
on injection. Instead, we’ll perform a manual look up of
the BeanManager, a class provided by CDI’s excellent
portable extension mechanism. We then query
the BeanManager for our desired classes. But how
do we identify our REST resources? Remember
the Plugin marker interface? Plummer defines
another marker, RestResource, to mark the JAX-RS
resources we want to load, which are typical JAX-RS resources with
the exception of this extra interface:

@Path("myurl")
public class PluginRestResource implements RestResource {
@GET
public String test(@QueryParam("text") String text) {
return "You sent " + text;
}
}

When the REST application is initialized, this class is loaded
and exposed at /myurl as you would expect.

Conclusion

There are many, many plug-in systems available for Java
applications. It might be that one of these systems, modelled after
or borrowed from, for example, Hudson or others, is the best choice
for your application. I think that chances are good, though, that
you need not resort to such a relatively complex system. The Java
EE platform provides a rich set of APIs that will allow you to
implement a domain-specific plug-in system very simply, and with
the introduction of another external dependency.

You can find the complete source for Plummer and the examples
discussed here on GitHub. Feel free to
fork the code, fix bugs, add features, etc. If you find this
approach (or the example code) useful or use it in a production
system, I’d love to hear your feedback!

This tutorial originally appeared in the August edition
of JAX
Magazine
. Photo by State
Farm
.

Author
JasonLee
Jason Lee is a Senior Member of the Technical Staff for Oracle working on the GlassFish Administration Console as well as the RESTful Administration interface. Jason has extensive experience working with web-based technologies such as JavaServer Faces and Ajax, as well as many other enterprise technologies based on the GlassFish/Java EE platform. Jason has been writing software professionally since 1997 in a wide variety of language including Java, PHP, Python and C/C++.
Comments
comments powered by Disqus