costin 00/12/02 00:27:05
Modified: src/share/org/apache/tomcat/core BaseInterceptor.java
ContextManager.java
src/share/org/apache/tomcat/request ReloadInterceptor.java
src/share/org/apache/tomcat/util/collections MultiMap.java
src/share/org/apache/tomcat/util/depend DependManager.java
src/share/org/apache/tomcat/util/http Parameters.java
Log:
- Fixed the documentation of ContextManager ( or started to ), fixed
the shutdown. Thanks Larry, I think now is better. I'll continue to
fix the code to match the documentation.
- fixed the compilation for jdk1.1.7 ( the compiler is buggy )
- make sure the "JVM is broken" is displayed only once, no need
to see it for every request.
Revision Changes Path
1.26 +5 -0
jakarta-tomcat/src/share/org/apache/tomcat/core/BaseInterceptor.java
Index: BaseInterceptor.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/BaseInterceptor.java,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- BaseInterceptor.java 2000/11/02 21:24:42 1.25
+++ BaseInterceptor.java 2000/12/02 08:26:45 1.26
@@ -247,6 +247,9 @@
*
* WebXmlReader needs to be the first interceptor in
* the contextInit chain.
+ *
+ * @exception If the interceptor throws exception the context will
+ * not be initialized ( state==NEW or ADDED or DISABLED ).
*/
public void contextInit(Context ctx)
throws TomcatException
@@ -307,6 +310,8 @@
}
/** Called when the ContextManger is started
+ * @exception TomcatException The server will not start if any exception is
thrown by
+ * engineInit
*/
public void engineInit(ContextManager cm)
throws TomcatException
1.153 +151 -94
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.152
retrieving revision 1.153
diff -u -r1.152 -r1.153
--- ContextManager.java 2000/12/01 17:42:51 1.152
+++ ContextManager.java 2000/12/02 08:26:47 1.153
@@ -90,76 +90,91 @@
One application may try to embed multiple ( distinct ) servlet containers -
this feature hasn't been tested or used
-
- Expected startup order:
+ <h2>Startup</h2>
- 1. Create ContextManager
+ 1. Create ContextManager.
- 2. Set settable properties for ContextManager ( home, debug, etc)
+ 2. Set properties for ContextManager ( home, debug, etc).
- 3. Add global Interceptors
+ 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. Call init(). At this stage engineInit() callback will be
- called for all global interceptors.
- - DefaultCMSetter ( or a replacement ) must be the first in
- the chain and will adjust the paths and set defaults for
- all unset properties.
- - AutoSetup and other interceptors can automatically add/set
- more properties and make other calls.
+ 5. init() At this stage engineInit() callback will be
+ called for all global interceptors.
- During engineInit() a number of Contexts are created and
+ During engineInit() a number of Contexts can be created and
added to the server. No addContext() callback is called until
- the last engineInit() returns. ( XXX do we need this restriction ?)
+ the last engineInit() returns. Interceptors can also change the
+ state of the server ( change properites, add other interceptors,
+ etc)
- XXX I'n not sure about contextInit and about anything below.
+ After this call the server will be in INITIALIZED state.
+ No callback other than engineInit can be called before the server
+ enters this state.
- x. Server will move to 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().
- x. addContext() callbacks will be called for each context.
- After init you may add more contexts, and addContext() callback
- will be called (since the server is initialized )
+ InitContext will have no effect before the server is started -
+ all initContexts for added contexts will be called automatically
+ at start.
- x. Call start().
+ 7. start(). All contexts will be initialized ( contextInit()
+ callback ). ContextInit will move the context to READY state,
+ allowing it to serve requests.
- x. All contexts will be initialized ( contextInit()
- callback ).
+ 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") .
- x. Server will move to STARTED state. No servlet should be
- served before this state.
+ <h2>Normal operation</h2>
-
- During normal operation, it is possible to add Contexts.
+ 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 !)
- 1. Create the Context, set properties ( that can be done from servlets
- or by interceptors like ~user)
+ 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.
- 2. call CM.addContext(). This will triger the addContext() callback.
- ( if CM is initialized )
+ 3. addContext(). This will triger the addContext() callback.
- 3. call CM.initContext( ctx ). This will triger contextInit() callback.
- After that the context is initialized and can serve requests.
- No request belonging to this context can't be served before this
- method returns.
+ 4. initContext(). This will triger contextInit() callbacks/
+ After that the context is READY and can serve requests.
- XXX Context state
-
- It is also possible to remove Contexts.
+ 5. You can find a Context by enumerating all added contexts.
- 1. Find the Context ( enumerate all existing contexts and find the one
- you need - host and path are most likely keys ).
+ 6. contextShutdown(). The context will no longer be READY and can't
+ serve requests ( Application unavailable ). contextShutdown hooks
+ are called
- 2. Call removeContext(). This will call removeContext() callbacks.
+ 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 )
-
- To stop the server, you need to:
+ <h2>Stopping the server</h2>
+
+ 1. stop(). The server will exit the START state and enter STOP,any request
+ will get a "Server unavailable" error. All contextShutdown() and
+ will be called. ( STOP==INIT ? )
- 1. Call shutdown().
+ 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 ? )
- 2. The server will ...
+ Notes:
+ DefaultCMSetter ( or a replacement ) must be the first in
+ the chain and will adjust the paths and set defaults for
+ all unset properties.
+ 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]]
@@ -385,39 +400,35 @@
*/
public final void init() throws TomcatException {
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 );
}
state=STATE_INIT;
- // delayed execution of addContext
+ // 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();
- cI=ctx.getContainer().getInterceptors();
- for( int i=0; i< cI.length; i++ ) {
- cI[i].addContext( this, ctx );
+ try {
+ cI=ctx.getContainer().getInterceptors();
+ for( int i=0; i< cI.length; i++ ) {
+ cI[i].addContext( this, ctx );
+ }
+ ctx.setState( Context.STATE_ADDED );
+ } catch( TomcatException ex ) {
+ log( "Context not added " + ctx , ex );
+ continue;
}
- ctx.setState( Context.STATE_ADDED );
- }
- }
-
- /** Remove all contexts.
- * - call removeContext ( that will call Interceptor.removeContext hooks )
- * - call Interceptor.engineShutdown() hooks.
- */
- public final void shutdown() throws TomcatException {
- while (!contextsV.isEmpty()) {
- removeContext((Context)contextsV.firstElement());
- }
-
- BaseInterceptor cI[]=defaultContainer.getInterceptors();
- for( int i=0; i< cI.length; i++ ) {
- cI[i].engineShutdown( this );
}
}
@@ -425,17 +436,24 @@
* 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);
+
Enumeration enum = getContexts();
while (enum.hasMoreElements()) {
Context ctx = (Context)enum.nextElement();
- BaseInterceptor cI[]=ctx.getContainer().getInterceptors();
- for( int i=0; i< cI.length; i++ ) {
- cI[i].contextInit( ctx );
+ try {
+ initContext( ctx );
+ } catch( TomcatException ex ) {
+ // just log the error, the context will not serve
+ // requests but we go on
+ log( "Error initializing " + ctx , ex );
+ continue;
}
- ctx.setState( Context.STATE_READY );
}
-
+
+ // requests can be processed now
state=STATE_START;
}
@@ -445,6 +463,21 @@
shutdown();
}
+ /** Remove all contexts.
+ * - call removeContext ( that will call Interceptor.removeContext hooks )
+ * - call Interceptor.engineShutdown() hooks.
+ */
+ public final void shutdown() throws TomcatException {
+ while (!contextsV.isEmpty()) {
+ removeContext((Context)contextsV.firstElement());
+ }
+
+ BaseInterceptor cI[]=defaultContainer.getInterceptors();
+ for( int i=0; i< cI.length; i++ ) {
+ cI[i].engineShutdown( this );
+ }
+ }
+
// -------------------- Contexts --------------------
/** Return the list of contexts managed by this server
@@ -465,22 +498,31 @@
* @param ctx context to be added.
*/
public final void addContext( Context ctx ) throws TomcatException {
- log("Adding context " + ctx.toString());
-
// Make sure context knows about its manager.
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 )
- return;
+ if( state == STATE_PRE_INIT ) {
+ log( "Delay context add " + ctx.toString());
+ return;
+ }
- BaseInterceptor cI[]=ctx.getContainer().getInterceptors();
- for( int i=0; i< cI.length; i++ ) {
- cI[i].addContext( this, ctx );
+ try {
+ BaseInterceptor cI[]=ctx.getContainer().getInterceptors();
+ for( int i=0; i< cI.length; i++ ) {
+ // If an exception is thrown, context will remain in
+ // NEW state.
+ cI[i].addContext( this, ctx );
+ }
+ ctx.setState( Context.STATE_ADDED );
+ log("Adding context " + ctx.toString());
+ } catch (TomcatException ex ) {
+ log( "Context not added " + ctx , ex );
+ throw ex;
}
- ctx.setState( Context.STATE_ADDED );
}
/** Shut down and removes a context from service.
@@ -489,24 +531,29 @@
if( context==null ) return;
log( "Removing context " + context.toString());
-
- // disable the context.
- if( context.getState() == Context.STATE_READY )
- shutdownContext( context );
contextsV.removeElement(context);
- if( context.getState() == Context.STATE_DISABLED )
+ // if it's already disabled - or was never activated,
+ // no need to shutdown and remove
+ if( context.getState() == Context.STATE_NEW )
return;
- context.setState( Context.STATE_NEW );
+ // 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 );
- // remove it from operation
+ // remove it from operation - notify interceptors that
+ // this context is no longer active
BaseInterceptor cI[]=context.getContainer().getInterceptors();
for( int i=0; i< cI.length; i++ ) {
cI[i].removeContext( this, context );
}
+ // mark the context as "not active"
+ context.setState( Context.STATE_NEW );
}
@@ -522,14 +569,21 @@
*
* 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 {
- if( state!= STATE_PRE_INIT ) {
- BaseInterceptor cI[]=ctx.getContainer().getInterceptors();
- for( int i=0; i< cI.length; i++ ) {
- cI[i].contextInit( ctx );
- }
+ // 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 );
}
@@ -542,10 +596,13 @@
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 request should be allowed in unstable state
+ // the hook, no more request should be allowed in unstable state
BaseInterceptor cI[]=ctx.getContainer().getInterceptors();
for( int i=0; i< cI.length; i++ ) {
1.9 +3 -0
jakarta-tomcat/src/share/org/apache/tomcat/request/ReloadInterceptor.java
Index: ReloadInterceptor.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/ReloadInterceptor.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- ReloadInterceptor.java 2000/11/02 21:44:50 1.8
+++ ReloadInterceptor.java 2000/12/02 08:26:49 1.9
@@ -125,6 +125,9 @@
if( ! ctx.shouldReload() ) return 0;
+ if( debug> 0 )
+ log( "Detected changes in " + ctx.toString());
+
try {
// Reload context.
ContextManager cm=ctx.getContextManager();
1.2 +8 -6
jakarta-tomcat/src/share/org/apache/tomcat/util/collections/MultiMap.java
Index: MultiMap.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/collections/MultiMap.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- MultiMap.java 2000/11/30 17:34:16 1.1
+++ MultiMap.java 2000/12/02 08:26:53 1.2
@@ -232,7 +232,7 @@
public int findNext( int startPos ) {
int next= fields[startPos].nextPos;
- if( next != Field.NEED_NEXT ) {
+ if( next != MultiMap.NEED_NEXT ) {
return next;
}
@@ -245,10 +245,14 @@
return i;
}
}
- fields[startPos].nextPos= Field.LAST;
+ fields[startPos].nextPos= MultiMap.LAST;
return -1;
}
+ // workaround for JDK1.1.8/solaris
+ static final int NEED_NEXT=-2;
+ static final int LAST=-1;
+
// -------------------- Internal representation --------------------
final class Field {
MessageBytes name;
@@ -258,8 +262,6 @@
// multiple fields with same name - a linked list will
// speed up multiple name enumerations and search.
- static final int NEED_NEXT=-2;
- static final int LAST=-1;
int nextPos;
// hashkey
@@ -267,13 +269,13 @@
Field nextSameHash;
Field() {
- nextPos=NEED_NEXT;
+ nextPos=MultiMap.NEED_NEXT;
}
void recycle() {
name.recycle();
value.recycle();
- nextPos=NEED_NEXT;
+ nextPos=MultiMap.NEED_NEXT;
}
}
}
1.3 +5 -2
jakarta-tomcat/src/share/org/apache/tomcat/util/depend/DependManager.java
Index: DependManager.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/depend/DependManager.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- DependManager.java 2000/12/01 23:15:22 1.2
+++ DependManager.java 2000/12/02 08:26:58 1.3
@@ -101,11 +101,14 @@
return checkCount;
}
+ private static boolean noWarnBadVM=true;
public boolean shouldReload() {
boolean b=shouldReload1();
- if( b!=expired)
+ if( b!=expired && noWarnBadVM ) {
log("BUG ( VM or Tomcat? ) shouldReload returns expired=" + b +
" and the real value is " + expired);
+ noWarnBadVM=false;
+ }
return expired;
}
@@ -173,7 +176,7 @@
// -------------------- Private
- private static final int debug=10;
+ private static final int debug=0;
void log( String s ) {
System.out.println("DependManager: " + s );
1.2 +15 -1
jakarta-tomcat/src/share/org/apache/tomcat/util/http/Parameters.java
Index: Parameters.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/http/Parameters.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Parameters.java 2000/11/30 17:42:49 1.1
+++ Parameters.java 2000/12/02 08:27:03 1.2
@@ -87,7 +87,21 @@
isSet=false;
isFormBased=false;
}
-
+ // XXX need better name
+ public boolean isEvaluated() {
+ return isSet;
+ }
+ public void setEvaluated( boolean b ) {
+ isSet=b;
+ }
+ // XXX need better name
+ public boolean hasFormData() {
+ return isFormBased;
+ }
+ public void setFormData(boolean b ) {
+ isFormBased=b;
+ }
+
// duplicated
public static int indexOf( byte bytes[], int off, int end, char qq )
{