We have multiple Java web apps packaged as WARs all packaged in an EAR. Our RESTful services are built using JAX-RS and in version specific WARs.
We'd like to add static content for each of these version specific WARs, but use the root context (of the WAR) for both the static content and the RESTful service API calls, such that all of the following URLs will work:
{hostname}/v1/swagger.yaml <-- Static Content describing the v1 API
{hostname}/v1/orders/{uid} <-- JAX-RS RESTful API (v1)
{hostname}/v2/swagger.yaml <-- Static Content describing the v2 API
{hostname}/v2/orders/{uid} <-- JAX-RS RESTful API (v2)
The following deployment structure is what we currently have, which works for the JAX-RS services, but not the static content. In other words these URLs work:
{hostname}/v1/orders/{uid} <-- JAX-RS RESTful API (v1)
{hostname}/v2/orders/{uid} <-- JAX-RS RESTful API (v2)
But the problem is that these URLS are inaccessible:
{hostname}/v1/swagger.yaml <-- Static Content describing the v1 API
{hostname}/v2/swagger.yaml <-- Static Content describing the v2 API
Question: How do we get these static URLs to work?
Here's the exploded EAR:
example.ear
META-INF
application.xml
v1.war
swagger.yaml
WEB-INF
web.xml
classes
ApplicationV1.class
OrdersResourceV1.class
v2.war
swagger.yaml
WEB-INF
web.xml
classes
ApplicationV2.class
OrdersResourceV2.class
Here's the EARs application.xml
:
<?xml version="1.0"?>
<application xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="6">
<application-name>...</application-name>
<module>
<web>
<web-uri>v1.war</web-uri>
<context-root>/v1</context-root>
</web>
</module>
<module>
<web>
<web-uri>v2.war</web-uri>
<context-root>/v2</context-root>
</web>
</module>
<module>
<web>
<web-uri>another.war</web-uri>
<context-root>/</context-root>
</web>
</module>
</application>
Here's the v1 & v2 web.xml
:
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
</web-app>
Here's the ApplicationV1.java
(JAX-RS) implementation, notice the URL mapping:
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class ApplicationV1 extends Application {
private Set<Object> singletons = new HashSet<Object>();
public ApplicationV1() {
singletons.add(new OrdersResourceV1());
}
@Override
public Set<Object> getSingletons() {
return singletons;
}
}
Here's the OrdersResourceV1.java
(JAX-RS) implementation, notice the URL mapping:
import javax.enterprise.context.RequestScoped;
import javax.ws.rs.*;
@RequestScoped
@Path("/orders")
public class OrdersResourceV1 {
@GET
@Path("/{uid}")
@Produces("application/json;charset=UTF-8")
public Response getOrder(@PathParam("uid") String orderUid) {
<ommited for brevity>
}
}
I do know that if we changed ApplicationV*.java
's mapping to @ApplicationPath("/services")
, that the static content will be assessable, but the URLs will then be as follows, but it's our goal to not include any extraneous path elements like this.
{hostname}/v1/swagger.yaml <-- Static Content describing the v1 API
{hostname}/v1/services/orders/{uid} <-- JAX-RS RESTful API (v1)
{hostname}/v2/swagger.yaml <-- Static Content describing the v2 API
{hostname}/v2/services/orders/{uid} <-- JAX-RS RESTful API (v2)
So my question is, how do we get the JAX-RS and static content under the root context for the WAR (/v1
and /v2
)? Is there a different way to map the URLs? Or is there a configuration option that allows for a static fallback if JAX-RS doesn't have a handler for the URL?
I'm hoping that this can be solved a JavaEE generic fashion, but if not, we're using Wildfly 8.1 on Java8.
So I found a solution (tested) that works. As stated in the Resteasy Documentation - RESTEasy as a servlet Filter:
The downside of running Resteasy as a Servlet is that you cannot have static resources like .html and .jpeg files in the same path as your JAX-RS services. Resteasy allows you to run as a Filter instead. If a JAX-RS resource is not found under the URL requested, Resteasy will delegate back to the base servlet container to resolve URLs.
web.xml example
<web-app>
<filter>
<filter-name>Resteasy</filter-name>
<filter-class>
org.jboss.resteasy.plugins.server.servlet.FilterDispatcher
</filter-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.restfully.shop.services.ShoppingApplication</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Resteasy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With