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