Writing Plugged-in Java EE Apps: Jason Lee
-
Upload
jaxconf -
Category
Technology
-
view
534 -
download
1
description
Transcript of Writing Plugged-in Java EE Apps: Jason Lee
<Insert Picture Here>
Writing Plugged-In Java EE Apps
Jason Lee
July 9, 2012
2Oracle Confidential
Who Am I?
• Principal MTS for Oracle Corporation (by way of Sun Microsystems)
• Member of GlassFish team– RESTful Management APIs– Administration Console
• JSF user/developer• Live in Oklahoma City, OK
3Oracle Confidential
Introduction
• Plugins are not a new concept– Means of providing extensibility or decomposing and decoupling
functionality– The concept has been around for years
• NetBeans/Eclipse/IDEA• Wordpress• Hudson
• The what and why are easy. The how is the hard part.– How do I get access to the plugin code?– How do I identify the plugins deployed with the system– How do I expose core system functionality to the plugins
4Oracle Confidential
Introduction – cont.
• Some background– GlassFish 3.x Administration Console
• Core application does very little• All actual functionality delivered as plugins• Based on proprietary technologies
– HK2/OSGi– JSFTemplating
– For GlassFish 4.x, the basic stack had to change• Reevaluate whole system• Investigate HK2/OSGi, CDI, existing systems, etc.• Design a system based on modern technologies, preferably
standards
5Oracle Confidential
Problem #1 – Class Loading
• The hard part– Where do I put the jar files?– How do I load them?
• Three (probably of many) choices– Repackaging– Manual ClassLoading– OSGi
6Oracle Confidential
Problem #1 - Class Loading - Repackaging
• Simple and portable– Guaranteed to support every Java EE technology supported
in .war files
• Ant-/Maven-/etc-based– Base distribution war– Collection of plugins– War rebuilt to include plugin jars
• Liferay uses this. Works well.• Redeploys/upgrades take a bit more time/work
7Oracle Confidential
#!/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
Problem #1 - Class Loading - RepackagingProblem #1 - Class Loading - Repackaging
8Oracle Confidential
Problem #1 - Class Loading – Manual ClassLoading
• Filesystem-based– Much like Wordpress
• wordpress/wp-content/plugins/*– ~/.plugins
• War is deployed unchanged• Fairly portable, in theory
– Demo works on GlassFish– Currently breaks on JBoss– Should be easily solvable
• Demo - Plummer
9Oracle Confidential
public class PluginLoader implements Extension {
// ...
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);
}
}
}
// ...
}
Problem #1 - Class Loading – Manual ClassLoading
10Oracle Confidential
Problem #1 – Class Loading - OSGi
• Well-defined and understood solution
• Web Application Bundles not quite what we need– Requires repackaging
• Container must support OSGi• Deployment will likely vary between containers
11Oracle Confidential
public class PluginActivator implements BundleActivator {
@Override
public void start(BundleContext context) throws Exception {
ServiceTracker tracker = new ServiceTracker(context, PluginTracker.class.getName(), null);
tracker.open();
PluginTracker pt = (PluginTracker)tracker.getService();
if (pt != null) {
pt.registerPluginBundle(context.getBundle());
}
tracker.close();
}
@Override
public void stop(BundleContext context) throws Exception {
}
}
Problem #1 – Class Loading - OSGi
12Oracle Confidential
public class PluginTrackerImpl implements PluginTracker {
@Override
public void registerPluginBundle(Bundle bundle) {
if (bundle.getEntry("META-INF/beans.xml") != null) {
Enumeration<URL> e = bundle.findEntries("/", "*.class", true);
while (e.hasMoreElements()) {
String className = e.nextElement().getPath().substring(1).replace("/", ".");
className = className.substring(0, className.length()-6);
classes.add(className);
}
}
}
public Set<String> getClasses() {
return classes;
}
}
Problem #1 – Class Loading - OSGi
13Oracle Confidential
public class PlummerActivator implements BundleActivator {
@Override
public void start(BundleContext context) throws Exception {
context.registerService(PluginTracker.class.getName(), PluginTrackerImpl.instance(),
new Properties());
}
@Override
public void stop(BundleContext context) throws Exception {
context.ungetService(context.getServiceReference(PluginTracker.class.getName()));
}
}
Problem #1 – Class Loading - OSGi
14Oracle Confidential
Problem #2 – Application Design
• Largely application-specific
• General strategies and techniques can be defined
• Once plugins are loaded, how are they integrated into the application?– Java EE to the rescue
• JSF• CDI• REST
15Oracle Confidential
JSF Extensibility
• Views decomposed into fragments• Custom component used to insert fragments
– pl:viewFragment
• Current solution is Mojarra-specific– MyFaces solution needed– Can also be implemented in Swing/JavaFX
16Oracle Confidential
CDI – The Real Work Horse
• CDI Events– Pub/Sub– Loose coupling– Multiple Receivers
• Programmatic Bean Lookup– Instance<Foo>– Iterate over over instances
17Oracle Confidential
JAX-RS Resources
• Plugins can provide REST resources
• Configure using Application rather than a package– javax.ws.rs.core.Application– <servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value> org.glassfish.plummer.kernel.rest.RestApplication </param-value>
</init-param>
</servlet>
18Oracle Confidential
JAX-RS Resources – Part 2
• Use CDI to find JAX-RS resources– Use a marker interface, e.g. RestResource– Look up BeanManager in JNDI
• BeanManager beanManager = (BeanManager) initialContext.lookup("java:comp/BeanManager");
– Ask CDI for the RestResource instances• beanManager.getBeans(RestResource.class);
– Return set of Classes• Application.getClasses()