views:

939

answers:

7

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.

+4  A: 

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.

bmatthews68
Me and a guy from my work have been talking about doing this too.
Konrad
Has anybody actually done this successfully with osgi? If so - what guidance would you have on how to start?
harmanjd
I'm actually working with a team that have used OSGi to implement the service layer of the application. They used Apache Felix and embedded an Jetty container to expose the services as RESTful web services. There were problems due to the fact that Apache Felix did not support fragments fully until version 1.8.
bmatthews68
+1  A: 

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?

Martin
+1  A: 

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.

Will Hartung
+1  A: 
anjanb
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.

extraneon
+3  A: 

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.

iAn
A: 

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.

Yeah, I rolled my own, too. But you will feel the pain, and then hope you went with Spring DS or OSGI from the start. I know I did.
Thilo