An off-hand discussion at work (“This application is being used by more groups now . . . wouldn’t it be cool to make it so they can develop independently?”) led to me looking into Java classloaders this weekend. Here’s the core for an application that’s treated like a bus in that it looks to see what’s plugged into it and provides communications (context) to each plug-in.
private void audit() {
// get the plugin JARs
File basedir = new File(System.getProperty("user.dir") + File.separator + "dynamic");
System.err.println("Searching " + basedir + " for pluggable JARs");
if (basedir.isDirectory() && basedir.canRead()) {
// get a list of jar files
String [] jars = basedir.list(new FilenameFilter() {
public boolean accept(File file, String s) {
return s.endsWith(".jar");
}
});
URL [] urlJars = new URL[jars.length];
List<String> initializers = new ArrayList<String>(jars.length);
int i = 0;
for (String jar : jars) {
String jarpath = basedir.getAbsolutePath() + File.separator + jar;
// get the plug-in entry point from the jar
File jarfile = new File(jarpath);
if (jarfile.canRead()) {
// read the pluggable manifest
JarFile jf = null;
try {
jf = new JarFile(jarpath);
JarEntry entry = jf.getJarEntry("pluggable.txt");
if (entry != null) {
// manifest file found
BufferedInputStream bis = null;
String plugin = null;
try {
bis = new BufferedInputStream(jf.getInputStream(jf.getEntry("pluggable.txt")));
// todo should make sure bytes are available...
byte [] inBuf = new byte[1024];
// should be short: one line, pointing to a single class
bis.read(inBuf);
// todo validate plug-in class
plugin = new String(inBuf).trim();
if (plugin.length() < 1) {
System.err.println("Plug-in class name not found");
plugin = null;
} else if (initializers.contains(plugin)) {
System.err.println("Duplicate plug-in class name");
plugin = null;
}
} catch (IOException e) {
// couldn't open plug-in manifest
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
// do nothing
}
}
}
// only use the jar if the plug-in has a manifest class
if (plugin != null) {
try {
urlJars[i++] = new URL("file:///" + jarpath);
initializers.add(plugin);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
// couldn't open jar file
e.printStackTrace();
} finally {
if (jf != null) {
try {
jf.close();
} catch (IOException e) {
// do nothing
}
}
}
}
}
// load the pluggables
ClassLoader loader = URLClassLoader.newInstance(urlJars);
// load each pluggable initializer
for (String pluggableClass : initializers) {
try {
// load the pluggable class
Class clz = loader.loadClass(pluggableClass);
Pluggable pluggable = (Pluggable)clz.newInstance();
// initialize the plug-in
Method method = clz.getMethod("initializePlugin", PluggableContext.class);
method.invoke(pluggable, context);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
Java2html
Plug-in architectures in Java
Posted by Chris Jones
On March 14th, 2010 at 17:56
Permalink | Trackback | Links In |
Comments (2) |
Posted in Java
On March 14th, 2010 at 17:56
Permalink | Trackback | Links In |
Comments (2) |
Posted in Java
2 Responses to “Plug-in architectures in Java”
Categories
Bloglines Blogroll
- A Baggins Under the Hill
- Daily Grind
- The Dolf Zone
- Going On A Safari...
- The Java Rocker
- P7A77's Den o' Love
- samsonfamily.com
- Shaken Angel
- AFK Gamer
- Aggro Me
- Aspen's Blog
- The Corporation @ Corpnews.com - Lying About Games Since Forever
- covert.creations
- The Daedalus Project
- damned vulpine
- Everquest Daily Grind: MMORPG Infinity (no beyond)
- game girl advance
- The Gaming Bitch
- Heartlessgamer.com
- Kill Ten Rats
- MMOG Nation
- My 2 Copper
- Mystic Worlds
- n3rfed
- Plaguelands
- PlayOn
- Sierra Kilo
- Tattered Page
- Terra Nova
- Tide's Horizon
- Tobold's MMORPG Blog
- Van Hemlock
- VirginWorlds Blog
- West Karana
- What Would Matt Do
- Wonderland
- WorldIV.com
- A Dwarf Priest
- Banana Shoulders
- BigRedKitty - Cataclysm
- Blessing of Kings
- The Egotistical Priest
- Enter the Witch!
- Frostbolt, a World of Warcraft Blog
- The Game Dame
- Hogit's Story - A World of Warcraft Blog
- Less QQ, More PewPew
- Mania's Arcania
- Og's Ledger
- Picklemonkey
- Priestly Endeavors - a WoW Blog
- Unbearably HoT
- World of Warcraft Bot - WoW bots exposed
- Broken Toys
- Click Nothing
- Design Synthesis - structure.function.relation
- Devgamer
- Double Buffered
- Evidence-Based Design
- Game Matters
- Game Producer Blog
- GameDevBlog
- Games * Design * Art * Culture
- Games Are Art
- Games from Within
- Grumpy Gamer
- Jeff On Games
- kfsone's pittance
- Lost Garden
- The Ludologist
- Madness & Games
- Mobhunter.com
- Nerfbat
- Online Games Are a Niche Market
- PARANOIA
- Patrick Curry's Thoughts on Game Design
- PlayNoEvil - Game Security, IT Security, and Secure Game Design
- Programmer Joe
- QBlog
- Raph's Website
- Semionaut's Notebook
- SunSword's Edge
- toomuchimagination
- Vicarious Game Designer - PatrickMoran.com
- Working as Designed
- Zen of Design
- Addicting Entertainment
- The Flogging Will Continue...
- The Forge
- GBGames - Thoughts on Indie Game Development
- Make It Big In Games
- PhilSteinmeyer.com
- Psychochild's Blog
- Tales of the Rampant Coyote

March 16th, 2010 at 7:00 am
Isn’t this something that you can use osgi for? I am no osgi guy, but from the little I’ve read, anytime I want to have a pluggable classloader, osgi is the way to go.
You back in cincy, or still out in the NW US?
March 16th, 2010 at 8:29 am
Surprisingly, I hadn’t run across OSGI before Amazon or after. I thought of this code example more like the dynamic WAR loader in Tomcat or another container without the directory monitoring implemented.
OSGI looks like it provides a good set of high-level service calls if implemented completely and on top of standards-based libraries.