001 /*
002 * ============================================================================
003 * GNU Lesser General Public License
004 * ============================================================================
005 *
006 * Beanlet - JSE Application Container.
007 * Copyright (C) 2006 Leon van Zantvoort
008 *
009 * This library is free software; you can redistribute it and/or
010 * modify it under the terms of the GNU Lesser General Public
011 * License as published by the Free Software Foundation; either
012 * version 2.1 of the License, or (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017 * Lesser General Public License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
022 *
023 * Leon van Zantvoort
024 * 243 Acalanes Drive #11
025 * Sunnyvale, CA 94086
026 * USA
027 *
028 * zantvoort@users.sourceforge.net
029 * http://beanlet.org
030 */
031 package org.beanlet.rest;
032
033 import java.io.BufferedReader;
034 import java.io.IOException;
035 import java.io.InputStreamReader;
036 import java.lang.reflect.Constructor;
037 import java.lang.reflect.Modifier;
038 import java.net.URL;
039 import java.security.AccessController;
040 import java.security.PrivilegedActionException;
041 import java.security.PrivilegedExceptionAction;
042 import java.util.Enumeration;
043 import javax.servlet.*;
044 import javax.servlet.http.HttpServlet;
045 import org.beanlet.BeanletApplicationException;
046
047 /**
048 * Add the following configuration to the web application's {@code web.xml} file
049 * to support restlets.
050 * </br>
051 * Not required for Servlet 3.0 containers.
052 * </br>
053 * <pre>
054 * <web-app>
055 * ...
056 * <listener>
057 * <listener-class>org.beanlet.rest.RequestContextListener<listener-class>
058 * </listener>
059 * ...
060 * </web-app>
061 * </pre>
062 *
063 * Restlets are deployed automatically by defining a RestFilter or RestServlet in the web.xml:
064 *
065 * <pre>
066 * <servlet>
067 * <servlet-name>Beanlet Rest Servlet</servlet-name>
068 * <servlet-class>org.beanlet.rest.RestServlet</servlet-class>
069 * <init-param>
070 * <param-name>om.sun.jersey.config.property.packages</param-name>
071 * <param-value>com.acme</param-value>
072 * </init-param>
073 * <load-on-startup>1</load-on-startup>
074 * </servlet>
075 *
076 * <servlet-mapping>
077 * <servlet-name>Beanlet Rest Servlet</servlet-name>
078 * <url-pattern>/*</url-pattern>
079 * </servlet-mapping>
080 * </pre>
081 *
082 * @author Leon van Zantvoort
083 */
084 public class RestServlet extends HttpServlet {
085
086 private static class LazyHolder {
087 static final Constructor<HttpServlet> delegate;
088 static {
089 try {
090 try {
091 Constructor constructor = AccessController.doPrivileged(
092 new PrivilegedExceptionAction<Constructor>() {
093 public Constructor run() throws Exception {
094 String path = "META-INF/services/" +
095 RestServlet.class.getName();
096
097 // PERMISSION: java.lang.RuntimePermission getClassLoader
098 ClassLoader loader = Thread.currentThread().
099 getContextClassLoader();
100 final Enumeration<URL> urls;
101 if (loader == null) {
102 urls = RequestContextListener.class.
103 getClassLoader().getResources(path);
104 } else {
105 urls = loader.getResources(path);
106 }
107 while (urls.hasMoreElements()) {
108 URL url = urls.nextElement();
109 BufferedReader reader = new BufferedReader(new InputStreamReader(
110 url.openStream()));
111 try {
112 String className = null;
113 while ((className = reader.readLine()) != null) {
114 final String name = className.trim();
115 if (!name.startsWith("#") && !name.startsWith(";") &&
116 !name.startsWith("//")) {
117 final Class<?> cls;
118 if (loader == null) {
119 cls = Class.forName(name);
120 } else {
121 cls = Class.forName(name, true, loader);
122 }
123 int m = cls.getModifiers();
124 if (HttpServlet.class.isAssignableFrom(cls) &&
125 !Modifier.isAbstract(m) &&
126 !Modifier.isInterface(m)) {
127 // PERMISSION: java.lang.RuntimePermission accessDeclaredMembers
128 Constructor constructor = cls.getDeclaredConstructor();
129 // PERMISSION: java.lang.reflect.ReflectPermission suppressAccessChecks
130 if (!Modifier.isPublic(constructor.getModifiers())) {
131 constructor.setAccessible(true);
132 }
133 return constructor;
134 } else {
135 throw new ClassCastException(cls.getName());
136 }
137 }
138 }
139 } finally {
140 reader.close();
141 }
142 }
143 throw new BeanletApplicationException("No " +
144 "RestServlet implementation " +
145 "found.");
146 }
147 });
148 @SuppressWarnings("unchecked")
149 Constructor<HttpServlet> tmp =
150 (Constructor<HttpServlet>) constructor;
151 delegate = tmp;
152 } catch (PrivilegedActionException e) {
153 throw e.getException();
154 }
155 } catch (BeanletApplicationException e) {
156 throw e;
157 } catch (RuntimeException e) {
158 throw new BeanletApplicationException(e);
159 } catch (Error e) {
160 throw e;
161 } catch (Throwable t) {
162 throw new BeanletApplicationException(t);
163 }
164 }
165 }
166
167 private final HttpServlet delegate;
168
169 public RestServlet() {
170 try {
171 try {
172 delegate = LazyHolder.delegate.newInstance();
173 } catch (ExceptionInInitializerError e) {
174 try {
175 throw e.getException();
176 } catch (Throwable t) {
177 throw new BeanletApplicationException(t);
178 }
179 }
180 } catch (BeanletApplicationException e) {
181 throw e;
182 } catch (RuntimeException e) {
183 throw e;
184 } catch (Error e) {
185 throw e;
186 } catch (Exception e) {
187 throw new BeanletApplicationException(e);
188 }
189 }
190
191 @Override
192 public String getServletName() {
193 return delegate.getServletName();
194 }
195
196 @Override
197 public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
198 delegate.service(servletRequest, servletResponse);
199 }
200
201 @Override
202 public void destroy() {
203 delegate.destroy();
204 }
205
206 @Override
207 public String getInitParameter(String s) {
208 return delegate.getInitParameter(s);
209 }
210
211 @Override
212 public Enumeration<String> getInitParameterNames() {
213 return delegate.getInitParameterNames();
214 }
215
216 @Override
217 public ServletConfig getServletConfig() {
218 return delegate.getServletConfig();
219 }
220
221 @Override
222 public ServletContext getServletContext() {
223 return delegate.getServletContext();
224 }
225
226 @Override
227 public String getServletInfo() {
228 return delegate.getServletInfo();
229 }
230
231 @Override
232 public void init(ServletConfig servletConfig) throws ServletException {
233 delegate.init(servletConfig);
234 }
235
236 @Override
237 public void init() throws ServletException {
238 delegate.init();
239 }
240
241 @Override
242 public void log(String s) {
243 delegate.log(s);
244 }
245
246 @Override
247 public void log(String s, Throwable throwable) {
248 delegate.log(s, throwable);
249 }
250 }