/* * ============================================================================ * GNU Lesser General Public License * ============================================================================ * * Beanlet - JSE Application Container. * Copyright (C) 2006 Leon van Zantvoort * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * Leon van Zantvoort * 243 Acalanes Drive #11 * Sunnyvale, CA 94086 * USA * * zantvoort@users.sourceforge.net * http://beanlet.org */ package org.beanlet.rest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Enumeration; import javax.servlet.*; import javax.servlet.http.HttpServlet; import org.beanlet.BeanletApplicationException; /** * Add the following configuration to the web application's {@code web.xml} file * to support restlets. * </br> * Not required for Servlet 3.0 containers. * </br> * <pre> * <web-app> * ... * <listener> * <listener-class>org.beanlet.rest.RequestContextListener<listener-class> * </listener> * ... * </web-app> * </pre> * * Restlets are deployed automatically by defining a RestFilter or RestServlet in the web.xml: * * <pre> * <servlet> * <servlet-name>Beanlet Rest Servlet</servlet-name> * <servlet-class>org.beanlet.rest.RestServlet</servlet-class> * <init-param> * <param-name>om.sun.jersey.config.property.packages</param-name> * <param-value>com.acme</param-value> * </init-param> * <load-on-startup>1</load-on-startup> * </servlet> * * <servlet-mapping> * <servlet-name>Beanlet Rest Servlet</servlet-name> * <url-pattern>/*</url-pattern> * </servlet-mapping> * </pre> * * @author Leon van Zantvoort */ public class RestServlet extends HttpServlet { private static class LazyHolder { static final Constructor<HttpServlet> delegate; static { try { try { Constructor constructor = AccessController.doPrivileged( new PrivilegedExceptionAction<Constructor>() { public Constructor run() throws Exception { String path = "META-INF/services/" + RestServlet.class.getName(); // PERMISSION: java.lang.RuntimePermission getClassLoader ClassLoader loader = Thread.currentThread(). getContextClassLoader(); final Enumeration<URL> urls; if (loader == null) { urls = RequestContextListener.class. getClassLoader().getResources(path); } else { urls = loader.getResources(path); } while (urls.hasMoreElements()) { URL url = urls.nextElement(); BufferedReader reader = new BufferedReader(new InputStreamReader( url.openStream())); try { String className = null; while ((className = reader.readLine()) != null) { final String name = className.trim(); if (!name.startsWith("#") && !name.startsWith(";") && !name.startsWith("//")) { final Class<?> cls; if (loader == null) { cls = Class.forName(name); } else { cls = Class.forName(name, true, loader); } int m = cls.getModifiers(); if (HttpServlet.class.isAssignableFrom(cls) && !Modifier.isAbstract(m) && !Modifier.isInterface(m)) { // PERMISSION: java.lang.RuntimePermission accessDeclaredMembers Constructor constructor = cls.getDeclaredConstructor(); // PERMISSION: java.lang.reflect.ReflectPermission suppressAccessChecks if (!Modifier.isPublic(constructor.getModifiers())) { constructor.setAccessible(true); } return constructor; } else { throw new ClassCastException(cls.getName()); } } } } finally { reader.close(); } } throw new BeanletApplicationException("No " + "RestServlet implementation " + "found."); } }); @SuppressWarnings("unchecked") Constructor<HttpServlet> tmp = (Constructor<HttpServlet>) constructor; delegate = tmp; } catch (PrivilegedActionException e) { throw e.getException(); } } catch (BeanletApplicationException e) { throw e; } catch (RuntimeException e) { throw new BeanletApplicationException(e); } catch (Error e) { throw e; } catch (Throwable t) { throw new BeanletApplicationException(t); } } } private final HttpServlet delegate; public RestServlet() { try { try { delegate = LazyHolder.delegate.newInstance(); } catch (ExceptionInInitializerError e) { try { throw e.getException(); } catch (Throwable t) { throw new BeanletApplicationException(t); } } } catch (BeanletApplicationException e) { throw e; } catch (RuntimeException e) { throw e; } catch (Error e) { throw e; } catch (Exception e) { throw new BeanletApplicationException(e); } } @Override public String getServletName() { return delegate.getServletName(); } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { delegate.service(servletRequest, servletResponse); } @Override public void destroy() { delegate.destroy(); } @Override public String getInitParameter(String s) { return delegate.getInitParameter(s); } @Override public Enumeration<String> getInitParameterNames() { return delegate.getInitParameterNames(); } @Override public ServletConfig getServletConfig() { return delegate.getServletConfig(); } @Override public ServletContext getServletContext() { return delegate.getServletContext(); } @Override public String getServletInfo() { return delegate.getServletInfo(); } @Override public void init(ServletConfig servletConfig) throws ServletException { delegate.init(servletConfig); } @Override public void init() throws ServletException { delegate.init(); } @Override public void log(String s) { delegate.log(s); } @Override public void log(String s, Throwable throwable) { delegate.log(s, throwable); } }