How would you implement an extendable web application? What I'm thinking about is a web application similar to Jenkins or Hudson which provides plug-in support. While it's obvious to me how plug-ins can be located and loaded, I don't know how they can be integrated within the overall architecture. I'm especially uncertain about the following points.
How can a plug-in change the view, e.g. add input elements to a form?
My first idea would be that a plug-in can register partials / fragments for a certain form.
Example: Newsletter plug-in which registers a typical newsletter checkbox fragment which will be rendered in the user registration view.
How can a plug-in react to incoming requests?
Again, a direct approach would be to provide listeners for certain requests or actions, e.g. POST request to /user.
How could a plug-in persist data?
I'm assuming this is a situation where NoSQL data storage solutions would be superior to relational databases.
I would appreciate any comments, ideas and experiences (maybe there is even a design pattern) that you have regarding extendable web applications.
1 Answer 1
Your question contains almost all the answers. You're right in the ballpark: it's all plug-ins and their extension points to set the context and make them do the things you want. There are numerou ways to design plug-in systems. For starters:
http://people.clarkson.edu/~dhou/courses/EE564-s07/plugin.pdf
http://blogs.atlassian.com/developer/2011/03/plugin_architecture_episode_i.html
Here is a trivial example to illustrate how a rudimentary plugin-aware system would work:
public interface Plugin {
void setEntityManager(EntityManager manager); // this is very course grained and liberal! A plugin would have access to whatever Entity Manager the container gives it. A plugin would then have a carte blanche to do whatever it needs: create, drop, insert, select, delete.
View renderView(ViewContext context); // a plugin would render or return a view (whatever it is, could be a string in the simplest case) based on the context that the container passed to the plugin
Action readEvent(Event event); // a plugin performs some Action based on an event as notified by a container
}
public class PluginContainer {
private List<Plugin> plugins = new ArrayList<Plugin>();
public void registerPlugins() {
// loop through plugin descriptors obtained by your preferred mechanism
// like introspecting libraries (JARs) in a configurable location
// for each descriptor, load a Plugin dynamically and "register" it with a container
Plugin p = ClassLoader.getSystemClassLoader().loadClass("com.my.PluginA").newInstance();
p.setEntityManager(entityManager);
plugins.add(p);
}
public void readEvent(AppEvent appEvent) {
Event e = this.constructPluginSpecificEventFromAppEvent(); // optional
for (Plugin p : this.plugins) {
p.readEvent(e); // disregarding Action here
}
}
}
public class Application {
private PluginContainer pContainer;
private void buttonClicked(AppEvent appEvent) {
this.showCoolDialog("Thank you for clicking a button!");
// now let my plugins handle this
// they can do whatever they want for this event
// since they have access to EntityManager, they can work with a persistence storage as well
this.pcContainer.readEvent(appEvent);
}
}
Explore related questions
See similar questions with these tags.