I decided to implement dynamic class loading in my glassfish web application, as a way of trying it out and to support small plugins that could be loaded and executed by the web app at runtime.
I added the following class:
public class PluginManager { private static final String dropBoxDir = "file:///path/to/dropbox/"; private static final URLClassLoader dropBoxClassLoader; static { try { URL dropBoxURL = new URL(dropBoxDir); dropBoxClassLoader = URLClassLoader.newInstance(new URL[]{dropBoxURL}); } catch (MalformedURLException mue) { throw new RuntimeException("MalformedURLException thrown during PluginManager initialization - the hardcoded URL " + dropBoxDir + " must be invalid.", mue); } } //this method is called by a web service public static void runPluginFromDropBox(String fullClassName) { try { //load the plugin class Class<?> pluginClass = dropBoxClassLoader.loadClass(fullClassName); //instantiate it Runnable plugin = (Runnable)pluginClass.newInstance(); //call its run() method plugin.run(); } catch (ClassNotFoundException cnfe) { throw new RuntimeException("The class file for " + fullClassName + " could not be located at the designated directory (" + dropBoxDir + "). Check that the specified class name is correct, and that its file is in the right location.", cnfe); } catch (InstantiationException ie) { throw new RuntimeException("InstantiationException thrown when attempting to instantiate the plugin class " + fullClassName + " - make sure it is an instantiable class with a no-arg constructor.", ie); } catch (IllegalAccessException iae) { throw new RuntimeException("IllegalAccessException thrown when attempting to instantiate the plugin class " + fullClassName + " - make sure the class and its no-arg constructor have public access.", iae); } catch (ClassCastException cce) { throw new RuntimeException("Plugin instance could not be cast to Runnable - plugin classes must implement this interface.", cce); } } } Then in a separate project, I created a test plugin:
public class TestPlugin implements Runnable { @Override public void run() { System.out.println("plugin code executed"); } } I deployed the web application, then compiled TestPlugin into a .class file and dropped it into the designated folder. I called a web service that hits runPluginFromDropBox() with the class name and got the expected output.
This all worked as a proof of concept, but my plugin is effectively useless unless it can be made aware of my web application's classes. I've since read that .war is intended only as a standalone application, and not meant to be on other libraries' classpaths, which doesn't bode well for this little side-project.
I had a look at this discussion: Extending Java Web Applications with plugins and get the feeling I'm wading into a swamp of design challenges for no huge reason and should turn around. However that post is kind of old and is Tomcat-specific, so I just thought I'd ask if there's any straightforward way for me to approach this without some elaborate third party framework.