Source code: org/mortbay/jetty/servlet/ServletHolder.java
1 // ===========================================================================
2 // Copyright (c) 1996-2003 Mort Bay Consulting Pty. Ltd. All rights reserved.
3 // $Id: ServletHolder.java,v 1.39 2003/09/18 13:29:24 gregwilkins Exp $
4 // ---------------------------------------------------------------------------
5
6 package org.mortbay.jetty.servlet;
7
8 import java.io.IOException;
9 import java.security.Principal;
10 import java.util.Enumeration;
11 import java.util.HashMap;
12 import java.util.Map;
13 import java.util.Stack;
14
15 import javax.servlet.Servlet;
16 import javax.servlet.ServletConfig;
17 import javax.servlet.ServletContext;
18 import javax.servlet.ServletException;
19 import javax.servlet.ServletRequest;
20 import javax.servlet.ServletResponse;
21 import javax.servlet.UnavailableException;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.mortbay.http.HttpRequest;
26 import org.mortbay.http.UserRealm;
27 import org.mortbay.util.LogSupport;
28
29
30 /* --------------------------------------------------------------------- */
31 /** Servlet Instance and Context Holder.
32 * Holds the name, params and some state of a javax.servlet.Servlet
33 * instance. It implements the ServletConfig interface.
34 * This class will organise the loading of the servlet when needed or
35 * requested.
36 *
37 * @version $Id: ServletHolder.java,v 1.39 2003/09/18 13:29:24 gregwilkins Exp $
38 * @author Greg Wilkins
39 */
40 public class ServletHolder extends Holder
41 implements Comparable
42 {
43 private static Log log = LogFactory.getLog(ServletHolder.class);
44
45 /* ---------------------------------------------------------------- */
46
47 private int _initOrder;
48 private boolean _initOnStartup=false;
49 private Map _roleMap;
50 private String _forcedPath;
51 private String _run_as;
52 private UserRealm _realm;
53
54
55 private transient Stack _servlets;
56 private transient Servlet _servlet;
57 private transient Config _config;
58 private transient long _unavailable;
59 private transient UnavailableException _unavailableEx;
60
61
62 /* ---------------------------------------------------------------- */
63 /** Constructor for Serialization.
64 */
65 public ServletHolder()
66 {}
67
68
69 /* ---------------------------------------------------------------- */
70 /** Constructor.
71 * @param handler The ServletHandler instance for this servlet.
72 * @param name The name of the servlet.
73 * @param className The class name of the servlet.
74 */
75 public ServletHolder(ServletHandler handler,
76 String name,
77 String className)
78 {
79 super(handler,(name==null)?className:name,className);
80 }
81
82 /* ---------------------------------------------------------------- */
83 /** Constructor.
84 * @param handler The ServletHandler instance for this servlet.
85 * @param name The name of the servlet.
86 * @param className The class name of the servlet.
87 * @param forcedPath If non null, the request attribute
88 * javax.servlet.include.servlet_path will be set to this path before
89 * service is called.
90 */
91 public ServletHolder(ServletHandler handler,
92 String name,
93 String className,
94 String forcedPath)
95 {
96 this(handler,(name==null)?className:name,className);
97 _forcedPath=forcedPath;
98 }
99
100
101 /* ------------------------------------------------------------ */
102 public int getInitOrder()
103 {
104 return _initOrder;
105 }
106
107 /* ------------------------------------------------------------ */
108 /** Set the initialize order.
109 * Holders with order<0, are initialized on use. Those with
110 * order>=0 are initialized in increasing order when the handler
111 * is started.
112 */
113 public void setInitOrder(int order)
114 {
115 _initOnStartup=true;
116 _initOrder = order;
117 }
118
119 /* ------------------------------------------------------------ */
120 /** Comparitor by init order.
121 */
122 public int compareTo(Object o)
123 {
124 if (o instanceof ServletHolder)
125 {
126 ServletHolder sh= (ServletHolder)o;
127 if (sh==this)
128 return 0;
129 if (sh._initOrder<_initOrder)
130 return 1;
131 if (sh._initOrder>_initOrder)
132 return -1;
133 int c=_className.compareTo(sh._className);
134 if (c==0)
135 c=_name.compareTo(sh._name);
136 if (c==0)
137 c=this.hashCode()>o.hashCode()?1:-1;
138 return c;
139 }
140 return 1;
141 }
142
143 /* ------------------------------------------------------------ */
144 public boolean equals(Object o)
145 {
146 return compareTo(o)==0;
147 }
148
149 /* ---------------------------------------------------------------- */
150 public ServletContext getServletContext()
151 {
152 return ((ServletHandler)_httpHandler).getServletContext();
153 }
154
155 /* ------------------------------------------------------------ */
156 /** Link a user role.
157 * Translate the role name used by a servlet, to the link name
158 * used by the container.
159 * @param name The role name as used by the servlet
160 * @param link The role name as used by the container.
161 */
162 public synchronized void setUserRoleLink(String name,String link)
163 {
164 if (_roleMap==null)
165 _roleMap=new HashMap();
166 _roleMap.put(name,link);
167 }
168
169 /* ------------------------------------------------------------ */
170 /** get a user role link.
171 * @param name The name of the role
172 * @return The name as translated by the link. If no link exists,
173 * the name is returned.
174 */
175 public String getUserRoleLink(String name)
176 {
177 if (_roleMap==null)
178 return name;
179 String link=(String)_roleMap.get(name);
180 return (link==null)?name:link;
181 }
182
183 /* ------------------------------------------------------------ */
184 /**
185 * @param role Role name that is added to UserPrincipal when this servlet
186 * is called.
187 */
188 public void setRunAs(String role)
189 {
190 _run_as=role;
191 }
192
193 /* ------------------------------------------------------------ */
194 public String getRunAs()
195 {
196 return _run_as;
197 }
198
199 /* ------------------------------------------------------------ */
200 public void start()
201 throws Exception
202 {
203 _unavailable=0;
204 super.start();
205
206 if (!javax.servlet.Servlet.class
207 .isAssignableFrom(_class))
208 {
209 Exception ex = new IllegalStateException("Servlet "+_class+
210 " is not a javax.servlet.Servlet");
211 super.stop();
212 throw ex;
213 }
214
215 if (javax.servlet.SingleThreadModel.class
216 .isAssignableFrom(_class))
217 _servlets=new Stack();
218
219 if (_initOnStartup)
220 {
221 _servlet=(Servlet)newInstance();
222 _config=new Config();
223 try
224 {
225 _servlet.init(_config);
226 }
227 catch(Throwable e)
228 {
229 _servlet=null;
230 _config=null;
231 if (e instanceof Exception)
232 throw (Exception) e;
233 else if (e instanceof Error)
234 throw (Error)e;
235 else
236 throw new ServletException(e);
237 }
238 }
239
240 if (_run_as!=null)
241 _realm=_httpHandler.getHttpContext().getRealm();
242
243 }
244
245 /* ------------------------------------------------------------ */
246 public void stop()
247 {
248 if (_servlet!=null)
249 _servlet.destroy();
250 _servlet=null;
251
252 while (_servlets!=null && _servlets.size()>0)
253 {
254 Servlet s = (Servlet)_servlets.pop();
255 s.destroy();
256 }
257 _config=null;
258 super.stop();
259 }
260
261
262 /* ------------------------------------------------------------ */
263 /** Get the servlet.
264 * @return The servlet
265 */
266 public synchronized Servlet getServlet()
267 throws UnavailableException
268 {
269 // Handle previous unavailability
270 if (_unavailable!=0)
271 {
272 if (_unavailable<0 || _unavailable>0 && System.currentTimeMillis()<_unavailable)
273 throw _unavailableEx;
274 _unavailable=0;
275 _unavailableEx=null;
276 }
277
278 try
279 {
280 if (_servlets!=null)
281 {
282 Servlet servlet=null;
283 if (_servlets.size()==0)
284 {
285 servlet= (Servlet)newInstance();
286 servlet.init(_config);
287 }
288 else
289 servlet = (Servlet)_servlets.pop();
290
291 return servlet;
292 }
293
294 if (_servlet==null)
295 _servlet=(Servlet)newInstance();
296
297 if (_config==null)
298 {
299 _config=new Config();
300 _servlet.init(_config);
301 }
302
303 return _servlet;
304 }
305 catch(UnavailableException e)
306 {
307 _servlet=null;
308 _config=null;
309 _unavailableEx=e;
310 _unavailable=-1;
311 if (_unavailableEx.getUnavailableSeconds()>0)
312 _unavailable=System.currentTimeMillis()+
313 1000*_unavailableEx.getUnavailableSeconds();
314 throw _unavailableEx;
315 }
316 catch(Exception e)
317 {
318 _servlet=null;
319 _config=null;
320 log.warn(LogSupport.EXCEPTION,e);
321 throw new UnavailableException(_servlet,e.toString());
322 }
323 }
324
325 /* ------------------------------------------------------------ */
326 /** Service a request with this servlet.
327 */
328 public void handle(ServletRequest request,
329 ServletResponse response)
330 throws ServletException,
331 UnavailableException,
332 IOException
333 {
334 if (_class==null)
335 throw new UnavailableException("Servlet Not Initialized");
336
337 Servlet servlet=(!_initOnStartup||_servlets!=null)?getServlet():_servlet;
338 if (servlet==null)
339 throw new UnavailableException("Could not instantiate "+_class);
340
341 // Service the request
342 boolean servlet_error=true;
343 Principal user=null;
344 HttpRequest http_request=null;
345 try
346 {
347 // Handle aliased path
348 if (_forcedPath!=null)
349 request.setAttribute("javax.servlet.include.servlet_path",_forcedPath);
350
351 // Handle run as
352 if (_run_as!=null && _realm!=null)
353 {
354 ServletHttpRequest servletHttpRequest=
355 ServletHttpRequest.unwrap(request);
356 http_request=servletHttpRequest.getHttpRequest();
357
358 user=_realm.pushRole(http_request.getUserPrincipal(),_run_as);
359 http_request.setUserPrincipal(user);
360 }
361
362 servlet.service(request,response);
363 servlet_error=false;
364 }
365 catch(UnavailableException e)
366 {
367 if (_servlets!=null && servlet!=null)
368 servlet.destroy();
369 servlet=null;
370 throw e;
371 }
372 finally
373 {
374 // pop run-as role
375 if (_run_as!=null && _realm!=null && user!=null)
376 {
377 user=_realm.popRole(user);
378 http_request.setUserPrincipal(user);
379 }
380
381 // Handle error params.
382 if (servlet_error)
383 request.setAttribute("javax.servlet.error.servlet_name",getName());
384
385 // Return to singleThreaded pool
386 synchronized(this)
387 {
388 if (_servlets!=null && servlet!=null)
389 _servlets.push(servlet);
390 }
391 }
392 }
393
394 /* ------------------------------------------------------------ */
395 /* ------------------------------------------------------------ */
396 /* ------------------------------------------------------------ */
397 class Config implements ServletConfig
398 {
399 /* -------------------------------------------------------- */
400 public String getServletName()
401 {
402 return getName();
403 }
404
405 /* -------------------------------------------------------- */
406 public ServletContext getServletContext()
407 {
408 return ((ServletHandler)_httpHandler).getServletContext();
409 }
410
411 /* -------------------------------------------------------- */
412 public String getInitParameter(String param)
413 {
414 return ServletHolder.this.getInitParameter(param);
415 }
416
417 /* -------------------------------------------------------- */
418 public Enumeration getInitParameterNames()
419 {
420 return ServletHolder.this.getInitParameterNames();
421 }
422 }
423 }
424
425
426
427
428