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