costin 00/12/11 16:42:50
Modified: src/facade22/org/apache/tomcat/facade
Servlet22Interceptor.java ServletWrapper.java
WebXmlReader.java
src/facade22/org/apache/tomcat/modules/facade22
JspInterceptor.java
src/share/org/apache/tomcat/context ErrorHandler.java
src/share/org/apache/tomcat/core Context.java Handler.java
src/share/org/apache/tomcat/request AccessInterceptor.java
StaticInterceptor.java
src/share/org/apache/tomcat/startup Main.java
Log:
First round of refactoring for Handler/ServletWrapper. Reorganized the code
to make sure the right order of calls in the right state is enforced.
It seems that Handler is still too complex, and a lot of servlet-specific code
( like handling of init, UnavailableException, etc) need to be moved in
the right place ( ServletWrapper). The problem is that ServletWrapper is too
complex.
I'll start cleaning ServletWrapper and then move init/destroy - Handler will
then be a very simple and maintainable class. I need your review on this one,
please send comments if you find any problem.
Revision Changes Path
1.6 +4 -1
jakarta-tomcat/src/facade22/org/apache/tomcat/facade/Servlet22Interceptor.java
Index: Servlet22Interceptor.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat/src/facade22/org/apache/tomcat/facade/Servlet22Interceptor.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- Servlet22Interceptor.java 2000/11/02 21:51:39 1.5
+++ Servlet22Interceptor.java 2000/12/12 00:42:40 1.6
@@ -144,7 +144,10 @@
ServletWrapper sw=new ServletWrapper();
sw.setName( hN );
sw.setContext( ct.getContext() );
- log( "Create handler ");
+ // *.jsp -> jsp is a legacy default mapping
+ if( ! "jsp".equals(hN) ) {
+ log( "Create handler " + hN);
+ }
ct.setHandler(sw);
ct.getContext().addServlet( sw );
}
1.14 +124 -143
jakarta-tomcat/src/facade22/org/apache/tomcat/facade/ServletWrapper.java
Index: ServletWrapper.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat/src/facade22/org/apache/tomcat/facade/ServletWrapper.java,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- ServletWrapper.java 2000/12/08 23:18:29 1.13
+++ ServletWrapper.java 2000/12/12 00:42:40 1.14
@@ -124,8 +124,19 @@
public String toString() {
if( path==null )
return "Servlet " + name + "(" + servletClassName + ")";
- return "Jsp " + name + "(" + path + ")";
+ return "Jsp " + name + "(" + path + "/" + servletClassName + ")";
}
+
+ // -------------------- Configuration hook
+
+ /** This method can called to add the servlet to the web application.
+ * ( typlically used from the config - WebXmlReader ).
+ */
+ public void addServlet(Context ctx) throws TomcatException {
+ context=ctx;
+ // System.out.println("Adding servlet " + this );
+ context.addServlet( this );
+ }
// -------------------- Servlet specific properties
public void setLoadOnStartUp( int level ) {
@@ -170,17 +181,21 @@
}
public String getServletClass() {
- return this.servletClassName;
+ return getServletClassName();
}
public String getServletClassName() {
- return this.servletClassName;
+ if( servletClassName == null )
+ servletClassName=name;
+ return servletClassName;
}
public void setServletClassName(String servletClassName) {
servlet=null; // reset the servlet, if it was set
servletClass=null;
this.servletClassName=servletClassName;
+ if( debug>0 && path!=null)
+ log( "setServletClassName for jsp " + servletClassName);
}
public void setServletClass(String servletClassName) {
setServletClassName(servletClassName);
@@ -191,7 +206,8 @@
if ( ex != null ) {
if ( ex instanceof UnavailableException &&
! ((UnavailableException)ex).isPermanent()) {
- // make updated UnavailableException, reporting a minimum of 1 second
+ // make updated UnavailableException, reporting a minimum
+ // of 1 second
int secs=1;
long moreWaitTime=unavailableTime - System.currentTimeMillis();
if( moreWaitTime > 0 )
@@ -204,7 +220,7 @@
public void reload() {
- if( initialized ) {
+ if( getState()==STATE_READY ) {
try {
destroy();
} catch(Exception ex ) {
@@ -212,12 +228,12 @@
}
}
- if( servletClassName != null ) {
+ if( getServletClassName() != null ) {
// I can survive reload
servlet=null;
servletClass=null;
}
- initialized=false;
+ setState( STATE_ADDED );
}
/** Security Role Ref represent a mapping between servlet role names and
@@ -247,7 +263,9 @@
// --------------------
public Servlet getServlet() {
+
if(servlet==null) {
+ System.out.println("XXX getServlet for un-loaded servlet ");
try {
loadServlet();
} catch( Exception ex ) {
@@ -303,116 +321,80 @@
}
}
+ // Special hook
+ protected void preInit() throws Exception
+ {
+ if( debug > 0 )
+ log( "preInit " + servlet + " " + path + " " + servletClassName);
+
+ // Deal with Unavailable errors
+ if( ! checkErrorExpired() ) {
+ // init can't proceed
+ setState( STATE_DELAYED_INIT );
+ return;
+ }
+
+ // For JSPs we rely on JspInterceptor to set the servlet class name.
+ // We make no distinction between servlets and jsps.
+ loadServlet();
+ }
+
/** Load and init a the servlet pointed by this wrapper
*/
private void loadServlet()
throws ClassNotFoundException, InstantiationException,
IllegalAccessException
{
- // XXX Move this to an interceptor, so it will be configurable.
- // ( and easier to read )
- // log("LoadServlet " + servletClass + " "
- // + servletClassName);
+ if( debug>0)
+ log("LoadServlet " + name + " " + servletName + " " +
+ servletClass + " " + servletClassName);
// default
if( servletClassName==null )
- servletClassName=servletName;
+ servletClassName=name;
if (servletClass == null) {
- if (servletClassName == null) {
- // It happens :-(
- throw new IllegalStateException("Can't happen - classname "
- + "is null, who added this ?");
- }
servletClass=context.getClassLoader().loadClass(servletClassName);
}
servlet = (Servlet)servletClass.newInstance();
-
- // hack for internal servlets
- if( ! servletClassName.startsWith("org.apache.tomcat") ) return;
}
- /** Override Handler's init - load the servlet before calling
- and interceptor
- */
- public void init()
- throws Exception
- {
- // if initialized, then we were sync blocked when first init() succeeded
- if( initialized ) return;
- // if exception present, then we were sync blocked when first init() failed
- // or an interceptor set an inital exeception
- // in the latter case, preServletInit() and postServletInit() interceptors
- // don't get called
- if ( isExceptionPresent() ) return;
-
- // make sure the servlet is loaded before calling preInit
- // Jsp case - maybe another Jsp engine is used
-
- if( servlet==null && path != null && ! jspServletInitialized ) {
- // log("Calling handleJspInit " + servletClassName);
- // dual mode
- handleJspInit();
- jspServletInitialized=true;
- }
- if( servlet==null ) {
- // try to load servlet, save exception if one occurs
- try {
- loadServlet();
- } catch ( Exception ex ) {
- // save init exception
- setErrorException( ex );
- setExceptionPermanent( true );
- return;
- }
- }
-
- // Call pre, doInit and post
- BaseInterceptor cI[]=context.getContainer().getInterceptors();
- for( int i=0; i< cI.length; i++ ) {
- try {
- cI[i].preServletInit( context, this );
- } catch( TomcatException ex) {
- log("preServletInit" , ex);
- }
- }
-
- doInit();
-
- // doInit() catches exceptions, so post interceptors are always called
- for( int i=0; i< cI.length; i++ ) {
- try {
- cI[i].postServletInit( context, this );
- } catch( TomcatException ex) {
- log("postServletInit" , ex);
- }
- }
+ public ServletConfig getServletConfig() {
+ if( configF==null )
+ configF=new ServletConfigImpl( this );
+ return configF;
}
-
+
protected void doInit()
throws Exception
{
isReloadable=context.getReloadable();
configF = new ServletConfigImpl(this);
- // ASSERT synchronized at higher level, initialized must be false
try {
final Servlet sinstance = servlet;
final ServletConfig servletConfig = configF;
servlet.init(servletConfig);
- initialized=true;
} catch( UnavailableException ex ) {
- setServletUnavailable( ex );
- servlet=null;
- } catch( Exception ex ) {
- // other init exceptions are treated as permanent
- // XXX need a context setting for unavailable time
- setErrorException(ex);
- setExceptionPermanent(true);
+ // Implement the "UnavailableException" specification
+ // servlet exception state
+ setErrorException( ex );
+ if ( ex.isPermanent() ) {
+ setState( STATE_DISABLED );
+ } else {
+ setState( STATE_DELAYED_INIT );
+ setServletUnavailable( ex );
+ }
servlet=null;
+ throw ex;
+ // it's a normal exception, servlet will
+ // not be initialized.
}
+
+ // other exceptions are just thrown -
+ // init() will deal with them.
}
protected void doService(Request req, Response res)
@@ -428,11 +410,16 @@
req.getContext().getPath() + "/" + path );
req.setAttribute( "javax.servlet.include.servlet_path", path );
}
+
- // if servlet is not available
- if ( isExceptionPresent() ) {
- // get if error has expired
- checkErrorExpired( req, res );
+ // if unavailable
+ if( ! checkErrorExpired() ) {
+ // if error still present
+ Exception ex=getErrorException();
+ if( ex!=null ) {
+ // save error state on request and response
+ saveError( req, res, ex );
+ }
// if we have an error on this request
if ( req.isExceptionPresent()) {
// if in included, defer handling to higher level
@@ -441,8 +428,7 @@
// otherwise handle error
contextM.handleError( req, res, getErrorException());
}
- context.log(getServletName() +
- " unavailable time expired, trying again ");
+ return; // we can't handle it
}
// Get facades - each req have one facade per context
@@ -463,26 +449,30 @@
req.setFacade( reqF );
res.setFacade( resF );
}
+
+ if( servlet==null ) {
+ System.out.println("XXX servlet==null " + getState() );
+ loadServlet();
+ }
try {
doService( reqF, resF );
- } catch ( Exception ex ) {
- // support for UnavailableException
- if ( ex instanceof UnavailableException ) {
- // if error not set
- if ( ! isExceptionPresent() ) {
- synchronized(this) {
- if ( ! isExceptionPresent() ) {
- setServletUnavailable( (UnavailableException)ex );
- // XXX if the UnavailableException is permanent we are
supposed
- // to destroy the servlet. Synchronization of this
destruction
- // needs review before adding this.
- }
+ } catch ( UnavailableException ex ) {
+ if ( ex.isPermanent() ) {
+ setState( STATE_DISABLED );
+ } else {
+ setServletUnavailable((UnavailableException)ex );
+ }
+ if ( null != getErrorException() ) {
+ synchronized(this) {
+ if ( null!= getErrorException() ) {
+ // servlet exception state
+ setErrorException( ex );
}
}
}
- throw ex; // will be saved/handled by Handler
}
+ // other exceptions will be thrown
}
protected void doService(HttpServletRequest req, HttpServletResponse res)
@@ -501,55 +491,46 @@
// -------------------- Jsp hooks
ServletWrapper jspServletW=null;
- // <servlet><jsp-file> case - we know it's a jsp
- void handleJspInit() {
- // XXX Jsp Servlet is initialized, the servlet is not generated -
- // we can't hook in! It's jspServet that has to pass the config -
- // but it can't so easily, plus it'll have to hook in.
- // I don't think that ever worked anyway - and I don't think
- // it can work without integrating Jsp handling into tomcat
- // ( using interceptor )
- jspServletW = (ServletWrapper)context.getServletByName("jsp");
- servletClassName = jspServletW.getServletClass();
- }
+// // <servlet><jsp-file> case - we know it's a jsp
+// void handleJspInit() {
+// // XXX Jsp Servlet is initialized, the servlet is not generated -
+// // we can't hook in! It's jspServet that has to pass the config -
+// // but it can't so easily, plus it'll have to hook in.
+// // I don't think that ever worked anyway - and I don't think
+// // it can work without integrating Jsp handling into tomcat
+// // ( using interceptor )
+// jspServletW = (ServletWrapper)context.getServletByName("jsp");
+// servletClassName = jspServletW.getServletClass();
+// }
// -------------------- Utility methods --------------------
+ /** Set unavailable time
+ */
private void setServletUnavailable( UnavailableException ex ) {
- // servlet exception state
- setErrorException( ex );
- if ( ex.isPermanent() ) {
- setExceptionPermanent( true );
- } else {
- setExceptionPermanent( false );
- unavailableTime=System.currentTimeMillis();
- unavailableTime += ex.getUnavailableSeconds() * 1000;
- }
+ unavailableTime=System.currentTimeMillis();
+ unavailableTime += ex.getUnavailableSeconds() * 1000;
}
/** Check if error exception is present and if so, has the error
expired. Sets error on request and response if un-expired
error found.
*/
-
- private void checkErrorExpired( Request req, Response res ) {
- // synchronize so another request can't expire the error
- synchronized(this) {
- // if error still present
- if ( isExceptionPresent() ) {
- // if permanent exception or timer not expired
- if ( isExceptionPermanent() ||
- (unavailableTime - System.currentTimeMillis()) > 0) {
- // save error state on request and response
- saveError( req, res, getErrorException() );
- } else {
- // we can try again
- setErrorException(null);
- setExceptionPermanent(false);
- unavailableTime=-1;
- }
- }
+ private boolean checkErrorExpired() {
+ if( unavailableTime == -1 )
+ return true;
+
+ // if permanent exception this code isn't called
+ // if timer not expired
+ if ( (unavailableTime - System.currentTimeMillis()) < 0) {
+ // we can try again
+ setErrorException(null);
+ unavailableTime=-1;
+ context.log(getServletName() +
+ " unavailable time expired, trying again ");
+ return true;
}
+ // still unavailable
+ return false;
}
-
}
1.6 +14 -3
jakarta-tomcat/src/facade22/org/apache/tomcat/facade/WebXmlReader.java
Index: WebXmlReader.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat/src/facade22/org/apache/tomcat/facade/WebXmlReader.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- WebXmlReader.java 2000/12/08 23:18:29 1.5
+++ WebXmlReader.java 2000/12/12 00:42:40 1.6
@@ -53,8 +53,8 @@
throws TomcatException
{
// addServlet( ctx, "default",
"org.apache.tomcat.servlets.DefaultServlet");
-// addServlet( ctx, "invoker", "org.apache.tomcat.servlets.InvokerServlet");
- Handler sw=addServlet( ctx, "jsp", "org.apache.jasper.servlet.JspServlet");
+ // addServlet( ctx, "invoker",
"org.apache.tomcat.servlets.InvokerServlet");
+ // Handler sw=addServlet( ctx, "jsp",
"org.apache.jasper.servlet.JspServlet");
// sw.addInitParam("jspCompilerPlugin",
"org.apache.jasper.compiler.JikesJavaCompiler");
// ctx.addServletMapping( "/servlet/*", "invoker");
@@ -187,7 +187,18 @@
// Servlet
xh.addRule("web-app/servlet",
xh.objectCreate("org.apache.tomcat.facade.ServletWrapper") ); // servlet-wrapper
xh.addRule("web-app/servlet", xh.setParent( "setContext") ); // remove it
from stack when done
- xh.addRule("web-app/servlet", xh.addChild("addServlet",
"org.apache.tomcat.core.Handler") );
+ // xh.addRule("web-app/servlet", xh.addChild("addServlet",
"org.apache.tomcat.core.Handler") );
+
+ xh.addRule("web-app/servlet", new XmlAction() {
+ public void end( SaxContext xctx)
+ throws Exception {
+ ServletWrapper sw=(ServletWrapper)
+ xctx.currentObject();
+ Context cctx=(Context)xctx.previousObject();
+ sw.addServlet(cctx);
+ }
+ }
+ );
// remove it from stack when done
xh.addRule("web-app/servlet/servlet-name",
xh.methodSetter("setServletName",0) );
xh.addRule("web-app/servlet/servlet-class",
xh.methodSetter("setServletClass",0));
1.14 +6 -1
jakarta-tomcat/src/facade22/org/apache/tomcat/modules/facade22/JspInterceptor.java
Index: JspInterceptor.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat/src/facade22/org/apache/tomcat/modules/facade22/JspInterceptor.java,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- JspInterceptor.java 2000/12/08 23:18:33 1.13
+++ JspInterceptor.java 2000/12/12 00:42:42 1.14
@@ -122,9 +122,14 @@
}
}
+ /** Set the HttpJspBase classloader before init,
+ as required by Jasper
+ */
public void preServletInit( Context ctx, Handler sw )
throws TomcatException
{
+ if( ! (sw instanceof ServletWrapper) )
+ return;
Servlet theServlet = ((ServletWrapper)sw).getServlet();
if (theServlet instanceof HttpJspBase) {
if( debug > 0 )
@@ -224,7 +229,7 @@
// set initial exception on the servlet if one is present
if ( jspInfo.isExceptionPresent() ) {
wrapper.setErrorException(jspInfo.getCompileException());
- wrapper.setExceptionPermanent(true);
+ wrapper.setState(Handler.STATE_DISABLED);
}
} catch( TomcatException ex ) {
log("mapJspPage: request=" + req + ", jspInfo=" + jspInfo + ",
servletName=" + servletName + ", classN=" + classN, ex);
1.11 +10 -18
jakarta-tomcat/src/share/org/apache/tomcat/context/ErrorHandler.java
Index: ErrorHandler.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/context/ErrorHandler.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- ErrorHandler.java 2000/12/08 23:18:40 1.10
+++ ErrorHandler.java 2000/12/12 00:42:43 1.11
@@ -179,16 +179,14 @@
if( debug>0 )
ctx.log( "Handler " + errorServlet + " " + errorPath);
- try {
- errorServlet.service( req, res );
- } catch( IOException e ) {
- // ASSERT: Only thrown by included servlets
- // we can ignore it and it's very common - probably the user
+ errorServlet.service( req, res );
+ Exception ex=res.getErrorException();
+ if( ex!=null && ! (ex instanceof IOException) ) {
+ // we can ignore IOException - probably the user
// has clicked "STOP"
- } catch( Exception e ) {
// we need to log any other error - something may be
// broken if the error servlet has errors.
- ctx.log( "Error in errorServlet", e);
+ ctx.log( "Error in errorServlet", ex);
}
}
@@ -280,16 +278,14 @@
if( debug>0 )
ctx.log( "Handler " + errorServlet + " " + errorPath);
- try {
- errorServlet.service( req, res );
- } catch( IOException e ) {
- // ASSERT: Only thrown by included servlets
- // we can ignore it and it's very common - probably the user
+ errorServlet.service( req, res );
+ Exception ex=res.getErrorException();
+ if( ! (ex instanceof IOException) ) {
+ // we can ignore IOException - probably the user
// has clicked "STOP"
- } catch( Exception e ) {
// we need to log any other error - something may be
// broken if the error servlet has errors.
- ctx.log( "Error in errorServlet", e);
+ ctx.log( "Error in errorServlet", ex);
}
}
@@ -335,7 +331,6 @@
int sbNote=0;
NotFoundHandler() {
- initialized=true;
setOrigin( Handler.ORIGIN_INTERNAL );
name="tomcat.notFoundHandler";
}
@@ -388,7 +383,6 @@
int sbNote=0;
ExceptionHandler() {
- initialized=true;
setOrigin( Handler.ORIGIN_INTERNAL );
name="tomcat.exceptionHandler";
}
@@ -462,7 +456,6 @@
int sbNote=0;
StatusHandler() {
- initialized=true;
setOrigin( Handler.ORIGIN_INTERNAL );
name="tomcat.statusHandler";
}
@@ -523,7 +516,6 @@
int sbNote=0;
RedirectHandler() {
- initialized=true;
setOrigin( Handler.ORIGIN_INTERNAL );
name="tomcat.redirectHandler";
}
1.128 +4 -0 jakarta-tomcat/src/share/org/apache/tomcat/core/Context.java
Index: Context.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/Context.java,v
retrieving revision 1.127
retrieving revision 1.128
diff -u -r1.127 -r1.128
--- Context.java 2000/11/20 21:00:54 1.127
+++ Context.java 2000/12/12 00:42:44 1.128
@@ -820,6 +820,7 @@
throws TomcatException
{
wrapper.setContext( this );
+ wrapper.setState( Handler.STATE_ADDED );
String name=wrapper.getName();
// check for duplicates
@@ -835,6 +836,9 @@
public final void removeServletByName(String servletName)
throws TomcatException
{
+ Handler h=getServletByName( servletName );
+ if( h!=null )
+ h.setState( Handler.STATE_NEW );
servlets.remove( servletName );
}
1.26 +168 -75 jakarta-tomcat/src/share/org/apache/tomcat/core/Handler.java
Index: Handler.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/Handler.java,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- Handler.java 2000/12/08 23:18:43 1.25
+++ Handler.java 2000/12/12 00:42:46 1.26
@@ -135,15 +135,43 @@
// -------------------- State --------------------
+ /** The handler is new, not part of any application.
+ * You must to add the handler to application before doing
+ * anything else.
+ * To ADDED by calling Context.addHandler().
+ * From ADDED by calling Context.removeHandler();
+ */
public static final int STATE_NEW=0;
+ /** The handler is added to an application and can be initialized.
+ * To READY by calling init(), if success
+ * TO DISABLED by calling init if it fails ( exception )
+ * From READY by calling destroy()
+ */
public static final int STATE_ADDED=1;
-
- public static final int STATE_READY=2;
-
- public static final int STATE_TEMP_DISABLED=3;
+ /**
+ * If init() fails or preInit() detects the handler is still
+ * unavailable.
+ */
+ public static final int STATE_DELAYED_INIT=2;
+
+ /** The handler has been succesfully initialized and is ready to
+ * serve requests. If the handler is not in this state a 500 error
+ * should be reported. ( customize - may be 404 )
+ * To ADDED by calling destroy()
+ * FROM ADDED by calling init()
+ */
+ public static final int STATE_READY=3;
+
+ /** Handler is unable to perform - any attempt to use it should
+ * report an internal error. This is the result of an internal
+ * exception or an error in init()
+ * To ADDED by calling destroy()
+ * From ADDED by calling init() ( if failure )
+ */
public static final int STATE_DISABLED=4;
+
// -------------------- Properties --------------------
@@ -152,13 +180,8 @@
protected String name;
- protected int state=STATE_NEW;
+ private int state=STATE_NEW;
- /** True if it can handle requests.
- 404 or error if not.
- */
- protected boolean initialized=false;
-
Hashtable initArgs=null;
// who creates the servlet definition
@@ -172,7 +195,6 @@
protected boolean loadingOnStartup=false;
protected Exception errorException=null;
- protected boolean exceptionPermanent=false;
// Debug
protected int debug=0;
@@ -278,18 +300,6 @@
return errorException;
}
- public boolean isExceptionPresent() {
- return ( errorException != null );
- }
-
- public void setExceptionPermanent( boolean permanent ) {
- exceptionPermanent = permanent;
- }
-
- public boolean isExceptionPermanent() {
- return exceptionPermanent;
- }
-
// -------------------- Jsp specific code
public String getPath() {
@@ -335,47 +345,115 @@
/** Destroy a handler, and notify all the interested interceptors
*/
- public final void destroy() throws Exception {
- if ( ! initialized ) {
+ public final void destroy() {
+ if ( state!=STATE_READY ) {
+ // reset exception
errorException = null;
return;// already destroyed or not init.
}
- initialized=false;
+ setState( STATE_ADDED );
// XXX post will not be called if any error happens in destroy.
// That's how tomcat worked before - I think it's a bug !
- doDestroy();
+ try {
+ doDestroy();
+ } catch( Exception ex ) {
+ log( "Error during destroy ", ex );
+ }
+
errorException=null;
}
/** Call the init method, and notify all interested listeners.
+ * This is a final method to insure consistent behavior on errors.
+ * It also saves handlers from dealing with synchronization issues.
*/
- public /* final */ void init()
- throws Exception
+ public final void init()
{
- // if initialized, then we were sync blocked when first init() succeeded
- if( initialized ) return;
- // if exception present, then we were sync blocked when first init() failed
- // or an interceptor set an inital exeception
- if (errorException != null) throw errorException;
- try {
- doInit();
- initialized=true;
- } catch( Exception ex ) {
- // save error, assume permanent
- setErrorException(ex);
- setExceptionPermanent(true);
+ // we use getState() as a workaround for bugs in VMs
+
+ if( getState() == STATE_READY || getState() == STATE_DISABLED )
+ return;
+
+ synchronized( this ) {
+ // check again - if 2 threads are in init(), the first one will
+ // init and the second will enter the sync block after that
+ if( getState() == STATE_READY )
+ return;
+
+ // if exception present, then we were sync blocked when first
+ // init() failed or an interceptor set an inital exeception
+ // A different thread got an error in init() - throw
+ // the same error.
+ if (getState() == STATE_DISABLED )
+ return; //throw errorException;
+
+ try {
+ // special preInit() hook
+ preInit();
+ // preInit may either throw exception or setState DELAYED_INIT
+ } catch( Exception ex ) {
+ // save error, assume permanent
+ log("Exception in preInit " + ex.getMessage(), ex );
+ setErrorException(ex);
+ setState(STATE_DISABLED);
+ return;
+ }
+
+ // we'll try again later
+ if( getState() == STATE_DELAYED_INIT ||
+ getState()==STATE_DISABLED ) { // or disabled
+ return;
+ }
+ // preInit have no exceptions and doesn't delay us
+ // We can run init hooks and init
+
+ // Call pre, doInit and post
+ BaseInterceptor cI[]=context.getContainer().getInterceptors();
+ for( int i=0; i< cI.length; i++ ) {
+ try {
+ cI[i].preServletInit( context, this );
+ } catch( TomcatException ex) {
+ // log, but ignore.
+ log("preServletInit" , ex);
+ }
+ }
+
+ try {
+ doInit();
+ // if success, we are ready to serve
+ } catch( Exception ex ) {
+ // save error, assume permanent
+ log("Exception in init " + ex.getMessage(), ex );
+ setErrorException(ex);
+ state=STATE_DISABLED;
+ }
+
+ for( int i=0; i< cI.length; i++ ) {
+ try {
+ cI[i].postServletInit( context, this );
+ } catch( TomcatException ex) {
+ log("postServletInit" , ex);
+ }
+ }
+
+ // Now that both pre/post hooks have been called, the
+ // servlet is ready to serve.
+
+ // We are still in the sync block, that means other threads
+ // are waiting for this to be over.
+
+ // if no error happened and if doInit didn't put us in
+ // a special state, we are ready
+ if( state!=STATE_DISABLED &&
+ getErrorException() != null ) {
+ state=STATE_READY;
+ }
}
}
- // XXX XXX XXX
- // Must be changed - it's very confusing since it has the same name
- // with the servlet's service() method.
- // The Handler is at a different ( lower ) level, we should
- // use different names ( invoke() ? )
-
/** Call the service method, and notify all listeners
*
* @exception Exception if an error happens during handling of
@@ -391,28 +469,16 @@
* runtime exceptions )
*/
public final void service(Request req, Response res)
- throws Exception
{
- if( ! initialized ) {
- Exception ex=null;
- synchronized( this ) {
- // we may be initialized when we enter the sync block
- if( ! initialized ) {
- try {
- init();
- } catch ( Exception e ) {
- errorException = e;
- exceptionPermanent = true;
- }
- }
- // get copy of exception, if any, before leaving sync lock
- ex=errorException;
+ if( state!=STATE_READY ) {
+ if( state!= STATE_DISABLED ) {
+ init();
}
- // if error occurred
- if ( ex != null ) {
+ if( state== STATE_DISABLED ) {
+ // the init failed because of an exception
+ Exception ex=getErrorException();
// save error state on request and response
saveError( req, res, ex );
- log("Exception in init " + ex.getMessage(), ex );
// if in included, defer handling to higher level
if (res.isIncluded()) return;
// handle init error since at top level
@@ -421,43 +487,51 @@
else
contextM.handleError( req, res, ex );
return;
- }
+ }
}
- // if( ! internal ) {
- // no distinction for internal handlers !
BaseInterceptor reqI[]=
req.getContainer().getInterceptors(Container.H_preService);
for( int i=0; i< reqI.length; i++ ) {
reqI[i].preService( req, res );
}
- //}
+ Exception serviceException=null;
try {
doService( req, res );
} catch( Exception ex ) {
// save error state on request and response
- saveError( req, res, ex );
+ serviceException=ex;
+ saveError( req, res, ex);
}
- // continue with the postService
- // if( ! internal ) {
+ // continue with the postService ( roll back transactions, etc )
reqI=req.getContainer().getInterceptors(Container.H_postService);
for( int i=0; i< reqI.length; i++ ) {
reqI[i].postService( req, res );
}
- // }
// if no error
- if( ! res.isExceptionPresent() ) return;
+ if( serviceException == null ) return;
+
// if in included, defer handling to higher level
if (res.isIncluded()) return;
+
// handle original error since at top level
contextM.handleError( req, res, res.getErrorException() );
}
// -------------------- methods you can override --------------------
+ protected void handleInitError( Throwable t ) {
+
+ }
+
+ protected void handleServiceError( Request req, Response res, Throwable t )
+ {
+
+ }
+
/** Reload notification. This hook is called whenever the
* application ( this handler ) is reloaded
*/
@@ -471,6 +545,22 @@
}
+ /** Special hook called before init and init hooks.
+ *
+ * This hook will set the state of the handler for the init() hooks
+ * ( for example load the servlet class, other critical preparations ).
+ * If it fails, the servlet will be disabled and no other call will
+ * succed.
+ * The hook can also delay initialization ( put handler in DELAY_INIT
+ * state ). The application will be unavailable ( no service will be
+ * called ), and preInit will be called to check if the state changed.
+ * ( this can be used to implement UnavailableException )
+ *
+ */
+ protected void preInit() throws Exception {
+
+ }
+
/** Initialize the handler. Handler can override this
* method to initialize themself.
*/
@@ -505,7 +595,10 @@
protected final void log( String s ) {
if ( logger==null )
- contextM.log(s);
+ if( contextM!=null )
+ contextM.log(s);
+ else
+ System.out.println("(cm==null) " + s );
else
logger.log(s);
}
1.26 +4 -5
jakarta-tomcat/src/share/org/apache/tomcat/request/AccessInterceptor.java
Index: AccessInterceptor.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/AccessInterceptor.java,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- AccessInterceptor.java 2000/12/08 23:18:48 1.25
+++ AccessInterceptor.java 2000/12/12 00:42:48 1.26
@@ -216,8 +216,10 @@
Container ctxCt=ctx.getContainer();
SecurityConstraints ctxSecurityC=(SecurityConstraints)ctxCt.
getNote( secMapNote );
- if( ctxSecurityC==null)
- ctxCt.setNote( secMapNote, new SecurityConstraints() );
+ if( ctxSecurityC==null) {
+ ctxSecurityC= new SecurityConstraints();
+ ctxCt.setNote( secMapNote, ctxSecurityC );
+ }
if( ct.getRoles()!=null || ct.getTransport()!=null ) {
if( debug > 0 )
@@ -342,7 +344,6 @@
int sbNote=0;
BasicAuthHandler() {
- initialized=true;
setOrigin( Handler.ORIGIN_INTERNAL );
name="tomcat.basicAuthHandler";
}
@@ -389,7 +390,6 @@
class FormAuthHandler extends Handler {
FormAuthHandler() {
- initialized=true;
setOrigin( Handler.ORIGIN_INTERNAL );
name="tomcat.formAuthHandler";
}
@@ -447,7 +447,6 @@
class FormSecurityCheckHandler extends Handler {
FormSecurityCheckHandler() {
- initialized=true;
setOrigin( Handler.ORIGIN_INTERNAL );
name="tomcat.formSecurityCheck";
}
1.26 +0 -2
jakarta-tomcat/src/share/org/apache/tomcat/request/StaticInterceptor.java
Index: StaticInterceptor.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/StaticInterceptor.java,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- StaticInterceptor.java 2000/12/08 23:18:49 1.25
+++ StaticInterceptor.java 2000/12/12 00:42:48 1.26
@@ -217,7 +217,6 @@
int realFileNote;
FileHandler() {
- initialized=true;
setOrigin( Handler.ORIGIN_INTERNAL );
name="tomcat.fileHandler";
}
@@ -329,7 +328,6 @@
int sbNote=0;
DirHandler() {
- initialized=true;
setOrigin( Handler.ORIGIN_INTERNAL );
name="tomcat.dirHandler";
}
1.15 +1 -1 jakarta-tomcat/src/share/org/apache/tomcat/startup/Main.java
Index: Main.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/startup/Main.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- Main.java 2000/11/30 06:17:13 1.14
+++ Main.java 2000/12/12 00:42:49 1.15
@@ -282,7 +282,7 @@
"org.apache.tomcat.task.StartTomcat");
processArgs( proxy, args );
setAttribute( proxy, "parentClassLoader", parentL );
- setAttribute( proxy, "serverClassPath", urls );
+ // setAttribute( proxy, "serverClassPath", urls );
execute( proxy, "execute" );
return;
} catch( Exception ex ) {