mcherm
mcherm

Reputation: 24656

Can I have multiple Java webapps with overlapping paths?

I have a large collection of different independent (stateless) web services written in Java and compiled as WAR files. I want to deploy them to a single web application server.

If the URIs handled by the services in each WAR file began with a prefix I could use as a web app name, then this would be easy. I could, for instance, have

SALES WAR FILE: contains code for the following:
GET http://example.com/sales/widgets
POST http://example.com/sales/widgets
GET http://example.com/sales/sky-hooks

MARKETING WAR FILE: contains code for the following:
GET http://example.com/marketing/widgets
PUT http://example.com/marketing/sky-hooks

...in which case I would simply deploy two WAR files under the names "sales" and "marketing". However, I am not that fortunate. Instead, the URI paths handled by the components overlap. Something like this:

SALES WAR FILE: contains code for the following:
GET http://example.com/widgets/sales
POST http://example.com/widgets/sales
GET http://example.com/sky-hooks/sales

MARKETING WAR FILE: contains code for the following:
GET http://example.com/widgets/marketing
PUT http://example.com/sky-hooks/marketing

My question is how (if at all) I can deploy these on a single web application server.

I am open to suggestions that require a significant amount of work. For instance, my best-so-far idea is to build services that expect a component-name prefix before the regular URI path, then pipe all incoming traffic through a different server that knows what component each URI pattern falls into and modifies the URI to add that prefix. The difficulty with this approach is that tools like Swagger that read my source code will have a mistaken idea of what the URIs look like.

Any ideas?

Upvotes: 3

Views: 1321

Answers (5)

Aragorn
Aragorn

Reputation: 5289

This is a use case for Reverse Proxy. If your web server is Apache, as suggested by @nont proxy_mod can be used to create a reverse proxy.

I know that IBM Http Server (IHS) also allows this mod.

Upvotes: 0

Eugene Loy
Eugene Loy

Reputation: 12426

If I understand your question correctly, one of the solutions would be (I am assuming Tomcat is used but this should apply to most of the modern servlet containers):

1) Deploy your sales and marketing wars with different prefixes. I.e., using your example, they should be able to serve the following urls:

GET http://example.com/sales/widgets/sales
POST http://example.com/sales/widgets/sales 
GET http://example.com/sales/sky-hooks/sales

GET http://example.com/marketing/widgets/marketing
PUT http://example.com/marketing/sky-hooks/marketing

2) Use UrlRewriteFilter to craft lightweight web application that will be deployed to your servlet container root prefix (for Tomcat it is called ROOT.war) and will rewrite urls in incoming requests to point to relevant web application.

In other words, incoming request like:

/widgets/sales

will be transformed to:

/sales/widgets/sales

... and delivered to sales webapp.

Similarly, in response urls like:

/sales/widgets/sales

will be rewritten to:

/widgets/sales

3) Deploy this war to root of your servlet container.

This approach is somewhat similar to the one suggested by @nont but does not require apache as a frontend as the rewriting functionality will be handled by root web application (UrlRewriteFilter basically implements mod_rewrite functionality).

In other words you'll be able to deploy all your applications (including this rewrite application that is deployed to the root prefix) to single server alleviating need for extra intermediate proxy/rewrite servers.

Upvotes: 4

Kent Dorsey
Kent Dorsey

Reputation: 336

First, Determine How the Deployments may be Configured

Are you sure the absolute URIs must overlap? The context root will prefix the path supported by each service, unless the absolute path has somehow been coded into the application itself. The first step is to enable direct access to each WAR file, either through unique context roots or application instances.

Option 1: Set the Context Root for each WAR File Explicitly

The context root for a war file is set at deploy time. For some servers, this can be set outside of the web application using an external deployment descriptor. For Tomcat, it may embedded within META-INF/context.xml. See http://tomcat.apache.org/tomcat-7.0-doc/config/context.html for more information.

Option 2: Separate the Context Root Instances using Multiple Containers

Alternatively, deploy each war file to a separate instance of a Java EE servlet container, each running on a different port. This will solve the deployment conflict in the case of a hard-coded absolute path.

Finally, Set up a Virtual Host and Proxy the Requests via Apache and mod_jk

Once the context roots instances have been made uniquely accessible by one of the previous methods, configure an instance of Apache to serve as a reverse-proxy. First, set up a virtual host to handle requests for the externally visible URI. Next, configure mod_jk to route the requests to the correct WAR file deployment. See http://tomcat.apache.org/connectors-doc/webserver_howto/apache.html for more details.

Afterthoughts

The above solution approach is generic for this type of problem and will require some knowledge of Apache and Tomcat configuration, which were chosen as example reverse-proxy and Java EE servlet technologies for its implementation. Additional detail on the deployment constraints would help to determine an optimal solution. In general, identifying the hard constraints on what may be changed versus what may not be changed should guide you quickly to a solution.

Upvotes: 1

nont
nont

Reputation: 9529

If you're willing to put apache in front of your web container, you can use apache's mod_proxy to forward request to the right place.

One way this could work, would be deploy the separate wars at separate prefixes as in your first case (sales and marketing) and then use ProxyPass to send the requests to the correct place:

ProxyPass /widget/sales http://example.com/sales/widget
ProxyPass /sky-hooks/sales http://example.com/sales/sky-hooks

ProxyPass /widget/marketing http://example.com/marketing/widget
ProxyPass /sky-hooks/marketing http://example.com/marketing/sky-hooks

Its probably a better idea to just refactor your routing though - it might be hard to maintain.

(EDIT: I originally suggested mod_rewrite, but I wanted to make my answer more specific, and it looks like this could be done purely with proxying)

Upvotes: 6

NimChimpsky
NimChimpsky

Reputation: 47300

The obvious slotuion is to rename the wars, or refactor so that the appropriate mappings are in the correct place.

Anything else is going to be a bit hacky, you can't change the war name, even to soemthing like below :

SALES WAR FILE: contains code for the following:
GET http://example.com/webapp1/widgets/sales
POST http://example.com/webapp1/widgets/sales
GET http://example.com/webapp1/sky-hooks/sales

MARKETING WAR FILE: contains code for the following:
GET http://example.com/webapp2/widgets/marketing
PUT http://example.com/webapp2/sky-hooks/marketing

You could also create another war for routing/filtering, that redirects everything appropriately - but that also relies on altering url somewhat.

Upvotes: 0

Related Questions