/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2012-2015 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can * obtain a copy of the License at * http://glassfish.java.net/public/CDDL+GPL_1_1.html * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package org.glassfish.jersey.servlet.portability; import java.io.IOException; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /** * Jersey Servlet/Filter class that can be referenced in web.xml instead of Jersey 1.x specific * {@code com.sun.jersey.spi.container.servlet.ServletContainer} and Jersey 2.x specific * {@link org.glassfish.jersey.servlet.ServletContainer} to enable web application portability between * Jersey 1.x and Jersey 2.x servlet containers. * <p> * Since for some of the {@link org.glassfish.jersey.servlet.ServletProperties servlet init parameters} that can be * specified in web.xml you may want different values depending on which version of Jersey container is present, * You can prefix the init parameter name either with {@code jersey1#} or {@code jersey2#} to * make it specific to a given version. For example, to specify different values for * {@code javax.ws.rs.Application} init parameter depending on the version of Jersey used, you can include * the following in your web.xml: * <pre> * <servlet> * <servlet-name>Jersey Web Application</servlet-name> * <servlet-class>org.glassfish.jersey.servlet.portability.PortableServletContainer</servlet-class> * <init-param> * <param-name>jersey1#javax.ws.rs.Application</param-name> * <param-value>myapp.jersey1specific.Jersey1Application</param-value> * </init-param> * <init-param> * <param-name>jersey2#javax.ws.rs.Application</param-name> * <param-value>myapp.jersey2specific.Jersey2Application</param-value> * </init-param> * </servlet> * </pre> * </p> * * @author Martin Matula */ public class PortableServletContainer implements Filter, Servlet { private static final String JERSEY_1_PREFIX = "jersey1#"; private static final String JERSEY_2_PREFIX = "jersey2#"; private final Servlet wrappedServlet; private final Filter wrappedFilter; private final String includePrefix; private final String excludePrefix; /** * Create a new servlet container. */ @SuppressWarnings("unchecked") public PortableServletContainer() { Class<Servlet> servletClass; boolean isJersey1 = false; try { servletClass = (Class<Servlet>) Class.forName("com.sun.jersey.spi.container.servlet.ServletContainer"); isJersey1 = true; } catch (ClassNotFoundException e) { // Jersey 1.x not present, try Jersey 2.x try { servletClass = (Class<Servlet>) Class.forName("org.glassfish.jersey.servlet.ServletContainer"); } catch (ClassNotFoundException ex) { throw new IllegalStateException(LocalizationMessages.JERSEY_NOT_AVAILABLE()); } } try { wrappedServlet = servletClass.newInstance(); wrappedFilter = (Filter) wrappedServlet; } catch (Exception e) { throw new RuntimeException(LocalizationMessages.JERSEY_CONTAINER_CANT_LOAD(), e); } includePrefix = isJersey1 ? JERSEY_1_PREFIX : JERSEY_2_PREFIX; excludePrefix = isJersey1 ? JERSEY_2_PREFIX : JERSEY_1_PREFIX; } @Override public void init(final FilterConfig filterConfig) throws ServletException { wrappedFilter.init(new FilterConfigWrapper(filterConfig)); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { wrappedFilter.doFilter(request, response, chain); } @Override public void init(ServletConfig config) throws ServletException { wrappedServlet.init(new ServletConfigWrapper(config)); } @Override public ServletConfig getServletConfig() { return wrappedServlet.getServletConfig(); } @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { wrappedServlet.service(req, res); } @Override public String getServletInfo() { return wrappedServlet.getServletInfo(); } @Override public void destroy() { wrappedServlet.destroy(); } private abstract class InitParamsWrapper { private final HashMap<String, String> filteredInitParams = new HashMap<String, String>(); void init() { for (Enumeration e = getInitParamNames(); e.hasMoreElements(); ) { String name = (String) e.nextElement(); String value = getInitParamValue(name); if (name.startsWith(includePrefix)) { name = name.substring(includePrefix.length()); } else if (name.startsWith(excludePrefix)) { continue; } filteredInitParams.put(name, value); } } abstract String getInitParamValue(String name); abstract Enumeration getInitParamNames(); public String getInitParameter(String name) { return filteredInitParams.get(name); } public Enumeration getInitParameterNames() { return Collections.enumeration(filteredInitParams.keySet()); } } private class FilterConfigWrapper extends InitParamsWrapper implements FilterConfig { private final FilterConfig wrapped; FilterConfigWrapper(FilterConfig wrapped) { this.wrapped = wrapped; init(); } @Override public String getFilterName() { return wrapped.getFilterName(); } @Override public ServletContext getServletContext() { return wrapped.getServletContext(); } @Override String getInitParamValue(String name) { return wrapped.getInitParameter(name); } @Override Enumeration getInitParamNames() { return wrapped.getInitParameterNames(); } } private class ServletConfigWrapper extends InitParamsWrapper implements ServletConfig { private final ServletConfig wrapped; ServletConfigWrapper(ServletConfig wrapped) { this.wrapped = wrapped; init(); } @Override String getInitParamValue(String name) { return wrapped.getInitParameter(name); } @Override Enumeration getInitParamNames() { return wrapped.getInitParameterNames(); } @Override public String getServletName() { return wrapped.getServletName(); } @Override public ServletContext getServletContext() { return wrapped.getServletContext(); } } }