Question

I have this web application that has grown to an unmanageable mess.

I want to split it into a common "framework" part (that still includes web stuff like pages and images) and several modules that add extra functionality and screens. I want this refactoring to also be useful as a plugin system for third-party extensions.

All modules need to be separate unit of deployments, ideally a war or jar file.

I tried to just make several regular war files, but Tomcat keeps (according to the servlet spec) these war files completely separate from each-other, so that they cannot share their classes, for example.

I need to plugins to be able to see the "main" classpath.

I need to main application to have some control over the plugins, such as being able to list them, and set their configuration.

I would like to maintain complete separation between the plugins themselves (unless they specify dependencies) and any other unrelated web applications that may be running on the same Tomcat.

I would like them to be rooted under the "main" application URL prefix, but that is not necessary.

I would like to use Tomcat (big architectural changes need to be coordinated with too many people), but also to hear about a clean solution in the EJB or OSGi world if there are.

Was it helpful?

Solution

I have been tinkering with the idea of using OSGi to solve the same problem you are describing. In particular I am looking at using Spring Dynamic Modules.

OTHER TIPS

Take a look at Java Portlets - http://developers.sun.com/portalserver/reference/techart/jsr168/ - in a nutshell, a specification that allows interoperability between what are otherwise self-contained j2ee web applications

Edit I forgot to mention that Portlets are pretty much framework agnostic - so you can use Spring for the parent application, and individual developers can use whatever they want on their Portlets.

Have you looked at using maven to separate out your projects and then have it resolve the dependencies between the WARs and JARs? You'll end up with duplication of libraries between WARs, but only where it's necessary (and this shouldn't be a problem unless you get into some funky classloader fun).

Tomcat also allows you to configure cross context applications if you need to get from one WAR to another in a relatively transparent way...

If you want to keep things under the same single web app (say ROOT) you could create a proxy webapp that forwards through to the relevant other webapp behind the scenes for the user to make it relatively transparent?

Your primary problem is going to center around the physical, static assets of the system -- the rest are simply, effectively, jars.

WARs are separated, in Tomcat, with separate classloaders but also they're separated at the session level (each WAR is an indvidual web app, and has it's own session state).

In Glassfish, if the WARs were bundled in an EAR, they would share classloaders (GF uses a flat class loader space in EARs), but would still have separate session state.

Also, I'm not sure if you can do a "forward" to another WAR in the server. The problem there is that forwards use a relative URL to the root of the Web App, and each WebApp has their own root, so you simply "can't get there from here". You can redirect, but that's not the same thing as a forward.

So these features of the Web App conspire against you trying to deploy them homogenously within the container.

Rather, I think the hot tip is to create an "assembler" utility that takes your individual modules and "merges" them in to a single Web App. It can merge their web.xml, their content, normalize the jars and classes, etc.

WARs are a feature and a bug in the Java world. I love them because they really do make deploying compiled applications "Drag and drop" in terms of installing them, and that's feature is used far more than what you're encountering. But I feel your pain. We have a common "core" framework we share across apps, and we basically have to continuously merge it to maintain it. We've scripted it, but it's still a bit of a pain.

"Also, I'm not sure if you can do a "forward" to another WAR in the server. The problem there is that forwards use a relative URL to the root of the Web App, and each WebApp has their own root, so you simply "can't get there from here". You can redirect, but that's not the same thing as a forward."

You can forward to another WAR as long as that WAR lets someone do it.

glassfish and multiple WARs of an EAR : that makes sense.

If you put the MAIN classes in the shared CLASSPATH of tomcat, then you can put your individual PLUGINs in separate WAR files.

The Main app can also be part of the TOMCAT servlet that you define in server.xml. This can be the MASTER SERVLET and all other WARs can be controlled by this master servlet.

Does that make sense ?

BR,
~A

Depending on the complexity of the plugin functionality I would also be considering a web service, for instance implemented with Axis.

Your main appplication is then configured with the URL to the web application (plugin) which provides the service.

The advantage,as I see it, is twofold:

  • You get a nice, clean, debuggable API between the two wars, namely the Soap/XML messages
  • You are able to upgrade a single plugin without having to regression-test your entire application

The disadvatages are that you have to set up some Axis projects, and that you have to have some sort of plugin configuration. Furthermore you might need to limit access to your services web applications, so a bit of configuration might be required.

If the plugins work on the same database be sure to either limit cache time or to configure a war-spanning caching layer.

I also been trying develop a common or abstract framework where I can add plugins (or modules) at runtime and enhance existing running webapp.

Now, as you said, preferred ed way to do it using WAR or JAR file. Problem with WAR file is, you can't deploy as plugin to existing app. Tomcat will deploy it as separate web context. Not desirable.

Another option is to JAR file and write some custom code to copy that JAR file to WEB-INF/lib folder and load the classes into existing classloader. Problem is, how to deploy non-java files like JSP or config files. For that, there r two solutions, a. Use velocity templates instead of JSP (b.) write some custom code to read JSP from classpath instead of context path.

OSGI or Spring Dynamic modules are nice, but at this time, they look overly complex to me. I will look into that again, if I get feel of it.

I am looking for simple API, which can take care of life cycle of plugin and still able to use JSPs in my packaged JAR file.

May be, you can use un jar the plugin at time deployment and copy files to right directories.

There actually is nothing better than OSGI if you are thinking about splitting application into separate modules. Take a look at Greenpages example. You can create a parent module (core) where you include jars that your application need.

If you know something about component programming, you will soon find out that OSGI modules behave like interfaces, where you have to expose what you will use in other modules. It is quite simple once you understand. Anyway it also can be really painful when you learn how to use OSGI. We had problems using JSON, as a version of Jackson that we added as jar to the module, was overridden by other jar that was contained in the Spring core modules. You always have to double check what version of jar is loaded for your needs.

Unfortunately even OSGI approach does not solve what we are searching for. How to extend a persistent model and existing forms in runtime.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top