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
![Page 1: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/1.jpg)
<Insert Picture Here>
Writing Plugged-In Java EE Apps
Jason Lee
July 9, 2012
![Page 2: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/2.jpg)
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
![Page 3: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/3.jpg)
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
![Page 4: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/4.jpg)
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
![Page 5: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/5.jpg)
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
![Page 6: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/6.jpg)
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
![Page 7: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/7.jpg)
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
![Page 8: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/8.jpg)
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
![Page 9: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/9.jpg)
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
![Page 10: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/10.jpg)
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
![Page 11: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/11.jpg)
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
![Page 12: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/12.jpg)
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
![Page 13: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/13.jpg)
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
![Page 14: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/14.jpg)
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
![Page 15: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/15.jpg)
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
![Page 16: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/16.jpg)
16Oracle Confidential
CDI – The Real Work Horse
• CDI Events– Pub/Sub– Loose coupling– Multiple Receivers
• Programmatic Bean Lookup– Instance<Foo>– Iterate over over instances
![Page 17: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/17.jpg)
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>
![Page 18: Writing Plugged-in Java EE Apps: Jason Lee](https://reader036.fdocuments.us/reader036/viewer/2022081813/5585289ed8b42ae4748b5288/html5/thumbnails/18.jpg)
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()