All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.codehaus.enunciate.modules.jersey.EnunciateJerseyServletContainer Maven / Gradle / Ivy

Go to download

The Enunciate Jersey runtime contains the libraries to support a Jersey-based REST project.

There is a newer version: 1.31
Show newest version
package org.codehaus.enunciate.modules.jersey;

import com.sun.jersey.api.container.ContainerException;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.api.uri.UriComponent;
import com.sun.jersey.core.spi.component.ioc.IoCComponentProviderFactory;
import com.sun.jersey.spi.container.WebApplication;
import com.sun.jersey.spi.container.servlet.ServletContainer;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Enunciate-specific servlet container that adds additional Enunciate-supported functionality to the Jersey JAX-RS container. This additional functionality
 * includes:
 *
 * 
    *
  • Loading known Enunciate providers
  • *
  • Application of a JAXB namespace prefix mapper
  • *
  • path-based resource conneg
  • *
  • Automatic (and dynamic) leverage of Spring container, if found in the environment.
  • *
* * @author Ryan Heaton */ public class EnunciateJerseyServletContainer extends ServletContainer { private static final Logger LOG = Logger.getLogger(EnunciateJerseyServletContainer.class.getName()); private ResourceConfig resourceConfig; private String resourceProviderFactory = "org.codehaus.enunciate.modules.jersey.EnunciateSpringComponentProviderFactory"; private WebApplication wa; private String servletPath; private boolean pathBasedConneg = true; @Override protected void configure(ServletConfig sc, ResourceConfig rc, WebApplication wa) { rc.getClasses().add(EnunciateJAXBContextResolver.class); InputStream stream = loadResource("/jaxrs-providers.list"); if (stream != null) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "utf-8")); String line = reader.readLine(); while (line != null) { rc.getClasses().add(loadClass(line)); line = reader.readLine(); } } catch (Throwable e) { LOG.log(Level.SEVERE, "Error loading enunciate-provided provider class. Skipping...", e); } } stream = loadResource("/jaxrs-root-resources.list"); if (stream != null) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "utf-8")); String line = reader.readLine(); while (line != null) { rc.getClasses().add(loadClass(line)); line = reader.readLine(); } } catch (Throwable e) { LOG.log(Level.SEVERE, "Error loading enunciate-provided root resource class. Skipping...", e); } } try { rc.getClasses().add(loadClass("org.codehaus.enunciate.modules.amf.JAXRSProvider")); } catch (Throwable e) { LOG.log(Level.INFO, "org.codehaus.enunciate.modules.amf.JAXRSProvider not found."); } try { rc.getClasses().add(loadClass("org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider")); } catch (Throwable e) { LOG.log(Level.INFO, "org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider not loaded. Perhaps Jackson isn't on the classpath?"); } String pathBasedConneg = sc.getInitParameter(JerseyAdaptedHttpServletRequest.FEATURE_PATH_BASED_CONNEG); if (pathBasedConneg == null) { pathBasedConneg = Boolean.TRUE.toString(); } this.pathBasedConneg = Boolean.valueOf(pathBasedConneg); rc.getFeatures().put(JerseyAdaptedHttpServletRequest.FEATURE_PATH_BASED_CONNEG, this.pathBasedConneg); String resourceProvider = sc.getInitParameter(JerseyAdaptedHttpServletRequest.PROPERTY_RESOURCE_PROVIDER_FACTORY); if (resourceProvider != null) { this.resourceProviderFactory = resourceProvider; } stream = loadResource("/media-type-mappings.properties"); if (stream != null) { try { Properties mappings = new Properties(); mappings.load(stream); for (Map.Entry entry : mappings.entrySet()) { rc.getMediaTypeMappings().put(String.valueOf(entry.getKey()), MediaType.valueOf(String.valueOf(entry.getValue()))); } } catch (IOException e) { //fall through... } } String servletPath = sc.getInitParameter(JerseyAdaptedHttpServletRequest.PROPERTY_SERVLET_PATH); this.servletPath = servletPath == null ? "" : servletPath; super.configure(sc, rc, wa); } @Override protected void initiate(ResourceConfig rc, WebApplication wa) { wa.initiate(rc, loadResourceProviderFacotry(rc)); this.resourceConfig = rc; } @Override protected WebApplication create() { WebApplication wa = super.create(); this.wa = wa; return wa; } /** * Attempts to load the spring component provider factory, if spring is enabled. * @param rc The resource config. * @return The component provider factory, or null if none. */ protected IoCComponentProviderFactory loadResourceProviderFacotry(ResourceConfig rc) { try { return (IoCComponentProviderFactory) loadClass(this.resourceProviderFactory) .getConstructor(ResourceConfig.class, ServletContext.class) .newInstance(rc, getServletContext()); } catch (Throwable e) { LOG.log(Level.INFO, "Unable to load the spring component provider factory. Using the jersey default..."); return null; } } @Override public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //to service the request, we have to calculate a "base" uri and a "request" uri. //Jersey determines which resource is being invoked by the difference between //the "base" uri and the "request" uri. Unfortunately, the default implementation //does an bogus job of calculating the "base" uri because it bases it off //the value of request.getServletPath(), which is the path defined in the //web.xml that matched the call to this servlet. So if we defined in web.xml //the exact path to the servlet, then the calculated request url will be the //same as the calculated base url. So we have to compensate for that here. //see http://jersey.576304.n2.nabble.com/ServletContainer-and-relative-path-resolution-td674105.html //first get what the request url is, from which we can base our calculations. UriBuilder requestUrl; try { requestUrl = UriBuilder.fromUri(String.valueOf(request.getRequestURL())); } catch (IllegalArgumentException e) { String message = e.getCause() == null ? e.getMessage() : e.getCause().getMessage(); if (message == null) { message = request.getRequestURL().insert(0, "Illegal URI: ").toString(); } response.sendError(400, message); return; } //now calculate the path of the base uri, always starting with the context path. StringBuilder baseUriPathBuilder = new StringBuilder(); //the next part is specific to Enunciate because Enunciate allows users to configure a "rest subcontext" //so users can put their rest endpoints under, for example, "/rest" and their soap endpoints under, say "/soap". //furthermore, for rest endpoints, Enunciate provides for the ability to do path-based content negotiation //so the default resource will be at, for example, "/rest/resource", but the xml representation will be //at "/xml/resource" and the json at "/json/resource". String requestPath = request.getRequestURI(); //start with what was actually requested. final String contextPath = request.getContextPath(); MediaType mediaType = null; if (!"".equals(contextPath) && requestPath.startsWith(contextPath)) { //the context path is part of the base uri. baseUriPathBuilder.append(contextPath); requestPath = requestPath.substring(contextPath.length()); } if (!"".equals(this.servletPath) && requestPath.startsWith(this.servletPath)) { //the enunciate-configured servlet path ("rest subcontext") is part of the base uri baseUriPathBuilder.append(this.servletPath); requestPath = requestPath.substring(this.servletPath.length()); } else if (this.pathBasedConneg) { //the enunciate-configured servlet path ("rest subcontext") is NOT part of the request. Iterate through //each media type mapping and see if it's part of the path. if (requestPath.startsWith("/")) { requestPath = requestPath.substring(1); } for (Map.Entry mediaMapping : this.resourceConfig.getMediaTypeMappings().entrySet()) { if (requestPath.startsWith(mediaMapping.getKey())) { //found a match to a specific media type, so we need to append the media type's 'key' to the base uri. String mediaKey = mediaMapping.getKey(); baseUriPathBuilder.append('/').append(mediaKey); requestPath = requestPath.substring(mediaKey.length()); mediaType = mediaMapping.getValue(); break; } } } final String baseUriPath = baseUriPathBuilder.append('/').toString(); //this check is in the super class, so I thought I'd keep it here for grins. if (!baseUriPath.equals(UriComponent.encode(baseUriPath, UriComponent.Type.PATH))) { throw new ContainerException("The servlet context path and/or the servlet path contain characters that are percent enocded"); } final URI baseUri = requestUrl.replacePath(baseUriPath).build(); String queryParameters = request.getQueryString(); if (queryParameters == null) { queryParameters = ""; } final URI requestUri = requestUrl .path(requestPath) .replaceQuery(queryParameters) .build(); request = new JerseyAdaptedHttpServletRequest(request, mediaType); response = new JerseyAdaptedHttpServletResponse(response, this.wa); service(baseUri, requestUri, request, response); } /** * Return the default ClassLoader to use: typically the thread context * ClassLoader, if available; the ClassLoader that loaded the EnunciateJAXBContextResolver * class will be used as fallback. *

Call this method if you intend to use the thread context ClassLoader * in a scenario where you absolutely need a non-null ClassLoader reference: * for example, for class path resource loading (but not necessarily for * Class.forName, which accepts a null ClassLoader * reference as well). * @return the default ClassLoader (never null) * @see java.lang.Thread#getContextClassLoader() */ public static ClassLoader getDefaultClassLoader() { ClassLoader cl = null; try { cl = Thread.currentThread().getContextClassLoader(); } catch (Throwable ex) { //fall through... } if (cl == null) { // No thread context class loader -> use class loader of this class. cl = EnunciateJAXBContextResolver.class.getClassLoader(); } return cl; } /** * Loads a resource from the classpath. * * @param resource The resource to load. * @return The resource. */ protected InputStream loadResource(String resource) { return getDefaultClassLoader().getResourceAsStream(resource); } /** * Loads a class from the classpath. * * @param classname The class name. * @return The class. */ protected Class loadClass(String classname) throws ClassNotFoundException { return getDefaultClassLoader().loadClass(classname); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy