Annotation of java/classes/org/w3c/jigsaw/servlet/ServletWrapper.java, revision 1.60
1.1 abaird 1: // ServletWrapper.java
1.60 ! ylafon 2: // $Id: ServletWrapper.java,v 1.50 2001/10/30 00:28:00 tk 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;
1.59 ylafon 13: import java.util.LinkedList;
14: import java.util.NoSuchElementException;
1.51 ylafon 15:
16: import javax.servlet.Servlet;
17: import javax.servlet.ServletConfig;
18: import javax.servlet.ServletContext;
19: import javax.servlet.ServletException;
20: import javax.servlet.SingleThreadModel;
1.56 ylafon 21: import javax.servlet.UnavailableException;
1.51 ylafon 22:
23: import org.w3c.tools.timers.EventHandler;
24: import org.w3c.tools.timers.EventManager;
25:
26: import org.w3c.util.ArrayDictionary;
27: import org.w3c.util.EmptyEnumeration;
28:
29: import org.w3c.jigsaw.http.Reply;
30: import org.w3c.jigsaw.http.Request;
31: import org.w3c.jigsaw.http.httpd;
32:
33: import org.w3c.tools.resources.Attribute;
34: import org.w3c.tools.resources.AttributeHolder;
35: import org.w3c.tools.resources.AttributeRegistry;
36: import org.w3c.tools.resources.FramedResource;
37: import org.w3c.tools.resources.InvalidResourceException;
1.59 ylafon 38: import org.w3c.tools.resources.IntegerAttribute;
1.51 ylafon 39: import org.w3c.tools.resources.LongAttribute;
40: import org.w3c.tools.resources.ObjectAttribute;
41: import org.w3c.tools.resources.PropertiesAttribute;
42: import org.w3c.tools.resources.Resource;
43: import org.w3c.tools.resources.ResourceReference;
44: import org.w3c.tools.resources.ServerInterface;
45: import org.w3c.tools.resources.StringAttribute;
1.1 abaird 46:
1.56 ylafon 47: import org.w3c.www.http.HTTP;
48:
1.2 abaird 49: /**
50: * @author Alexandre Rafalovitch <alex@access.com.au>
51: * @author Anselm Baird-Smith <abaird@w3.org>
1.18 bmahe 52: * @author Benoit Mahe <bmahe@w3.org>
1.2 abaird 53: */
54:
1.40 bmahe 55: public class ServletWrapper extends FramedResource
56: implements ServletConfig
1.1 abaird 57: {
58:
1.40 bmahe 59: protected class TimeoutManager implements EventHandler {
60:
61: private Object timer = null;
62: private httpd server = null;
63:
64: /**
65: * Handle timer events.
66: * @param data The timer closure.
67: * @param time The absolute time at which the event was triggered.
68: * @see org.w3c.tools.timers.EventManager
69: * @see org.w3c.tools.timers.EventHandler
70: */
71: public synchronized void handleTimerEvent(Object data, long time) {
72: timer = null;
1.60 ! ylafon 73: // FIXME, each servlet instance available should have its
! 74: // individual timeout manager.
! 75: // Thus, resources could be released as required. This mechanism
! 76: // would opt for a more fine grained servlet instance management.
1.40 bmahe 77: destroyServlet();
78: }
79:
80: private synchronized void setTimer(long ms) {
81: if ( timer != null ) {
82: server.timer.recallTimer(timer) ;
83: timer = null ;
84: }
85: timer = server.timer.registerTimer(ms, this, null);
86: }
87:
88: protected void restart() {
89: start();
90: }
91:
92: protected void start() {
1.45 bmahe 93: long timeout = getServletTimeout();
94: if (timeout != -1)
1.59 ylafon 95: setTimer(timeout);
1.40 bmahe 96: }
97:
98: protected synchronized void stop() {
99: if ( timer != null ) {
100: server.timer.recallTimer(timer) ;
101: timer = null;
102: }
103: }
104:
105: TimeoutManager(httpd server) {
106: this.server = server;
107: }
108:
109: }
110:
1.57 ylafon 111: public static final String RUNNER = "org.w3c.jigsaw.servlet.runner";
112:
1.40 bmahe 113: protected TimeoutManager timeoutManager = null;
114:
1.60 ! ylafon 115: // protected int connections = 0;
1.46 bmahe 116:
1.40 bmahe 117: protected final static boolean debug = false;
1.9 bmahe 118:
1.20 bmahe 119: /**
120: * Attributes index - The servlet class name.
121: */
122: protected static int ATTR_SERVLET_CLASS = -1 ;
123: /**
1.40 bmahe 124: * Attributes index - The servlet timeout
125: */
126: protected static int ATTR_SERVLET_TIMEOUT = -1 ;
127: /**
1.60 ! ylafon 128: * Attributes index - The servlet maxinstances for single thread model
! 129: * servlet instance pool size limitation, tk, 20.10.2001
1.59 ylafon 130: */
131: protected static int ATTR_SERVLET_INSTANCEMAX = -1 ;
132: /**
1.20 bmahe 133: * Attribute index - The init parameters for that servlet.
134: */
135: protected static int ATTR_PARAMETERS = 1;
136: /**
137: * Attribute index - Our parent-inherited servlet context.
138: */
139: protected static int ATTR_SERVLET_CONTEXT = -1;
140: /**
1.28 bmahe 141: * Attribute index - Our parent-inherited session context.
142: */
143: protected static int ATTR_SESSION_CONTEXT = -1;
1.20 bmahe 144:
145: static {
146: Attribute a = null ;
147: Class cls = null ;
148: try {
149: cls = Class.forName("org.w3c.jigsaw.servlet.ServletWrapper") ;
150: } catch (Exception ex) {
151: ex.printStackTrace();
152: System.exit(0);
153: }
154: // The servlet class attribute.
155: a = new StringAttribute("servlet-class"
1.1 abaird 156: , null
1.20 bmahe 157: , Attribute.EDITABLE | Attribute.MANDATORY) ;
158: ATTR_SERVLET_CLASS = AttributeRegistry.registerAttribute(cls, a) ;
159: // This servlet init parameters
160: a = new PropertiesAttribute("servlet-parameters"
161: , null
162: , Attribute.EDITABLE);
163: ATTR_PARAMETERS = AttributeRegistry.registerAttribute(cls, a);
164: // Our servlet context:
165: a = new ObjectAttribute("servlet-context",
1.24 bmahe 166: "org.w3c.jigsaw.servlet.JigsawServletContext",
1.20 bmahe 167: null,
168: Attribute.DONTSAVE);
169: ATTR_SERVLET_CONTEXT = AttributeRegistry.registerAttribute(cls, a);
1.28 bmahe 170: // Our session context:
171: a = new ObjectAttribute("session-context",
1.60 ! ylafon 172: "org.w3c.jigsaw.servlet.JigsawHttpSessionContext",
! 173: null,
! 174: Attribute.DONTSAVE);
1.28 bmahe 175: ATTR_SESSION_CONTEXT = AttributeRegistry.registerAttribute(cls, a);
1.40 bmahe 176: // The servlet timeout:
177: a = new LongAttribute("servlet-timeout",
178: null,
179: Attribute.EDITABLE);
180: ATTR_SERVLET_TIMEOUT = AttributeRegistry.registerAttribute(cls, a);
1.59 ylafon 181: // The servlet maxinstances:
182: a = new IntegerAttribute("servlet-instancemax",
1.60 ! ylafon 183: null,
! 184: Attribute.EDITABLE);
1.59 ylafon 185: ATTR_SERVLET_INSTANCEMAX = AttributeRegistry.registerAttribute(cls, a);
1.20 bmahe 186: }
1.51 ylafon 187:
1.59 ylafon 188: /**
1.60 ! ylafon 189: * Using a limited pool of servlet instances instead of a single
! 190: * instance, tk, 22.10.2001
1.59 ylafon 191: * protected Servlet servlet = null;
1.20 bmahe 192: */
1.59 ylafon 193: protected ServletPool servletPool = new ServletPool();
194:
1.20 bmahe 195: /**
1.59 ylafon 196: * Is our servler initialized ?
1.20 bmahe 197: */
198: protected boolean inited = false;
199:
200: /**
201: * The Path where we can find the servlet class file.
202: */
203: public File getServletDirectory() {
1.25 bmahe 204: ResourceReference rr = getParent();
205: if (rr != null) {
206: try {
207: Resource parent = rr.lock();
208: if (parent.definesAttribute("directory"))
209: return (File) parent.getValue("directory", null);
210: } catch(InvalidResourceException ex) {
211: ex.printStackTrace();
212: } finally {
213: rr.unlock();
214: }
215: }
216: return null;
1.20 bmahe 217: }
218:
219: /**
220: * Servlet stub implementation - Get an init parameter value.
221: */
222: public synchronized String getInitParameter(String string) {
223: ArrayDictionary d = getServletParameters();
224: String v = (d != null) ? (String) d.get(string) : null;
225: return v;
226: }
227:
228: /**
229: * Servlet stub implementation - Get all init parameters.
230: */
231: public synchronized Enumeration getInitParameterNames() {
232: // Convert init parameters to hashtable:
233: ArrayDictionary d = getServletParameters();
234: return (d != null) ? d.keys() : new EmptyEnumeration();
235: }
236:
237: /**
238: * Servlet stub implementation - Get that servlet context.
239: */
240: public ServletContext getServletContext() {
1.52 bmahe 241: ServletContext ctxt =
242: (ServletContext) getValue(ATTR_SERVLET_CONTEXT, null);
243: return ctxt;
1.20 bmahe 244: }
245:
1.28 bmahe 246: public JigsawHttpSessionContext getSessionContext() {
247: return (JigsawHttpSessionContext) getValue(ATTR_SESSION_CONTEXT, null);
248: }
249:
1.40 bmahe 250: protected long getServletTimeout() {
1.45 bmahe 251: long timeout = getLong(ATTR_SERVLET_TIMEOUT, 0);
252: if (timeout == 0) {
1.40 bmahe 253: JigsawServletContext ctxt =
254: (JigsawServletContext) getServletContext();
255: timeout = ctxt.getServletTimeout();
256: }
257: return timeout;
258: }
259:
1.60 ! ylafon 260: protected int getInstanceMax() {
! 261: // added for single thread model
! 262: // servlet instance pool size limitation, tk, 20.10.2001
1.59 ylafon 263: int instancemax = getInt(ATTR_SERVLET_INSTANCEMAX, 1);
264: if (instancemax < 1) {
265: JigsawServletContext ctxt =
266: (JigsawServletContext) getServletContext();
267: instancemax = ctxt.getServletInstanceMax();
268: }
1.60 ! ylafon 269: if (instancemax < 1) {
! 270: return 1;
! 271: } else {
! 272: return instancemax;
! 273: }
1.59 ylafon 274: }
275:
1.36 bmahe 276: protected void invalidateAllSession() {
1.60 ! ylafon 277: if (debug) {
1.36 bmahe 278: System.out.println("Invalidate All Session...");
1.60 ! ylafon 279: }
1.36 bmahe 280: JigsawHttpSessionContext ctxt = getSessionContext();
281: Enumeration enum = ctxt.getIds();
1.60 ! ylafon 282: while (enum.hasMoreElements()) {
1.36 bmahe 283: ctxt.getSession((String)enum.nextElement()).invalidate();
1.60 ! ylafon 284: }
1.36 bmahe 285: }
286:
1.37 bmahe 287: /**
288: * Check the servlet class, ans try to initialize it.
289: * @exception ClassNotFoundException if servlet class can't be found.
290: * @exception ServletException if servlet can't be initialized.
291: */
1.36 bmahe 292: protected void checkServlet()
293: throws ClassNotFoundException, ServletException
1.60 ! ylafon 294: {
! 295: synchronized(servletPool) {
! 296: // tk, 20.10.2001, synchronized loading is necessary at
! 297: // least for the non-SingleThreadModel
! 298: boolean classmodified =
! 299: getLocalServletLoader().classChanged(getServletClass());
! 300:
! 301: if ((!inited) ||
! 302: classmodified ||
! 303: // (servlet.getClass() !=
! 304: // getLocalServletLoader().loadClass(getServletClass()))
! 305: (servletPool.getLoadedClass() !=
! 306: getLocalServletLoader().loadClass(getServletClass()))
! 307: ) {
! 308: inited = launchServlet();
! 309: }
1.36 bmahe 310: }
1.60 ! ylafon 311: }
1.20 bmahe 312:
313: protected boolean isInited() {
314: return inited;
315: }
316:
1.59 ylafon 317: /**
1.60 ! ylafon 318: * Check and eventually load the servlet we are wrapping.
! 319: * This method was added for replacing getServlet() during access checks
! 320: * in order to do perform checks without accessing a servlet instance.
! 321: * @return true if and only if the sevlet has successfully been loaded
! 322: */
! 323: public boolean isServletLoaded() {
! 324: try {
! 325: checkServlet();
! 326: } catch (Exception ex) {
! 327: if (debug) {
! 328: ex.printStackTrace();
! 329: }
! 330: }
! 331: return inited;
! 332: }
! 333:
! 334: /**
! 335: * Helper class for managing a limited pool of servlet instances,
! 336: * tk, 20.10.2001
! 337: * For the SingleThreadModel instance are created as required and
! 338: * retained up to a specified limit.
! 339: * For the non-SingleThreadModel one instance only is created
! 340: * (in accordance with the servlet spec).
! 341: * The first instance initializes the pool with its pars-pro-toto
! 342: * class attributes.
1.59 ylafon 343: */
344: private class ServletPool {
345:
1.60 ! ylafon 346: // maximum pool size
! 347: private int maximum = 1;
! 348:
1.59 ylafon 349: // current pool capacity
350: private int capacity = 0;
351:
1.60 ! ylafon 352: // current pool usage level
! 353: private int usage = 0;
! 354:
1.59 ylafon 355: // list of servlet instances
1.60 ! ylafon 356: private Servlet[] pool = null;
1.59 ylafon 357:
358: // indicator for SingleThreadModel
359: private boolean singleThreaded = false;
360:
361: // common class of the servlet pool
362: private Class loadedClass = null;
363:
1.60 ! ylafon 364:
1.59 ylafon 365: /**
1.60 ! ylafon 366: * method for exporting the class common to all loaded servlet
! 367: * instances
1.59 ylafon 368: * @return common loaded servlet class
369: */
370: protected Class getLoadedClass() {
371: return loadedClass;
372: }
373:
374: /**
1.60 ! ylafon 375: * method for adding a fresh servlet instance to the pool
! 376: * (using external synchronization)
1.59 ylafon 377: * @param servlet the instance to be added to the pool
378: */
379: protected void add(Servlet servlet) {
1.60 ! ylafon 380: if ((pool == null)||(loadedClass == null)) {
! 381: singleThreaded = (servlet instanceof SingleThreadModel);
! 382: if (singleThreaded) maximum = getInstanceMax();
! 383: else maximum = 1;
! 384: loadedClass = servlet.getClass();
! 385: pool = new Servlet[maximum];
! 386: }
! 387: if (capacity < maximum) {
! 388: pool[capacity++] = servlet;
1.59 ylafon 389: }
390: }
391:
392: /**
1.60 ! ylafon 393: * non-blocking method for removing a servlet instance from the
! 394: * pool (using external synchronization)
1.59 ylafon 395: * @return a removed servlet instance or null if the pool is empty
396: */
397: protected Servlet remove() {
1.60 ! ylafon 398: if (capacity > usage) {
! 399: Servlet servlet = pool[--capacity];
! 400: if (capacity < 1) {
! 401: pool = null;
! 402: loadedClass = null;
! 403: singleThreaded = false;
! 404: maximum = 1;
! 405: }
! 406: return servlet;
! 407: }
! 408: else return null;
1.59 ylafon 409: }
410:
411: /**
412: * blocking method for accessing a servlet instance from the pool
1.60 ! ylafon 413: * @exception ServletException thrown if the pool is not properly
! 414: * initialized
1.59 ylafon 415: */
416: protected synchronized Servlet takeServlet() throws ServletException {
1.60 ! ylafon 417: if ((!inited)||(capacity < 1)||
! 418: (pool == null)||(loadedClass == null)) {
! 419: throw new ServletException("Accessing servlet without"+
! 420: " initialization.");
1.59 ylafon 421: }
422: if (singleThreaded) {
1.60 ! ylafon 423: try {
! 424: while (true) {
! 425: if (usage < capacity) {
! 426: return pool[usage++];
! 427: } else {
! 428: if (capacity < maximum) {
! 429: if (launchServlet(loadedClass)) {
! 430: notifyAll();
! 431: Thread.currentThread().yield();
! 432: // give previous waiters a chance
! 433: } else {
! 434: wait();
! 435: }
! 436: } else {
! 437: wait();
! 438: }
! 439: }
! 440: }
! 441: }
! 442: catch (InterruptedException ex) {
! 443: throw new ServletException("Waiting for a free servlet"+
! 444: " instance interrupted.");
! 445: }
! 446: } else {
! 447: // One instance only is used in non single thread case
! 448: // (cf. servlet api for details)
! 449: usage++;
! 450: return pool[0];
1.59 ylafon 451: }
452: }
453:
454: /**
455: * method for releasing a servlet instance into the pool after work
1.60 ! ylafon 456: * @param servlet the instance to be returned to the pool
! 457: * @exception ServletException thrown if pool is not properly
! 458: * initialized
1.59 ylafon 459: */
1.60 ! ylafon 460: protected synchronized void releaseServlet(Servlet servlet)
! 461: throws ServletException
! 462: {
! 463: if ((!inited)||(capacity < 1)||(pool == null)||
! 464: (loadedClass == null)) {
! 465: throw new ServletException("Releasing servlet without"+
! 466: " initialization.");
1.59 ylafon 467: }
1.60 ! ylafon 468: if (usage > 0) {
! 469: if (singleThreaded) {
! 470: pool[--usage] = servlet;
! 471: notifyAll();
! 472: } else {
! 473: // In this case the servlet instance is shared, i.e.
! 474: // we have a counting semaphore only.
! 475: usage--;
! 476: }
! 477: } else {
! 478: throw new ServletException("Incorrect servlet release"+
! 479: " occurred.");
! 480: }
1.59 ylafon 481: }
482:
483: /**
484: * method for referencing a servlet instance of the pool
1.60 ! ylafon 485: * This method was added for backward compatibility in order to
! 486: * support the deprecated getServlet() method,
! 487: * which is structurally not applicable to the pool mechanism, i.e.
! 488: * it always returns null in
! 489: * case of the SingleThreadModel (in accordance with the current
! 490: * servlet spec)
1.59 ylafon 491: * @return a servlet reference or null
492: */
493: protected synchronized Servlet getRepresentative() {
1.60 ! ylafon 494: if ((!inited)||(capacity < 1)||(loadedClass == null)) {
! 495: return null;
! 496: } else {
! 497: if (singleThreaded) {
! 498: // FIXME, here we could also return pool[0],
! 499: // which is defined but probably taken.
! 500: // However, using pool[0] in a normal manner might
! 501: // cause strange behavior
! 502: // due to its single threaded design aspect.
! 503: return null;
! 504: } else {
! 505: return pool[0];
! 506: }
1.59 ylafon 507: }
508: }
1.60 ! ylafon 509: }
1.59 ylafon 510:
1.55 ylafon 511: private class ServletRunner extends Thread {
512: Servlet srServlet;
513: JigsawHttpServletRequest srReq;
514: JigsawHttpServletResponse srResp;
515:
516: public void run() {
1.58 ylafon 517: // synchronization object
518: Object o = null;
1.55 ylafon 519: try {
1.58 ylafon 520: Reply reply = srResp.getReply();
521: if (reply != null) {
522: o = reply.getState(JigsawHttpServletResponse.MONITOR);
523: }
1.55 ylafon 524: srServlet.service(srReq , srResp);
1.60 ! ylafon 525: try {
! 526: servletPool.releaseServlet(srServlet);
! 527: }
! 528: finally {
! 529: srServlet = null;
! 530: }
1.55 ylafon 531: srResp.flushStream(true);
1.56 ylafon 532: } catch (UnavailableException uex) {
533: String message = null;
534: srResp.setStatus(HTTP.SERVICE_UNAVAILABLE);
535: if (uex.isPermanent()) {
536: message = "<h2>The servlet is permanently "+
537: "unavailable :</h2>"+
538: "Details: <b>"+uex.getMessage()+"</b>";
539: try {
540: srResp.sendError(HTTP.SERVICE_UNAVAILABLE, message);
541: } catch (IOException ioex) {
542: // not much to do now...
543: }
544: } else {
545: int delay = uex.getUnavailableSeconds();
546: if (delay > 0) {
547: message = "<h2>The servlet is temporarily "+
548: "unavailable :</h2>"+
549: "Delay : "+delay+
550: " seconds<br><br>Details: <b>"+
551: uex.getMessage()+"</b>";
552: srResp.getReply().setRetryAfter(delay);
553: try {
554: srResp.sendError(HTTP.SERVICE_UNAVAILABLE,message);
555: } catch (IOException ioex) {
556: // not much to do now...
557: }
558: } else {
559: message = "<h2>The servlet is temporarily "+
560: "unavailable :</h2>"+
561: "Details: <b>"+uex.getMessage()+
562: "</b>";
563: try {
564: srResp.sendError(HTTP.SERVICE_UNAVAILABLE,message);
565: } catch (IOException ioex) {
566: // not much to do now...
567: }
568: }
569: }
1.55 ylafon 570: } catch (Exception ex) {
1.56 ylafon 571: try {
572: srResp.sendError(HTTP.INTERNAL_SERVER_ERROR,
573: "Servlet has thrown exception:" +
574: ex.toString());
575: } catch (IOException ioex) {
576: // no stream to write on, fail silently
577: }
578: } finally {
1.60 ! ylafon 579: if (srServlet != null) {
! 580: try {
! 581: servletPool.releaseServlet(srServlet);
! 582: }
! 583: catch (ServletException ex) {
! 584: // ignore
! 585: }
! 586: }
1.56 ylafon 587: // release the monitor waiting for the end of the reply setup
1.58 ylafon 588: if (o != null) {
589: synchronized (o) {
590: o.notifyAll();
1.56 ylafon 591: }
592: }
1.55 ylafon 593: }
594: }
595:
596: ServletRunner(Servlet servlet,
597: JigsawHttpServletRequest request,
598: JigsawHttpServletResponse response) {
599: srServlet = servlet;
600: srReq = request;
601: srResp = response;
1.59 ylafon 602:
1.60 ! ylafon 603: // name modified in order to keep track of who is running
! 604: // which instance, tk, 21.10.2001
! 605: setName("ServletRunner<" + getName() + ":" + servlet.hashCode()
! 606: + ">");
1.55 ylafon 607: }
608: }
609:
1.20 bmahe 610: protected void service(Request request, Reply reply)
611: throws ServletException, IOException
1.60 ! ylafon 612: {
! 613: JigsawHttpServletResponse jRes = null;
! 614: JigsawHttpServletRequest jReq = null;
! 615: /* modified due to servlet pooling, tk, 20.10.2001
! 616: if (servlet instanceof SingleThreadModel) {
! 617: synchronized (this) {
! 618: jRes = new JigsawHttpServletResponse(request, reply);
! 619: jReq = new JigsawHttpServletRequest(servlet,
! 620: request,
! 621: jRes,
! 622: getSessionContext());
! 623: jRes.setServletRequest(jReq);
! 624: try {
! 625: connections++;
! 626: // FIXME we should reuse a thread rather than
! 627: // reallocating one for every hit
! 628: ServletRunner runner = new ServletRunner(servlet, jReq, jRes);
! 629: reply.setState(RUNNER, runner);
! 630: runner.start();
! 631: } finally {
! 632: connections--;
! 633: }
! 634: }
! 635: } else {
! 636: */
1.31 bmahe 637: jRes = new JigsawHttpServletResponse(request, reply);
1.60 ! ylafon 638: Servlet servlet = servletPool.takeServlet();
! 639: // accessing a fresh or sharable instance, tk, 21.10.2001
1.59 ylafon 640: // jReq = new JigsawHttpServletRequest(servlet,
1.31 bmahe 641: jReq = new JigsawHttpServletRequest(servlet,
642: request,
643: jRes,
644: getSessionContext());
645: jRes.setServletRequest(jReq);
1.60 ! ylafon 646: // try {
! 647: // connections++;
! 648: // FIXME we should reuse a thread rather than
! 649: // reallocating one for every hit
! 650: // reallocating one for every hit
! 651: ServletRunner runner = new ServletRunner(servlet, jReq, jRes);
! 652: reply.setState(RUNNER, runner);
! 653: runner.start();
! 654: // } finally {
! 655: // connections--;
! 656: // }
! 657: /* } */
! 658: timeoutManager.restart();
! 659: }
1.20 bmahe 660:
661: /**
662: * Get the class name of the wrapped servlet.
663: * @return The class name for the servlet if attribute is defined.
664: * Otherwise the class name is deduced from the resource identifier.
665: */
666:
667: public String getServletClass()
1.60 ! ylafon 668: {
! 669: String sclass = getString(ATTR_SERVLET_CLASS, null);
! 670: if (sclass == null) {
! 671: String ident = getIdentifier();
! 672: if (ident.endsWith(".class")) {
! 673: sclass = ident;
! 674: }
! 675: }
! 676: return sclass;
1.20 bmahe 677: }
678:
679: /**
680: * Get the init parameters for our wrapped servlet.
681: * @return An ArrayDictionary instance if the attribute is defined,
682: * <strong>false</strong> otherwise.
683: */
684:
685: public ArrayDictionary getServletParameters() {
686: return (ArrayDictionary) getValue(ATTR_PARAMETERS, null);
687: }
688:
1.26 bmahe 689: protected void setValueOfSuperClass(int idx, Object value) {
690: super.setValue(idx, value);
691: }
692:
1.20 bmahe 693: /**
694: * Catch assignements to the servlet class name attribute.
695: * <p>When a change to that attribute is detected, the servlet is
696: * automatically reinitialized.
697: */
698:
699: public void setValue(int idx, Object value) {
700: super.setValue(idx, value);
1.44 bmahe 701: if (((idx == ATTR_SERVLET_CLASS) && (value != null)) ||
702: (idx == ATTR_PARAMETERS)) {
1.36 bmahe 703: try {
1.60 ! ylafon 704: synchronized(servletPool) {
! 705: // synchronization added, tk, 20.10.2001
1.59 ylafon 706: inited = launchServlet();
707: }
1.36 bmahe 708: } catch (Exception ex) {
709: String msg = ("unable to set servlet class \""+
710: getServletClass()+
711: "\" : "+
712: ex.getMessage());
713: getServer().errlog(msg);
714: }
1.40 bmahe 715: } if (idx == ATTR_SERVLET_TIMEOUT) {
716: timeoutManager.restart();
1.36 bmahe 717: }
1.20 bmahe 718: }
719:
720: /**
721: * Destroy the servlet we are wrapping.
722: */
1.60 ! ylafon 723: protected void destroyServlet() {
1.59 ylafon 724: // if ((servlet != null) && (connections < 1)) {
1.60 ! ylafon 725: synchronized(servletPool) {
! 726: Servlet servlet = servletPool.remove();
! 727: while (servlet != null) {
! 728: servlet.destroy();
! 729: // servlet = null;
! 730: servlet = servletPool.remove();
! 731: }
! 732: inited = (servletPool.getLoadedClass() != null);
1.20 bmahe 733: }
1.60 ! ylafon 734: // }
1.20 bmahe 735: }
736:
737: /**
738: * Get the servlet we are wrapping.
739: * @return A servlet instance, if the servlet is alredy running,
740: * <strong>null</strong> otherwise.
741: */
1.60 ! ylafon 742: public Servlet getServlet() {
1.36 bmahe 743: try {
744: checkServlet();
745: } catch (Exception ex) {
746: if (debug)
747: ex.printStackTrace();
748: }
1.59 ylafon 749: return servletPool.getRepresentative();
1.20 bmahe 750: }
1.59 ylafon 751:
1.20 bmahe 752: /**
753: * Initialize our servlet from the given (loaded) class.
754: * @param cls The servlet loaded main class.
755: * @return A boolean, <strong>true</strong> if servlet was successfully
756: * initialised, <strong>false</strong> otherwise.
1.37 bmahe 757: * @exception ServletException if servlet can't be initialized.
1.20 bmahe 758: */
759:
1.36 bmahe 760: protected boolean launchServlet(Class cls)
761: throws ServletException
1.60 ! ylafon 762: {
! 763: if (debug) {
! 764: System.out.println("launching Servlet: "+getServletName());
! 765: }
! 766: Servlet servlet = null;
! 767: try {
! 768: servlet = (Servlet) cls.newInstance();
! 769: servlet.init((ServletConfig) this);
! 770: timeoutManager.restart();
! 771: } catch (IllegalAccessException ex) {
! 772: String msg = ("Illegal access during servlet instantiation, "+
! 773: ex.getClass().getName()+": "+
! 774: ex.getMessage());
! 775: if ( debug ) {
! 776: ex.printStackTrace();
! 777: }
! 778: getServer().errlog(this, msg);
! 779: return false;
! 780: } catch (InstantiationException iex) {
! 781: String msg = ("unable to instantiate servlet, "+
! 782: iex.getClass().getName()+": "+
! 783: iex.getMessage());
! 784: if ( debug ) {
! 785: iex.printStackTrace();
! 786: }
! 787: getServer().errlog(this, msg);
! 788: return false;
! 789: }
! 790: // modified for servlet pool and executed in a context
! 791: // synchronized on the servlet pool, tk, 20.10.2001
! 792: if (servlet != null) {
! 793: servletPool.add(servlet);
! 794: return true;
! 795: } else {
! 796: return false;
! 797: }
1.50 bmahe 798: }
1.32 bmahe 799:
800: /**
801: * Check if the Servletclass wrapped is a Servlet class without
1.36 bmahe 802: * initializing it. (not the same than checkServlet).
1.33 bmahe 803: * used by the ServletIndexer.
804: * @see org.w3c.jigsaw.servlet.ServletIndexer
1.32 bmahe 805: * @return A boolean.
806: */
807: protected boolean isWrappingAServlet() {
808: String clsname = getServletClass();
1.60 ! ylafon 809: if ( clsname == null ) {
1.32 bmahe 810: return false;
1.60 ! ylafon 811: }
1.32 bmahe 812: Class c = null;
813: try {
1.34 bmahe 814: c = getLocalServletLoader().loadClass(clsname, true);
1.32 bmahe 815: Object o = c.newInstance();
816: return (o instanceof Servlet);
817: } catch (Exception ex) {
818: return false;
819: }
1.20 bmahe 820: }
821:
822: /**
823: * Launch the servlet we are wrapping.
824: * <p>This method either succeed, or the wrapper resource itself will fail
825: * to initialize, acting as transparently as possible (in some sense).
826: * @return A boolean, <strong>true</strong> if servlet launched.
1.37 bmahe 827: * @exception ClassNotFoundException if servlet class can't be found.
828: * @exception ServletException if servlet can't be initialized.
1.20 bmahe 829: */
830:
1.36 bmahe 831: protected boolean launchServlet()
832: throws ClassNotFoundException, ServletException
1.60 ! ylafon 833: {
! 834: // Get and check the servlet class:
! 835: // if ( servlet != null )
1.20 bmahe 836: destroyServlet();
1.60 ! ylafon 837: if (inited) {
! 838: String msg = "relaunching servlet failed due to incomplete \""
! 839: + getServletClass() + "\" cleanup.";
! 840: getServer().errlog(this, msg);
! 841: return false;
! 842: } else {
! 843: // Load appropriate servlet class:
! 844: String clsname = getServletClass();
! 845: if ( clsname == null ) {
! 846: getServer().errlog(this, "no servlet class attribute"+
! 847: " defined.");
! 848: return false;
! 849: } else {
! 850: Class c = null;
! 851: try {
! 852: if (getLocalServletLoader().classChanged(clsname)) {
! 853: createNewLocalServletLoader(true);
! 854: invalidateAllSession();
! 855: }
! 856: c = getLocalServletLoader().loadClass(clsname, true);
! 857: } catch (ClassNotFoundException ex) {
! 858: String msg = ("unable to find servlet class \""+
! 859: getServletClass()+"\"");
! 860: getServer().errlog(msg);
! 861: // re throw the exception
! 862: throw ex;
! 863: }
! 864: return (c != null) ? launchServlet(c) : false;
! 865: }
1.20 bmahe 866: }
867: }
1.59 ylafon 868:
1.60 ! ylafon 869: public boolean acceptUnload() {
1.59 ylafon 870: // return (servlet == null);
1.60 ! ylafon 871: return (!inited);
1.40 bmahe 872: }
1.59 ylafon 873:
1.20 bmahe 874: public void notifyUnload() {
1.60 ! ylafon 875: if (timeoutManager != null) {
1.42 bmahe 876: timeoutManager.stop();
1.60 ! ylafon 877: }
1.20 bmahe 878: destroyServlet();
1.26 bmahe 879: }
880:
881: /**
882: * Get or create a suitable LocalServletLoader instance to load
883: * that servlet.
884: * @return A LocalServletLoader instance.
885: */
1.60 ! ylafon 886: // singleton synchronized already performed at the servlet context.
! 887: // protected synchronized AutoReloadServletLoader getLocalServletLoader() {
! 888: protected AutoReloadServletLoader getLocalServletLoader() {
1.34 bmahe 889: JigsawServletContext ctxt = (JigsawServletContext) getServletContext();
890: return ctxt.getLocalServletLoader();
1.26 bmahe 891: }
892:
1.60 ! ylafon 893: protected AutoReloadServletLoader createNewLocalServletLoader(boolean
! 894: keepold)
1.26 bmahe 895: {
1.60 ! ylafon 896: JigsawServletContext ctxt = (JigsawServletContext)
! 897: getServletContext();
1.34 bmahe 898: return ctxt.createNewLocalServletLoader(keepold);
1.20 bmahe 899: }
900:
901: /**
1.48 bmahe 902: * Returns the name of this servlet instance.
903: * The name may be provided via server administration, assigned in the
904: * web application deployment descriptor, or for an unregistered (and thus
905: * unnamed) servlet instance it will be the servlet's class name.
906: * @return the name of the servlet instance
907: */
908: public String getServletName() {
909: return getIdentifier();
910: }
911:
912: /**
1.20 bmahe 913: * Initialize this servlet wrapper resource.
914: * After the wrapper itself is inited, it performs the servlet
915: * initialzation.
916: * @param values The default attribute values.
917: */
918: public void initialize(Object values[]) {
919: super.initialize(values);
1.60 ! ylafon 920: // connections = 0;
1.41 bmahe 921:
922: if (getServletContext() != null) {
923: timeoutManager = new TimeoutManager((httpd)getServer());
924: timeoutManager.start();
925: }
1.40 bmahe 926:
1.20 bmahe 927: try {
928: registerFrameIfNone("org.w3c.jigsaw.servlet.ServletWrapperFrame",
929: "servlet-wrapper-frame");
930: } catch (Exception ex) {
931: ex.printStackTrace();
932: }
1.18 bmahe 933: }
1.1 abaird 934: }
Webmaster