Annotation of java/classes/org/w3c/jigsaw/servlet/ServletWrapper.java, revision 1.46.4.6
1.1 abaird 1: // ServletWrapper.java
1.46.4.6! bmahe 2: // $Id: ServletWrapper.java,v 1.53 2000/09/05 17:17:23 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.46.4.5 bmahe 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.46.4.5 bmahe 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.46.4.5 bmahe 220: ServletContext ctxt =
221: (ServletContext) getValue(ATTR_SERVLET_CONTEXT, null);
1.46.4.6! bmahe 222: if (ctxt == null) {
! 223: System.err.println("No servlet context available, check "+
! 224: "that the servlet ["+
! 225: getIdentifier()+
! 226: "] container has a "+
! 227: "ServletDirectoryFrame");
! 228: }
1.46.4.5 bmahe 229: return ctxt;
1.20 bmahe 230: }
231:
1.28 bmahe 232: public JigsawHttpSessionContext getSessionContext() {
233: return (JigsawHttpSessionContext) getValue(ATTR_SESSION_CONTEXT, null);
234: }
235:
1.40 bmahe 236: protected long getServletTimeout() {
1.45 bmahe 237: long timeout = getLong(ATTR_SERVLET_TIMEOUT, 0);
238: if (timeout == 0) {
1.40 bmahe 239: JigsawServletContext ctxt =
240: (JigsawServletContext) getServletContext();
241: timeout = ctxt.getServletTimeout();
242: }
243: return timeout;
244: }
245:
1.36 bmahe 246: protected void invalidateAllSession() {
247: if (debug)
248: System.out.println("Invalidate All Session...");
249: JigsawHttpSessionContext ctxt = getSessionContext();
250: Enumeration enum = ctxt.getIds();
251: while (enum.hasMoreElements())
252: ctxt.getSession((String)enum.nextElement()).invalidate();
253: }
254:
1.37 bmahe 255: /**
256: * Check the servlet class, ans try to initialize it.
257: * @exception ClassNotFoundException if servlet class can't be found.
258: * @exception ServletException if servlet can't be initialized.
259: */
1.36 bmahe 260: protected void checkServlet()
261: throws ClassNotFoundException, ServletException
262: {
263: boolean classmodified =
264: getLocalServletLoader().classChanged(getServletClass());
265:
1.46.4.1 bmahe 266: if ((! inited) ||
267: classmodified ||
1.36 bmahe 268: (servlet.getClass() !=
269: getLocalServletLoader().loadClass(getServletClass())))
270: {
271: inited = launchServlet();
272: }
1.20 bmahe 273: }
274:
275: protected boolean isInited() {
276: return inited;
277: }
278:
279: protected void service(Request request, Reply reply)
280: throws ServletException, IOException
281: {
1.23 bmahe 282: JigsawHttpServletResponse jRes = null;
283: JigsawHttpServletRequest jReq = null;
284: if (servlet instanceof SingleThreadModel) {
285: synchronized (this) {
286: jRes = new JigsawHttpServletResponse(request, reply);
1.28 bmahe 287: jReq = new JigsawHttpServletRequest(servlet,
288: request,
289: jRes,
290: getSessionContext());
291: jRes.setServletRequest(jReq);
1.46 bmahe 292: try {
293: connections++;
294: servlet.service(jReq , jRes);
295: } finally {
296: connections--;
297: }
1.39 bmahe 298: jRes.flushStream(true);
1.23 bmahe 299: }
300: } else {
1.31 bmahe 301: jRes = new JigsawHttpServletResponse(request, reply);
302: jReq = new JigsawHttpServletRequest(servlet,
303: request,
304: jRes,
305: getSessionContext());
306: jRes.setServletRequest(jReq);
1.46 bmahe 307: try {
308: connections++;
309: servlet.service(jReq , jRes);
310: } finally {
311: connections--;
312: }
1.39 bmahe 313: jRes.flushStream(true);
1.23 bmahe 314: }
1.40 bmahe 315: timeoutManager.restart();
1.20 bmahe 316: }
317:
318: /**
319: * Get the class name of the wrapped servlet.
320: * @return The class name for the servlet if attribute is defined.
321: * Otherwise the class name is deduced from the resource identifier.
322: */
323:
324: public String getServletClass()
325: {
326: String sclass = getString(ATTR_SERVLET_CLASS, null);
327: if (sclass == null) {
328: String ident = getIdentifier();
329: if (ident.endsWith(".class"))
330: sclass = ident;
331: }
332: return sclass;
333: }
334:
335: /**
336: * Get the init parameters for our wrapped servlet.
337: * @return An ArrayDictionary instance if the attribute is defined,
338: * <strong>false</strong> otherwise.
339: */
340:
341: public ArrayDictionary getServletParameters() {
342: return (ArrayDictionary) getValue(ATTR_PARAMETERS, null);
343: }
344:
1.26 bmahe 345: protected void setValueOfSuperClass(int idx, Object value) {
346: super.setValue(idx, value);
347: }
348:
1.20 bmahe 349: /**
350: * Catch assignements to the servlet class name attribute.
351: * <p>When a change to that attribute is detected, the servlet is
352: * automatically reinitialized.
353: */
354:
355: public void setValue(int idx, Object value) {
356: super.setValue(idx, value);
1.44 bmahe 357: if (((idx == ATTR_SERVLET_CLASS) && (value != null)) ||
358: (idx == ATTR_PARAMETERS)) {
1.36 bmahe 359: try {
360: inited = launchServlet();
361: } catch (Exception ex) {
362: String msg = ("unable to set servlet class \""+
363: getServletClass()+
364: "\" : "+
365: ex.getMessage());
366: getServer().errlog(msg);
367: }
1.40 bmahe 368: } if (idx == ATTR_SERVLET_TIMEOUT) {
369: timeoutManager.restart();
1.36 bmahe 370: }
1.20 bmahe 371: }
372:
373: /**
374: * Destroy the servlet we are wrapping.
375: */
376:
377: protected synchronized void destroyServlet() {
1.46 bmahe 378: if ((servlet != null) && (connections < 1)) {
1.20 bmahe 379: servlet.destroy();
380: servlet = null;
1.46.4.1 bmahe 381: inited = false;
1.20 bmahe 382: }
383: }
384:
385: /**
386: * Get the servlet we are wrapping.
387: * @return A servlet instance, if the servlet is alredy running,
388: * <strong>null</strong> otherwise.
389: */
390:
1.34 bmahe 391: public synchronized Servlet getServlet() {
1.36 bmahe 392: try {
393: checkServlet();
394: } catch (Exception ex) {
395: if (debug)
396: ex.printStackTrace();
397: }
1.20 bmahe 398: return servlet;
399: }
400:
401: /**
402: * Initialize our servlet from the given (loaded) class.
403: * @param cls The servlet loaded main class.
404: * @return A boolean, <strong>true</strong> if servlet was successfully
405: * initialised, <strong>false</strong> otherwise.
1.37 bmahe 406: * @exception ServletException if servlet can't be initialized.
1.20 bmahe 407: */
408:
1.36 bmahe 409: protected boolean launchServlet(Class cls)
410: throws ServletException
411: {
1.46.4.4 bmahe 412: if (debug) {
413: System.out.println("launching Servlet: "+getServletName());
414: }
1.20 bmahe 415: try {
416: servlet = (Servlet) cls.newInstance();
417: servlet.init((ServletConfig) this);
1.40 bmahe 418: timeoutManager.restart();
1.36 bmahe 419: } catch (IllegalAccessException ex) {
420: String msg = ("Illegal access during servlet instantiation, "+
1.34 bmahe 421: ex.getClass().getName()+": "+
1.20 bmahe 422: ex.getMessage());
423: if ( debug )
424: ex.printStackTrace();
425: getServer().errlog(this, msg);
426: return false;
1.36 bmahe 427: } catch (InstantiationException iex) {
428: String msg = ("unable to instantiate servlet, "+
429: iex.getClass().getName()+": "+
430: iex.getMessage());
431: if ( debug )
432: iex.printStackTrace();
433: getServer().errlog(this, msg);
434: return false;
1.20 bmahe 435: }
436: return (servlet != null) ;
1.32 bmahe 437: }
438:
439: /**
440: * Check if the Servletclass wrapped is a Servlet class without
1.36 bmahe 441: * initializing it. (not the same than checkServlet).
1.33 bmahe 442: * used by the ServletIndexer.
443: * @see org.w3c.jigsaw.servlet.ServletIndexer
1.32 bmahe 444: * @return A boolean.
445: */
446: protected boolean isWrappingAServlet() {
447: String clsname = getServletClass();
448: if ( clsname == null )
449: return false;
450: Class c = null;
451: try {
1.34 bmahe 452: c = getLocalServletLoader().loadClass(clsname, true);
1.32 bmahe 453: Object o = c.newInstance();
454: return (o instanceof Servlet);
455: } catch (Exception ex) {
456: return false;
457: }
1.20 bmahe 458: }
459:
460: /**
461: * Launch the servlet we are wrapping.
462: * <p>This method either succeed, or the wrapper resource itself will fail
463: * to initialize, acting as transparently as possible (in some sense).
464: * @return A boolean, <strong>true</strong> if servlet launched.
1.37 bmahe 465: * @exception ClassNotFoundException if servlet class can't be found.
466: * @exception ServletException if servlet can't be initialized.
1.20 bmahe 467: */
468:
1.36 bmahe 469: protected boolean launchServlet()
470: throws ClassNotFoundException, ServletException
471: {
1.20 bmahe 472: // Get and check the servlet class:
473: if ( servlet != null )
474: destroyServlet();
475: String clsname = getServletClass();
476: if ( clsname == null ) {
477: getServer().errlog(this, "no servlet class attribute defined.");
478: return false;
479: } else {
480: Class c = null;
481: try {
1.36 bmahe 482: if (getLocalServletLoader().classChanged(clsname)) {
1.34 bmahe 483: createNewLocalServletLoader(true);
1.36 bmahe 484: invalidateAllSession();
485: }
1.34 bmahe 486: c = getLocalServletLoader().loadClass(clsname, true);
1.20 bmahe 487: } catch (ClassNotFoundException ex) {
1.36 bmahe 488: String msg = ("unable to find servlet class \""+
489: getServletClass()+"\"");
1.20 bmahe 490: getServer().errlog(msg);
1.36 bmahe 491: // re throw the exception
492: throw ex;
1.20 bmahe 493: }
494: return (c != null) ? launchServlet(c) : false;
495: }
496: }
497:
1.40 bmahe 498: public boolean acceptUnload() {
499: return (servlet == null);
500: }
501:
1.20 bmahe 502: public void notifyUnload() {
1.42 bmahe 503: if (timeoutManager != null)
504: timeoutManager.stop();
1.20 bmahe 505: destroyServlet();
1.26 bmahe 506: }
507:
508: /**
509: * Get or create a suitable LocalServletLoader instance to load
510: * that servlet.
511: * @return A LocalServletLoader instance.
512: */
513:
1.34 bmahe 514: protected synchronized AutoReloadServletLoader getLocalServletLoader() {
515: JigsawServletContext ctxt = (JigsawServletContext) getServletContext();
516: return ctxt.getLocalServletLoader();
1.26 bmahe 517: }
518:
1.34 bmahe 519: protected
520: AutoReloadServletLoader createNewLocalServletLoader(boolean keepold)
1.26 bmahe 521: {
1.34 bmahe 522: JigsawServletContext ctxt = (JigsawServletContext) getServletContext();
523: return ctxt.createNewLocalServletLoader(keepold);
1.20 bmahe 524: }
525:
526: /**
1.46.4.2 bmahe 527: * Returns the name of this servlet instance.
528: * The name may be provided via server administration, assigned in the
529: * web application deployment descriptor, or for an unregistered (and thus
530: * unnamed) servlet instance it will be the servlet's class name.
531: * @return the name of the servlet instance
532: */
533: public String getServletName() {
534: return getIdentifier();
535: }
536:
537: /**
1.20 bmahe 538: * Initialize this servlet wrapper resource.
539: * After the wrapper itself is inited, it performs the servlet
540: * initialzation.
541: * @param values The default attribute values.
542: */
543: public void initialize(Object values[]) {
544: super.initialize(values);
1.46 bmahe 545: connections = 0;
1.41 bmahe 546:
547: if (getServletContext() != null) {
548: timeoutManager = new TimeoutManager((httpd)getServer());
549: timeoutManager.start();
550: }
1.40 bmahe 551:
1.20 bmahe 552: try {
553: registerFrameIfNone("org.w3c.jigsaw.servlet.ServletWrapperFrame",
554: "servlet-wrapper-frame");
555: } catch (Exception ex) {
556: ex.printStackTrace();
557: }
1.40 bmahe 558:
1.18 bmahe 559: }
1.1 abaird 560:
561: }
562:
563:
Webmaster