costin      00/12/26 15:23:30

  Modified:    src/share/org/apache/tomcat/core ContextManager.java
  Log:
  Reverted back to the 3.2 way of dealing with contextAdd - the hook
  will be called just after the method.
  
  Improved the documentation, states - now it's simpler and easier for user.
  
  More "permisive" status handling - correct instead of throwing exceptions.
  
  Added setProperty, removed showDebugInfo ( getProperty should be used instead),
  same for randomClass ( commit that fixes that will follow )
  
  Implemented removeInterceptor, make sure hooks are called regardless of
  add order.
  
  Added attribute-like get/setNote - that should simplify the use of notes.
  ( the id based method should be used at runtime )
  
  This is not the final version, I'm still lookig for the "right" way to
  setup/start/stop/configure the server.
  
  Revision  Changes    Path
  1.158     +195 -285  
jakarta-tomcat/src/share/org/apache/tomcat/core/ContextManager.java
  
  Index: ContextManager.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ContextManager.java,v
  retrieving revision 1.157
  retrieving revision 1.158
  diff -u -r1.157 -r1.158
  --- ContextManager.java       2000/12/08 23:18:43     1.157
  +++ ContextManager.java       2000/12/26 23:23:29     1.158
  @@ -57,7 +57,6 @@
    *
    */
   
  -
   package org.apache.tomcat.core;
   
   import org.apache.tomcat.util.*;
  @@ -68,117 +67,68 @@
   
   /**
     ContextManager is the entry point and "controler" of the servlet execution.
  -  It maintains a list of WebApplications and a list of global event
  -  interceptors that are set up to handle the actual execution.
  - 
  -  The ContextManager will direct the request processing flow
  -  from its arrival from the server/protocl adapter ( in service() ).
  -  It will do that by calling a number of hooks implemented by Interceptors.
  - 
  -  Hooks are provided for request parsing and mapping, auth, autorization,
  -  pre/post service, actual invocation and logging.
  - 
  -  ContextManager will also store properties that are global to the servlet
  -  container - like root directory, install dir, work dir.
  - 
  -  The extension mechanism for tomcat is the Interceptor.
  -  This class is final - if you need to change certain functionality
  -  you should add a new hook.
  - 
  -  ContextManager is not a singleton - it represent a servlet container
  -  instance ( with all associated ports and configurations ).
  -  One application may try to embed multiple ( distinct ) servlet containers -
  -  this feature hasn't been tested or used
  - 
  -   <h2>Startup</h2>
  -
  -  1. Create ContextManager.
  -
  -  2. Set properties for ContextManager ( home, debug, etc).
  -
  -  3. Add global Interceptors.
  -
  -  4. You may create, set and add Contexts. NO HOOKS ARE CALLED.
  -      This adds a lot of complexity to the code - but allow
  -      the server to have an initial set of contexts when it starts.
  -      More contexts can be added after startup.
  -  
  -  5. init() At this stage engineInit() callback will be
  -     called for all global interceptors. 
  -
  -     During engineInit() a number of Contexts can be created and
  -     added to the server. No addContext() callback is called until
  -     the last engineInit() returns. Interceptors can also change the
  -     state of the server ( change properites, add other interceptors,
  -     etc)
  -
  -     After this call the server will be in INITIALIZED state.
  -     No callback other than engineInit  can be called before the server
  -     enters this state.
  -
  -  6. init() will also call the addContext() hook for all contexts
  -     that were added during engineInit or before init() was called.
  -     More contexts can be added after init() and before start().
  -
  -     InitContext will have no effect before the server is started -
  -     all initContexts for added contexts will be called automatically
  -     at start.
  -
  -  7. start(). All contexts will be initialized ( contextInit()
  -     callback ). ContextInit will move the context to READY state,
  -     allowing it to serve requests.
  -
  -     Server will move to START state after all configured contexts
  -     are READY. No servlet should be served before the container is
  -     in START state ( tomcat should return "Server not ready") .
  -
  -     <h2>Normal operation</h2>
  +  It maintains a list of Contexts ( web applications )  and a list of
  +  interceptors (hooks) that are set up to handle the actual execution.
   
  -  1. Requests for a context in READY state will be served by that context.
  -     Requests for a context that is not READY will return an error (
  -     "application temp. unavailable" - no 404 on the parent context !)
  +  The execution is modeled after Apache2.0 and other web servers, with
  +  interceptors serving the same role as modules.
   
  -  2. At any time you can create a new Context, set properties ( that can
  -     be done from servlets or by interceptors like ~user). The context is
  -     not visible to tomcat until addContext completes.
  -
  -  3. addContext(). This will triger the addContext() callback.
  -
  -  4. initContext(). This will triger contextInit() callbacks/
  -     After that the context is READY and can serve requests.
  -
  -  5. You can find a Context by enumerating all added contexts.
  -
  -  6. contextShutdown(). The context will no longer be READY and can't
  -     serve requests ( Application unavailable ). contextShutdown hooks
  -     are called
  -
  -  7. removeContext(). This will call removeContext() hooks. After this
  -     method the context will no longer be visible to tomcat and will
  -     be removed from the list of known contexts. Requests for this
  -     context will be served by the parent context ( or root )
  +  The "core" is composed of representation of "Request", "Response",
  +  "Container" ( a set of URLs with shared properties - like a Location
  +  in Apache), "Context" ( web application - the deployment unit ).
  +
  +  "ContextManager" will  store properties that are global to the servlet
  +  container - like root directory, install dir, work dir and act as the
  +  top level controler.
  + 
  +  The server functionality is implemented in modules ( "BaseInterceptor" ).
   
  -     <h2>Stopping the server</h2>
  +  Hooks are provided for request parsing and mapping, auth, autorization,
  +  pre/post service, actual invocation and logging - similar with Apache and all
  +  other web servers.
   
  -  1. stop(). The server will exit the START state and enter INIT.
  -     All contextShutdown() and will be called. 
  +  <h2>Using tomcat</h2>
   
  -  2. shutdown(). All  removeContext() callbacks will be called and the server
  -      will enter PRE_INIT state. The contexts will not be removed from
  -      the server - it is possible to call init again ( server restart ? )
  +  <ol>
  +  <li> Create ContextManager.
   
  -  Notes: 
  -  DefaultCMSetter ( or a replacement ) must be the first in
  -  the chain and will adjust the paths and set defaults for
  -  all unset properties.
  +  <li> Set properties for ContextManager ( home, debug, etc).
  +
  +  <li> Add the initial set of modules. Modules can also be added and removed
  +     after the server is started. ( engineInit() and addInterceptor() hooks
  +     will be called ). An interceptor can add/remove other interceptors
  +     during the engineInit  hook, or change/set server properties.
  +     XXX web applications should be added at a later stage.
  +     
  +  <li> Add the initial set of web applications ( Contexts ). Applications can
  +     be added and removed after the server is started. ( addContext() hook
  +     will be called )
  +
  +  <li>init(). All contexts will be ready to run ( contextInit() hook is called)
  +
  +  <li>start(). engineStart() hook will be called, the connector modules
  +  should accept and serve requests.
  +
  +  <li>While tomcat is running, you can add/remove interceptors ( you must
  +  insure the server is temporarily stoped ). engineInit(), addInterceptor()
  +  will be called, then addContext() for all existing contexts and
  +  initContext() if server is in INIT state. 
  +
  +  <li>While tomcat is running, you can temporarily disable web applications,
  +  remove and add new applications. If an application is disabled you can
  +  add local modules, that will affect only that application. Modules can
  +  also add and remove webapplications automatically ( like ~user ).
  +
  +  <li>stop() will stop the server ( engineStop() hook will be called )
  +
  +  <li>shutdown() will clean up all resources in use by web applications
  +  ( contextShutdown() ) and remove all contexts ( removeContext() hook )
  +  </ol>
   
  -  AutoSetup and other interceptors can automatically add/set
  -  more properties and make other calls.
  - 
     @author James Duncan Davidson [[EMAIL PROTECTED]]
     @author James Todd [[EMAIL PROTECTED]]
     @author Harish Prabandham
  -  @author [EMAIL PROTECTED]
  +  @author Costin Manolache
     @author Hans Bergsten [[EMAIL PROTECTED]]
    */
   public final class ContextManager implements LogAware{
  @@ -188,45 +138,42 @@
       public static final String TOMCAT_NAME = "Tomcat Web Server";
       
       /** System property used to set the base directory ( tomcat home ).
  -     *  use -DTOMCAT_HOME= in java command line or System.setProperty.
  -     *
  -     *  XXX This is a particular implementation detail of the interceptor
  -     *  that sets the "default" home - it shouldn't be required or
  -     *  specified in the core
  +     *  use -DTOMCAT_HOME= in java command line or as a System.setProperty.
  +     *  XXX hack - setHome is better
        */
       public static final String TOMCAT_HOME="tomcat.home";
   
       // State
   
  -    /** Server is not initialized. You can add interceptors and contexts,
  -     *  but no hook will be called, tomcat will just store the information.
  -     *  The connectors are not activated.
  -     *
  -     *  Tomcat will be in this state when started and after shutdown()
  -     *  is called. Shutdown will also call the engineShutdown() hooks.
  +    /**
  +     *  Server is beeing configured - modules are added.
  +     *  This is the inital state. As soon as init() is called or the
  +     *  first context is added the server will move to init state.
        */
  -    public static final int STATE_PRE_INIT=0;
  -    
  -    /** Server is initialized, engineInit() was called.
  -     *
  -     *  On this state, the addContext hook can be called on all contexts added.
  -     *  ( but the context will be initialized only when tomcat starts )
  -     *
  -     *  The context will be in this state after init() is called or
  -     *  after stop() is called ( after it was in START state )
  -     *
  +    public static final int STATE_CONFIG=0;
  +
  +    /**
  +     *  Server is initialized, web applications can be added.
        */
       public static final int STATE_INIT=1;
  -
  -    /** Engine is running. 
  -     *  The contextInit() hook can be called for all  added contexts,
  -     *  and requests will be processed normally.
  + 
  +    /**
  +     *  Server is able to run requests.
        */
       public static final int STATE_START=2;
   
  +    /** Engine is stoped ( temporarily disabled ). 
  +     */
  +    public static final int STATE_STOP=3;
  +
  +    /** Engine is shutdown. This is the final state, modules should clean
  +     up all resources.
  +     */
  +    public static final int STATE_SHUTDOWN=4;
  +    
       // -------------------- local variables --------------------
   
  -    private int state=STATE_PRE_INIT;
  +    private int state=STATE_CONFIG;
       
       // All contexts managed by the server ( can belong to different
       // virtual hosts )
  @@ -248,11 +195,6 @@
        */
       private String installDir;
       
  -    /** The flag which controls the display of
  -     *  debugging information in default responses
  -     */
  -    boolean showDebugInfo = true;
  -
       // Server properties ( interceptors, etc ) - it's one level above "/"
       private Container defaultContainer;
   
  @@ -260,8 +202,11 @@
       private ClassLoader parentLoader;
   
       // Store Loggers that are used in this server
  -    private Hashtable loggers;
  +    // XXX use Log.getLog() instead!!
  +    private Hashtable loggers=new Hashtable();
   
  +    private Hashtable properties=new Hashtable();
  +    
       /**
        * Construct a new ContextManager instance with default values.
        */
  @@ -283,7 +228,7 @@
        *   files ).
        *
        *  The "tomcat.home" system property is used if no explicit
  -     *  value is set.
  +     *  value is set. XXX
        */
       public final void setHome(String home) {
        this.home=home;
  @@ -334,28 +279,30 @@
        return debug;
       }
   
  -    // -------------------- Other properties --------------------
  +    //  XmlMapper will call setProperty(name,value) if no explicit setter
  +    // is found - it's better to use this mechanism for special
  +    // properties ( that are not generic enough and used by few specific
  +    // module )
   
  -    /** Return the current state of the tomcat server.
  +    /** Generic properties support. You can get properties like
  +     *  "showDebugInfo", "randomClass", etc.
        */
  -    public final int getState() {
  -     return state;
  +    public String getProperty( String name ) {
  +     return (String)properties.get( name );
       }
   
  -    /** The showDebugInfo property state.  To be used for controlling the
  -     *  display of debugging information in default responses.
  -     **/
  -    public final boolean isShowDebugInfo() {
  -     return showDebugInfo;
  +    public void setProperty( String name, String value ) {
  +     properties.put( name, value );
       }
       
  -    /** Sets the showDebugInfo property used for controlling the display of
  -     *  debugging information in default responses.
  +    // -------------------- Other properties --------------------
  +
  +    /** Return the current state of the tomcat server.
        */
  -    public void setShowDebugInfo(boolean showDebugInfo) {
  -     this.showDebugInfo = showDebugInfo;
  +    public final int getState() {
  +     return state;
       }
  - 
  +
       /**
        *  Parent loader is the "base" class loader of the
        *       application that starts tomcat, and includes no
  @@ -404,73 +351,111 @@
       /** Add a global interceptor. It's hooks will be called for
        *  all requests.
        */
  -    public final void addInterceptor( BaseInterceptor ri ) {
  -     // The interceptors are handled per/container ( thanks to Nacho
  -     // for this contribution ).
  +    public final void addInterceptor( BaseInterceptor ri )
  +     throws TomcatException
  +    {
  +     ri.setContextManager( this );
  +
  +     BaseInterceptor existingI[]=defaultContainer.getInterceptors();
  +     for( int i=0; i<existingI.length; i++ ) {
  +         existingI[i].addInterceptor( this, null, ri );
  +     }
  +     ri.addInterceptor( this, null, ri ); // should know about itself
  +     
           defaultContainer.addInterceptor(ri);
  +
  +     if( state==STATE_CONFIG ) return;
  +
  +     // we are at least initialized, call engineInit hook
  +     ri.engineInit( this );
  +
  +     // make sure the interceptor knows about all existing contexts.
  +     Enumeration enum = getContexts();
  +     while (enum.hasMoreElements()) {
  +         Context ctx = (Context)enum.nextElement();
  +         try {
  +             ri.addContext( this, ctx ); 
  +             if( state==STATE_START ) {
  +                 ri.contextInit( ctx );
  +             }
  +         } catch( TomcatException ex ) {
  +             log( "Error adding context " +ctx + " to " + ri );
  +             // ignore it
  +         }
  +     }
  +
  +     if( state==STATE_START )
  +         ri.engineStart(this);
       }
   
  +    public final void removeInterceptor( BaseInterceptor ri )
  +     throws TomcatException
  +    {
  +     BaseInterceptor existingI[]=defaultContainer.getInterceptors();
  +     for( int i=0; i<existingI.length; i++ ) {
  +         existingI[i].removeInterceptor( this, null, ri );
  +     }
  +     ri.removeInterceptor( this, null, ri );
  +     
  +     defaultContainer.removeInterceptor( ri );
   
  +     if( state==STATE_CONFIG ) return;
  +     
  +     Enumeration enum = getContexts();
  +     while (enum.hasMoreElements()) {
  +         Context ctx = (Context)enum.nextElement();
  +         try {
  +             if( state==STATE_START ) {
  +                 ri.contextShutdown( ctx );
  +             }
  +             ri.removeContext( this, ctx ); 
  +         } catch( TomcatException ex ) {
  +             log( "Error adding context " +ctx + " to " + ri );
  +             // ignore it
  +         }
  +     }
  +
  +     if( state==STATE_START )
  +         ri.engineStop(this);
  +    }
  +
       // -------------------- Server functions --------------------
   
       /**
  -     *  Init() is called after the context manager is set up
  -     *  and configured ( all setFoo methods are called, all initial
  -     *  interceptors are added and their setters are called ).
  -     *
  -     *  CM will:
  -     *   - call Interceptor.engineInit() hook
  -     *   - move to state= INIT
  -     *   - call Interceptor.addContext() hook for all contexts
  -     *     added before init() and those added  by interceptors in
  -     *     engineInit hook ).
  -     *
  -     *  It is possible to add and init contexts later.
  -     *
  -     *  Note that addContext() is called each time a context is added,
  -     *  and that can be _before_ tomcat is initialized.
  +     *  Init() is called after the context manager is set up (properties)
  +     *  and configured ( modules ).
        *
  -     * @see addContext()
  +     *  All engineInit() hooks will be called and the server will 
  +     *  move to state= INIT
  +     * 
        */
       public final void init()  throws TomcatException {
  +     if( state == STATE_INIT  )
  +         return;
        if(debug>0 ) log( "Tomcat init");
  -     if( state!= STATE_PRE_INIT  )
  -         throw new TomcatException("Invalid state in init " + state );
        
  -     BaseInterceptor cI[]=defaultContainer.getInterceptors();
  -     for( int i=0; i< cI.length; i++ ) {
  -         cI[i].setContextManager( this );
  -         // If an exception is thrown, the server will not
  -         // move to INIT state.
  -         cI[i].engineInit( this );
  +     BaseInterceptor existingI[]=defaultContainer.getInterceptors();
  +     for( int i=0; i<existingI.length; i++ ) {
  +         existingI[i].engineInit( this );
        }
   
        state=STATE_INIT;
  +    }
   
  -     // delayed execution of addContext.
  -     // If any context is added before init, its initialization
  -     // will be delayed until INIT
  -     Enumeration existingCtxE=contextsV.elements();
  -     while( existingCtxE.hasMoreElements() ) {
  -         Context ctx=(Context)existingCtxE.nextElement();
  -         try {
  -             cI=ctx.getContainer().getInterceptors();
  -             for( int i=0; i< cI.length; i++ ) {
  -                 cI[i].addContext( this, ctx );
  -             }
  -             ctx.setState( Context.STATE_ADDED );
  -             log("Adding " +  ctx.toString());
  -         } catch( TomcatException ex ) {
  -             log( "Context not added " + ctx , ex );
  -             continue;
  -         }
  +    /** Will start the connectors and begin serving requests.
  +     *  It must be called after init.
  +     */
  +    public final void start() throws TomcatException {
  +     if( state==STATE_CONFIG ) {
  +         init();
        }
   
  +     // make sure all context are ready
        Enumeration enum = getContexts();
        while (enum.hasMoreElements()) {
            Context ctx = (Context)enum.nextElement();
            try {
  -             initContext( ctx );
  +             ctx.init();
            } catch( TomcatException ex ) {
                // just log the error, the context will not serve
                // requests but we go on
  @@ -479,19 +464,7 @@
            }
        }
   
  -
  -    }
  -
  -    /** Will start the connectors and begin serving requests.
  -     *  It must be called after init.
  -     */
  -    public final void start() throws TomcatException {
  -     if( state!=STATE_INIT )
  -         throw new TomcatException( "Invalid state in start(), " +
  -                                    " you need to call init() "+ state);
  -     
        //XXX before or after state=START ?
  -     
        BaseInterceptor cI[]=defaultContainer.getInterceptors();
        for( int i=0; i< cI.length; i++ ) {
            cI[i].engineStart( this );
  @@ -511,7 +484,7 @@
            cI[i].engineStop( this );
        }
   
  -     // XXX we shouldn't call shutdown is stop !
  +     // XXX we shouldn't call shutdown in stop !
        shutdown();
       }
   
  @@ -555,18 +528,16 @@
        * @param ctx context to be added.
        */
       public final void addContext( Context ctx ) throws TomcatException {
  +     if( state==STATE_CONFIG) {
  +         init();
  +     }
        // Make sure context knows about its manager.
  +     // this will also initialized all context-specific modules.
        ctx.setContextManager( this );
        ctx.setState( Context.STATE_NEW );
   
  -     // Add it to the contextV, when init all contexts will be added
        contextsV.addElement( ctx );
   
  -     if( state == STATE_PRE_INIT ) {
  -         log( "Delay context add " + ctx.toString());
  -         return;
  -     }
  -     
        try {
            BaseInterceptor cI[]=ctx.getContainer().getInterceptors();
            for( int i=0; i< cI.length; i++ ) {
  @@ -597,10 +568,8 @@
            return;
        
        // disable the context - it it is running 
  -     // ( it is possible to explicitely shut it down before
  -     // calling removeContext )
        if( context.getState() == Context.STATE_READY )
  -         shutdownContext( context );
  +         context.shutdown();
   
        // remove it from operation - notify interceptors that
        // this context is no longer active
  @@ -614,59 +583,6 @@
       }
   
   
  -    /**
  -     * Initializes this context to be able to accept requests. This action
  -     * will cause the context to load it's configuration information
  -     * from the webapp directory in the docbase.
  -     *
  -     * <p>This method must be called
  -     * before any requests are handled by this context. It will be called
  -     * after the context was added, typically when the engine starts
  -     * or after the admin adds a new context.
  -     *
  -     * After this call, the context will be in READY state and will
  -     * be able to server requests.
  -     * 
  -     * @exception if any interceptor throws an exception the error
  -     *   will prevent the context from becoming READY
  -     */
  -    public final void initContext( Context ctx ) throws TomcatException {
  -     // no action if ContextManager is not initialized
  -     if( state == STATE_PRE_INIT )
  -         throw new TomcatException("Invalid state");
  -     
  -     BaseInterceptor cI[]=ctx.getContainer().getInterceptors();
  -     for( int i=0; i< cI.length; i++ ) {
  -         cI[i].contextInit( ctx );
  -     }
  -     
  -     // Only if all init methods succeed an no ex is thrown
  -     ctx.setState( Context.STATE_READY );
  -    }
  -
  -    /** Stop the context. After the call the context will be disabled,
  -     ( DISABLED state ) and it'll not be able to serve requests.
  -     The context will still be available and can be enabled later
  -     by calling initContext(). Requests mapped to this context
  -     should report a "temporary unavailable" message.
  -     
  -
  -     All servlets will be destroyed, and resources held by the
  -     context will be freed.
  -
  -     The contextShutdown callbacks can wait until the running serlvets
  -     are completed - there is no way to force the shutdown.
  -     */
  -    public final void shutdownContext( Context ctx ) throws TomcatException {
  -     ctx.setState( Context.STATE_DISABLED ); // called before
  -     // the hook, no more request should be allowed in unstable state
  -
  -     BaseInterceptor cI[]=ctx.getContainer().getInterceptors();
  -     for( int i=0; i< cI.length; i++ ) {
  -         cI[i].contextShutdown( ctx );
  -     }
  -    }
  -
       // -------------------- Request processing / subRequest ------------------
       // -------------------- Main request processing methods ------------------
   
  @@ -1003,6 +919,16 @@
        return notes[pos];
       }
   
  +    public Object getNote( String name ) throws TomcatException {
  +     int id=getNoteId( SERVER_NOTE, name );
  +     return getNote( id );
  +    }
  +
  +    public void setNote( String name, Object value ) throws TomcatException {
  +     int id=getNoteId( SERVER_NOTE, name );
  +     setNote( id, value );
  +    }
  +    
       // -------------------- Logging and debug --------------------
       private Log loghelper = new Log("tc_log", "ContextManager");
   
  @@ -1032,7 +958,6 @@
       public final void addLogger(Logger l) {
        if (debug>20)
            log("addLogger: " + l, new Throwable("trace"), Logger.DEBUG);
  -        if( loggers==null ) loggers=new Hashtable();
           loggers.put(l.toString(),l);
       }
   
  @@ -1055,19 +980,4 @@
       public final void log(String msg, Throwable t, int level) {
           loghelper.log(msg, t, level);
       }
  -
  -    // -------------------- DEPRECATED --------------------
  -    /** System property used to set the random number generator
  -     */
  -    public static final String RANDOM_CLASS_PROPERTY=
  -     "tomcat.sessionid.randomclass";
  -
  -    // XXX RandomClass will be set on the interceptor that sets it
  -    //     public final String getRandomClass() {
  -    // XXX XXX @deprecated - use  interceptor properties
  -    public final void setRandomClass(String randomClass) {
  -        System.getProperties().put(RANDOM_CLASS_PROPERTY, randomClass);
  -    }
  -
  -
   }
  
  
  

Reply via email to