Annotation of java/classes/org/w3c/jigsaw/servlet/ServletWrapper.java, revision 1.55
1.1 abaird 1: // ServletWrapper.java
1.55 ! ylafon 2: // $Id: ServletWrapper.java,v 1.54 2000/09/06 13:18:16 bmahe Exp $
1.1 abaird 3: // (c) COPYRIGHT MIT and INRIA, 1996.
4: // Please first read the full copyright statement in file COPYRIGHT.html
5:
1.18 bmahe 6: package org.w3c.jigsaw.servlet;
1.1 abaird 7:
1.51 ylafon 8: import java.io.File;
9: import java.io.IOException;
10: import java.io.PrintStream;
11:
12: import java.util.Enumeration;
13:
14: import javax.servlet.Servlet;
15: import javax.servlet.ServletConfig;
16: import javax.servlet.ServletContext;
17: import javax.servlet.ServletException;
18: import javax.servlet.SingleThreadModel;
19:
20: import org.w3c.tools.timers.EventHandler;
21: import org.w3c.tools.timers.EventManager;
22:
23: import org.w3c.util.ArrayDictionary;
24: import org.w3c.util.EmptyEnumeration;
25:
26: import org.w3c.jigsaw.http.Reply;
27: import org.w3c.jigsaw.http.Request;
28: import org.w3c.jigsaw.http.httpd;
29:
30: import org.w3c.tools.resources.Attribute;
31: import org.w3c.tools.resources.AttributeHolder;
32: import org.w3c.tools.resources.AttributeRegistry;
33: import org.w3c.tools.resources.FramedResource;
34: import org.w3c.tools.resources.InvalidResourceException;
35: import org.w3c.tools.resources.LongAttribute;
36: import org.w3c.tools.resources.ObjectAttribute;
37: import org.w3c.tools.resources.PropertiesAttribute;
38: import org.w3c.tools.resources.Resource;
39: import org.w3c.tools.resources.ResourceReference;
40: import org.w3c.tools.resources.ServerInterface;
41: import org.w3c.tools.resources.StringAttribute;
1.1 abaird 42:
1.2 abaird 43: /**
44: * @author Alexandre Rafalovitch <alex@access.com.au>
45: * @author Anselm Baird-Smith <abaird@w3.org>
1.18 bmahe 46: * @author Benoit Mahe <bmahe@w3.org>
1.2 abaird 47: */
48:
1.40 bmahe 49: public class ServletWrapper extends FramedResource
50: implements ServletConfig
1.1 abaird 51: {
52:
1.40 bmahe 53: protected class TimeoutManager implements EventHandler {
54:
55: private Object timer = null;
56: private httpd server = null;
57:
58: /**
59: * Handle timer events.
60: * @param data The timer closure.
61: * @param time The absolute time at which the event was triggered.
62: * @see org.w3c.tools.timers.EventManager
63: * @see org.w3c.tools.timers.EventHandler
64: */
65: public synchronized void handleTimerEvent(Object data, long time) {
66: timer = null;
67: destroyServlet();
68: }
69:
70: private synchronized void setTimer(long ms) {
71: if ( timer != null ) {
72: server.timer.recallTimer(timer) ;
73: timer = null ;
74: }
75: timer = server.timer.registerTimer(ms, this, null);
76: }
77:
78: protected void restart() {
79: start();
80: }
81:
82: protected void start() {
1.45 bmahe 83: long timeout = getServletTimeout();
84: if (timeout != -1)
85: setTimer(getServletTimeout());
1.40 bmahe 86: }
87:
88: protected synchronized void stop() {
89: if ( timer != null ) {
90: server.timer.recallTimer(timer) ;
91: timer = null;
92: }
93: }
94:
95: TimeoutManager(httpd server) {
96: this.server = server;
97: }
98:
99: }
100:
101: protected TimeoutManager timeoutManager = null;
102:
1.46 bmahe 103: protected int connections = 0;
104:
1.40 bmahe 105: protected final static boolean debug = false;
1.9 bmahe 106:
1.20 bmahe 107: /**
108: * Attributes index - The servlet class name.
109: */
110: protected static int ATTR_SERVLET_CLASS = -1 ;
111: /**
1.40 bmahe 112: * Attributes index - The servlet timeout
113: */
114: protected static int ATTR_SERVLET_TIMEOUT = -1 ;
115: /**
1.20 bmahe 116: * Attribute index - The init parameters for that servlet.
117: */
118: protected static int ATTR_PARAMETERS = 1;
119: /**
120: * Attribute index - Our parent-inherited servlet context.
121: */
122: protected static int ATTR_SERVLET_CONTEXT = -1;
123: /**
1.28 bmahe 124: * Attribute index - Our parent-inherited session context.
125: */
126: protected static int ATTR_SESSION_CONTEXT = -1;
1.20 bmahe 127:
128: static {
129: Attribute a = null ;
130: Class cls = null ;
131: try {
132: cls = Class.forName("org.w3c.jigsaw.servlet.ServletWrapper") ;
133: } catch (Exception ex) {
134: ex.printStackTrace();
135: System.exit(0);
136: }
137: // The servlet class attribute.
138: a = new StringAttribute("servlet-class"
1.1 abaird 139: , null
1.20 bmahe 140: , Attribute.EDITABLE | Attribute.MANDATORY) ;
141: ATTR_SERVLET_CLASS = AttributeRegistry.registerAttribute(cls, a) ;
142: // This servlet init parameters
143: a = new PropertiesAttribute("servlet-parameters"
144: , null
145: , Attribute.EDITABLE);
146: ATTR_PARAMETERS = AttributeRegistry.registerAttribute(cls, a);
147: // Our servlet context:
148: a = new ObjectAttribute("servlet-context",
1.24 bmahe 149: "org.w3c.jigsaw.servlet.JigsawServletContext",
1.20 bmahe 150: null,
151: Attribute.DONTSAVE);
152: ATTR_SERVLET_CONTEXT = AttributeRegistry.registerAttribute(cls, a);
1.28 bmahe 153: // Our session context:
154: a = new ObjectAttribute("session-context",
155: "org.w3c.jigsaw.servlet.JigsawHttpSessionContext",
156: null,
157: Attribute.DONTSAVE);
158: ATTR_SESSION_CONTEXT = AttributeRegistry.registerAttribute(cls, a);
1.40 bmahe 159: // The servlet timeout:
160: a = new LongAttribute("servlet-timeout",
161: null,
162: Attribute.EDITABLE);
163: ATTR_SERVLET_TIMEOUT = AttributeRegistry.registerAttribute(cls, a);
164:
1.20 bmahe 165: }
1.51 ylafon 166:
1.20 bmahe 167: /**
168: * The servlet wrapped within that Jigsaw resource.
169: */
170: protected Servlet servlet = null;
171: /**
172: * Is out servler initialized ?
173: */
174: protected boolean inited = false;
175:
176: /**
177: * The Path where we can find the servlet class file.
178: */
179: public File getServletDirectory() {
1.25 bmahe 180: ResourceReference rr = getParent();
181: if (rr != null) {
182: try {
183: Resource parent = rr.lock();
184: if (parent.definesAttribute("directory"))
185: return (File) parent.getValue("directory", null);
186: } catch(InvalidResourceException ex) {
187: ex.printStackTrace();
188: } finally {
189: rr.unlock();
190: }
191: }
192: return null;
1.20 bmahe 193: }
194:
195: /**
196: * Servlet stub implementation - Get an init parameter value.
197: */
198:
199: public synchronized String getInitParameter(String string) {
200: ArrayDictionary d = getServletParameters();
201: String v = (d != null) ? (String) d.get(string) : null;
202: return v;
203: }
204:
205: /**
206: * Servlet stub implementation - Get all init parameters.
207: */
208:
209: public synchronized Enumeration getInitParameterNames() {
210: // Convert init parameters to hashtable:
211: ArrayDictionary d = getServletParameters();
212: return (d != null) ? d.keys() : new EmptyEnumeration();
213: }
214:
215: /**
216: * Servlet stub implementation - Get that servlet context.
217: */
218:
219: public ServletContext getServletContext() {
1.52 bmahe 220: ServletContext ctxt =
221: (ServletContext) getValue(ATTR_SERVLET_CONTEXT, null);
222: return ctxt;
1.20 bmahe 223: }
224:
1.28 bmahe 225: public JigsawHttpSessionContext getSessionContext() {
226: return (JigsawHttpSessionContext) getValue(ATTR_SESSION_CONTEXT, null);
227: }
228:
1.40 bmahe 229: protected long getServletTimeout() {
1.45 bmahe 230: long timeout = getLong(ATTR_SERVLET_TIMEOUT, 0);
231: if (timeout == 0) {
1.40 bmahe 232: JigsawServletContext ctxt =
233: (JigsawServletContext) getServletContext();
234: timeout = ctxt.getServletTimeout();
235: }
236: return timeout;
237: }
238:
1.36 bmahe 239: protected void invalidateAllSession() {
240: if (debug)
241: System.out.println("Invalidate All Session...");
242: JigsawHttpSessionContext ctxt = getSessionContext();
243: Enumeration enum = ctxt.getIds();
244: while (enum.hasMoreElements())
245: ctxt.getSession((String)enum.nextElement()).invalidate();
246: }
247:
1.37 bmahe 248: /**
249: * Check the servlet class, ans try to initialize it.
250: * @exception ClassNotFoundException if servlet class can't be found.
251: * @exception ServletException if servlet can't be initialized.
252: */
1.36 bmahe 253: protected void checkServlet()
254: throws ClassNotFoundException, ServletException
255: {
256: boolean classmodified =
257: getLocalServletLoader().classChanged(getServletClass());
258:
1.47 bmahe 259: if ((! inited) ||
260: classmodified ||
1.36 bmahe 261: (servlet.getClass() !=
262: getLocalServletLoader().loadClass(getServletClass())))
263: {
264: inited = launchServlet();
265: }
1.20 bmahe 266: }
267:
268: protected boolean isInited() {
269: return inited;
270: }
271:
1.55 ! ylafon 272: private class ServletRunner extends Thread {
! 273: Servlet srServlet;
! 274: JigsawHttpServletRequest srReq;
! 275: JigsawHttpServletResponse srResp;
! 276:
! 277: public void run() {
! 278: try {
! 279: srServlet.service(srReq , srResp);
! 280: srResp.flushStream(true);
! 281: } catch (Exception ex) {
! 282: ex.printStackTrace();
! 283: }
! 284: }
! 285:
! 286: ServletRunner(Servlet servlet,
! 287: JigsawHttpServletRequest request,
! 288: JigsawHttpServletResponse response) {
! 289: srServlet = servlet;
! 290: srReq = request;
! 291: srResp = response;
! 292: setName("ServletRunner");
! 293: start();
! 294: }
! 295: }
! 296:
1.20 bmahe 297: protected void service(Request request, Reply reply)
298: throws ServletException, IOException
299: {
1.23 bmahe 300: JigsawHttpServletResponse jRes = null;
301: JigsawHttpServletRequest jReq = null;
302: if (servlet instanceof SingleThreadModel) {
303: synchronized (this) {
304: jRes = new JigsawHttpServletResponse(request, reply);
1.28 bmahe 305: jReq = new JigsawHttpServletRequest(servlet,
306: request,
307: jRes,
308: getSessionContext());
309: jRes.setServletRequest(jReq);
1.46 bmahe 310: try {
311: connections++;
1.55 ! ylafon 312: // FIXME we should reuse a thread rather than
! 313: // reallocating one for every hit
! 314: new ServletRunner(servlet, jReq, jRes);
1.46 bmahe 315: } finally {
316: connections--;
317: }
1.23 bmahe 318: }
319: } else {
1.31 bmahe 320: jRes = new JigsawHttpServletResponse(request, reply);
321: jReq = new JigsawHttpServletRequest(servlet,
322: request,
323: jRes,
324: getSessionContext());
325: jRes.setServletRequest(jReq);
1.46 bmahe 326: try {
327: connections++;
1.55 ! ylafon 328: // FIXME we should reuse a thread rather than
! 329: // reallocating one for every hit
! 330: new ServletRunner(servlet, jReq, jRes);
1.46 bmahe 331: } finally {
332: connections--;
333: }
1.23 bmahe 334: }
1.40 bmahe 335: timeoutManager.restart();
1.20 bmahe 336: }
337:
338: /**
339: * Get the class name of the wrapped servlet.
340: * @return The class name for the servlet if attribute is defined.
341: * Otherwise the class name is deduced from the resource identifier.
342: */
343:
344: public String getServletClass()
345: {
346: String sclass = getString(ATTR_SERVLET_CLASS, null);
347: if (sclass == null) {
348: String ident = getIdentifier();
349: if (ident.endsWith(".class"))
350: sclass = ident;
351: }
352: return sclass;
353: }
354:
355: /**
356: * Get the init parameters for our wrapped servlet.
357: * @return An ArrayDictionary instance if the attribute is defined,
358: * <strong>false</strong> otherwise.
359: */
360:
361: public ArrayDictionary getServletParameters() {
362: return (ArrayDictionary) getValue(ATTR_PARAMETERS, null);
363: }
364:
1.26 bmahe 365: protected void setValueOfSuperClass(int idx, Object value) {
366: super.setValue(idx, value);
367: }
368:
1.20 bmahe 369: /**
370: * Catch assignements to the servlet class name attribute.
371: * <p>When a change to that attribute is detected, the servlet is
372: * automatically reinitialized.
373: */
374:
375: public void setValue(int idx, Object value) {
376: super.setValue(idx, value);
1.44 bmahe 377: if (((idx == ATTR_SERVLET_CLASS) && (value != null)) ||
378: (idx == ATTR_PARAMETERS)) {
1.36 bmahe 379: try {
380: inited = launchServlet();
381: } catch (Exception ex) {
382: String msg = ("unable to set servlet class \""+
383: getServletClass()+
384: "\" : "+
385: ex.getMessage());
386: getServer().errlog(msg);
387: }
1.40 bmahe 388: } if (idx == ATTR_SERVLET_TIMEOUT) {
389: timeoutManager.restart();
1.36 bmahe 390: }
1.20 bmahe 391: }
392:
393: /**
394: * Destroy the servlet we are wrapping.
395: */
396:
397: protected synchronized void destroyServlet() {
1.46 bmahe 398: if ((servlet != null) && (connections < 1)) {
1.20 bmahe 399: servlet.destroy();
400: servlet = null;
1.47 bmahe 401: inited = false;
1.20 bmahe 402: }
403: }
404:
405: /**
406: * Get the servlet we are wrapping.
407: * @return A servlet instance, if the servlet is alredy running,
408: * <strong>null</strong> otherwise.
409: */
410:
1.34 bmahe 411: public synchronized Servlet getServlet() {
1.36 bmahe 412: try {
413: checkServlet();
414: } catch (Exception ex) {
415: if (debug)
416: ex.printStackTrace();
417: }
1.20 bmahe 418: return servlet;
419: }
420:
421: /**
422: * Initialize our servlet from the given (loaded) class.
423: * @param cls The servlet loaded main class.
424: * @return A boolean, <strong>true</strong> if servlet was successfully
425: * initialised, <strong>false</strong> otherwise.
1.37 bmahe 426: * @exception ServletException if servlet can't be initialized.
1.20 bmahe 427: */
428:
1.36 bmahe 429: protected boolean launchServlet(Class cls)
430: throws ServletException
431: {
1.50 bmahe 432: if (debug) {
433: System.out.println("launching Servlet: "+getServletName());
434: }
1.20 bmahe 435: try {
436: servlet = (Servlet) cls.newInstance();
437: servlet.init((ServletConfig) this);
1.40 bmahe 438: timeoutManager.restart();
1.36 bmahe 439: } catch (IllegalAccessException ex) {
440: String msg = ("Illegal access during servlet instantiation, "+
1.34 bmahe 441: ex.getClass().getName()+": "+
1.20 bmahe 442: ex.getMessage());
443: if ( debug )
444: ex.printStackTrace();
445: getServer().errlog(this, msg);
446: return false;
1.36 bmahe 447: } catch (InstantiationException iex) {
448: String msg = ("unable to instantiate servlet, "+
449: iex.getClass().getName()+": "+
450: iex.getMessage());
451: if ( debug )
452: iex.printStackTrace();
453: getServer().errlog(this, msg);
454: return false;
1.20 bmahe 455: }
456: return (servlet != null) ;
1.32 bmahe 457: }
458:
459: /**
460: * Check if the Servletclass wrapped is a Servlet class without
1.36 bmahe 461: * initializing it. (not the same than checkServlet).
1.33 bmahe 462: * used by the ServletIndexer.
463: * @see org.w3c.jigsaw.servlet.ServletIndexer
1.32 bmahe 464: * @return A boolean.
465: */
466: protected boolean isWrappingAServlet() {
467: String clsname = getServletClass();
468: if ( clsname == null )
469: return false;
470: Class c = null;
471: try {
1.34 bmahe 472: c = getLocalServletLoader().loadClass(clsname, true);
1.32 bmahe 473: Object o = c.newInstance();
474: return (o instanceof Servlet);
475: } catch (Exception ex) {
476: return false;
477: }
1.20 bmahe 478: }
479:
480: /**
481: * Launch the servlet we are wrapping.
482: * <p>This method either succeed, or the wrapper resource itself will fail
483: * to initialize, acting as transparently as possible (in some sense).
484: * @return A boolean, <strong>true</strong> if servlet launched.
1.37 bmahe 485: * @exception ClassNotFoundException if servlet class can't be found.
486: * @exception ServletException if servlet can't be initialized.
1.20 bmahe 487: */
488:
1.36 bmahe 489: protected boolean launchServlet()
490: throws ClassNotFoundException, ServletException
491: {
1.20 bmahe 492: // Get and check the servlet class:
493: if ( servlet != null )
494: destroyServlet();
495: String clsname = getServletClass();
496: if ( clsname == null ) {
497: getServer().errlog(this, "no servlet class attribute defined.");
498: return false;
499: } else {
500: Class c = null;
501: try {
1.36 bmahe 502: if (getLocalServletLoader().classChanged(clsname)) {
1.34 bmahe 503: createNewLocalServletLoader(true);
1.36 bmahe 504: invalidateAllSession();
505: }
1.34 bmahe 506: c = getLocalServletLoader().loadClass(clsname, true);
1.20 bmahe 507: } catch (ClassNotFoundException ex) {
1.36 bmahe 508: String msg = ("unable to find servlet class \""+
509: getServletClass()+"\"");
1.20 bmahe 510: getServer().errlog(msg);
1.36 bmahe 511: // re throw the exception
512: throw ex;
1.20 bmahe 513: }
514: return (c != null) ? launchServlet(c) : false;
515: }
516: }
517:
1.40 bmahe 518: public boolean acceptUnload() {
519: return (servlet == null);
520: }
521:
1.20 bmahe 522: public void notifyUnload() {
1.42 bmahe 523: if (timeoutManager != null)
524: timeoutManager.stop();
1.20 bmahe 525: destroyServlet();
1.26 bmahe 526: }
527:
528: /**
529: * Get or create a suitable LocalServletLoader instance to load
530: * that servlet.
531: * @return A LocalServletLoader instance.
532: */
533:
1.34 bmahe 534: protected synchronized AutoReloadServletLoader getLocalServletLoader() {
535: JigsawServletContext ctxt = (JigsawServletContext) getServletContext();
536: return ctxt.getLocalServletLoader();
1.26 bmahe 537: }
538:
1.34 bmahe 539: protected
540: AutoReloadServletLoader createNewLocalServletLoader(boolean keepold)
1.26 bmahe 541: {
1.34 bmahe 542: JigsawServletContext ctxt = (JigsawServletContext) getServletContext();
543: return ctxt.createNewLocalServletLoader(keepold);
1.20 bmahe 544: }
545:
546: /**
1.48 bmahe 547: * Returns the name of this servlet instance.
548: * The name may be provided via server administration, assigned in the
549: * web application deployment descriptor, or for an unregistered (and thus
550: * unnamed) servlet instance it will be the servlet's class name.
551: * @return the name of the servlet instance
552: */
553: public String getServletName() {
554: return getIdentifier();
555: }
556:
557: /**
1.20 bmahe 558: * Initialize this servlet wrapper resource.
559: * After the wrapper itself is inited, it performs the servlet
560: * initialzation.
561: * @param values The default attribute values.
562: */
563: public void initialize(Object values[]) {
564: super.initialize(values);
1.46 bmahe 565: connections = 0;
1.41 bmahe 566:
567: if (getServletContext() != null) {
568: timeoutManager = new TimeoutManager((httpd)getServer());
569: timeoutManager.start();
570: }
1.40 bmahe 571:
1.20 bmahe 572: try {
573: registerFrameIfNone("org.w3c.jigsaw.servlet.ServletWrapperFrame",
574: "servlet-wrapper-frame");
575: } catch (Exception ex) {
576: ex.printStackTrace();
577: }
1.40 bmahe 578:
1.18 bmahe 579: }
1.1 abaird 580:
581: }
582:
583:
Webmaster