|
What this is
Other links
The source code/* * Copyright 1999-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.tomcat.facade; import javax.servlet.Servlet; import javax.servlet.SingleThreadModel; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.tomcat.core.BaseInterceptor; import org.apache.tomcat.core.Container; import org.apache.tomcat.core.Context; import org.apache.tomcat.core.Handler; import org.apache.tomcat.core.Request; import org.apache.tomcat.core.Response; import org.apache.tomcat.core.TomcatException; import org.apache.tomcat.util.collections.SimplePool; /** * Handler for servlets. It'll implement all servlet-specific * requirements ( init, Unavailable exception, etc). * * It is also used for Jsps ( since a Jsp is a servlet ), but * requires the Jsp interceptor to make sure that indeed a Jsp is * a servlet ( and set the class name ). * * The old Jsp hack is no longer supported ( i.e. declaring a servlet * with the name jsp, mapping *.jsp -> jsp will work as required * by the servlet spec - no special hook is provided for initialization ). * Note that JspServlet doesn't work without special cases in ServletWrapper. * * @author James Duncan Davidson [duncan@eng.sun.com] * @author Jason Hunter [jch@eng.sun.com] * @author James Todd [gonzo@eng.sun.com] * @author Harish Prabandham * @author Costin Manolache */ public final class ServletHandler extends Handler { /** * 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() * To DISABLED if permanent UnavailableException in service() * FROM ADDED by calling init() * * Note: Once this state is reached, only UnavailableExceptions are * stored in errorException. */ public static final int STATE_READY=3; // -------------------- Properties -------------------- // extra informations - if the servlet is declared in web.xml private ServletInfo sw; private String servletClassName; private SimplePool stmPool=null; private int stmPoolSize=SimplePool.DEFAULT_SIZE; private int stmInstances=0; private boolean useStmPool=true; protected Class servletClass; protected Servlet servlet; protected Context context; // If init() fails, Handler.errorException will hold the reason. // In the case of an UnavailableException, this field will hold // the expiration time if UnavailableException is not permanent. long unavailableTime=-1; public ServletHandler() { super(); } public String toString() { return "ServletH " + name + "(" + sw + ")"; } public void setServletInfo( ServletInfo sw ) { this.sw=sw; } public void setUseSTMPool(boolean useP){ useStmPool = useP; } public void setSTMPoolSize(int size) { stmPoolSize = size; } public ServletInfo getServletInfo() { if( sw==null ) { // it is possible to create a handler without ServletInfo // defaults are used. sw=new ServletInfo(this); } return sw; } /** */ public void setContext( Context context) { this.context = context; } /** Return the context associated with the handler */ public Context getContext() { return context; } public void setServletClassName( String servletClassName) { servlet=null; // reset the servlet, if it was set servletClass=null; this.servletClassName=servletClassName; if( debug>0 && sw!=null && sw.getJspFile()!=null) log( context, "setServletClassName for " + sw.getJspFile() + ": " + servletClassName); } public String getServletClassName() { if( servletClassName == null ) servletClassName=name; return servletClassName; } // -------------------- Init/destroy -------------------- // from Handler /** Destroy a handler, and notify all the interested interceptors */ public final void destroy() { if ( state!=STATE_READY ) { // reset exception errorException = null; return;// already destroyed or not init. } // XXX if we are being destroyed due to permanent UnavailableException // thrown in service(), we probably don't want to go to ADDED state. // may need a STATE_DISABLE_PERM? 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 ! try { doDestroy(); } catch( Exception ex ) { log(context, "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 synchronized void init() { // we use getState() as a workaround for bugs in VMs if( getState() == STATE_READY || getState() == STATE_DISABLED ) return; try { // special preInit() hook preInit(); // preInit may either throw exception or setState DELAYED_INIT } catch( ClassNotFoundException ex ) { log( context, "Class not found: " + servletClassName); setErrorException(ex); setState(STATE_DISABLED); return; } catch( Exception ex ) { // save error, assume permanent log(context, "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(context, "preServletInit" , ex); } } try { doInit(); // if success, we are ready to serve } catch( Exception ex ) { // save error, assume permanent log(context, "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(context, "postServletInit" , ex); } } // Now that both pre/post hooks have been called, the // servlet is ready to serve. // 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; } } private void log( Context ctx, String s ) { if( ctx==null ) log( s ); else ctx.log( s ); } private void log( Context ctx, String s, Throwable t ) { if( ctx==null ) log( s, t ); else ctx.log( s, t ); } // -------------------- -------------------- public void reload() { if( getState()==STATE_READY ) { try { destroy(); } catch(Exception ex ) { log(context, "Error in destroy ", ex ); } } if( sw.getServletClassName() != null ) { // I can survive reload servlet=null; servletClass=null; } setState( STATE_ADDED ); } // -------------------- public Servlet getServlet() throws ClassNotFoundException, InstantiationException, IllegalAccessException { if(servlet!=null) return servlet; if( debug>0) log(context, "LoadServlet " + name + " " + sw.getServletName() + " " + sw.getServletClassName() + " " + servletClass ); // default if( servletClassName==null ) servletClassName=name; if (servletClass == null) { servletClass=context.getClassLoader().loadClass(servletClassName); } servlet = (Servlet)servletClass.newInstance(); if (useStmPool && ( servlet instanceof SingleThreadModel )) { if(stmPool == null){ stmPool = new SimplePool(stmPoolSize); } stmPool.put(servlet); stmInstances++; } return servlet; } // -------------------- Destroy -------------------- protected void doDestroy() throws TomcatException { synchronized (this) { try { if( servlet!=null) { BaseInterceptor cI[]=context. getContainer().getInterceptors(); for( int i=0; i< cI.length; i++ ) { try { cI[i].preServletDestroy( context, this ); } catch( TomcatException ex) { log(context, "preServletDestroy", ex); } } if(useStmPool && (servlet instanceof SingleThreadModel)){ Servlet sl=null; while((sl = (Servlet)stmPool.get()) != null){ sl.destroy(); } stmInstances=0; } else { servlet.destroy(); } for( int i=0; i< cI.length; i++ ) { try { cI[i].postServletDestroy( context, this ); } catch( TomcatException ex) { log(context, "postServletDestroy", ex); } } } } catch(Exception ex) { // Should never come here... log(context, "Error in destroy ", ex ); } } } // Special hook protected void preInit() throws Exception { if( debug > 0 ) log(context, "preInit " + servlet + " " + sw.getJspFile() + " " + servletClassName); // Deal with Unavailable errors if( ! checkAvailable() ) { // remain in STATE_DELAYED_INIT state return; } // clear STATE_DELAYED_INIT if set setState( STATE_ADDED ); // For JSPs we rely on JspInterceptor to set the servlet class name. // We make no distinction between servlets and jsps. getServlet(); } protected void doInit() throws Exception { try { servlet.init( getServletInfo().getServletConfig() ); } catch( UnavailableException ex ) { // Implement the "UnavailableException" specification // servlet exception state setErrorException( ex ); if ( ex.isPermanent() ) { setState( STATE_DISABLED ); } else { setState( STATE_DELAYED_INIT ); setServletUnavailable( ex ); } servlet=null; // we have set the exception and state, okay to just return } // other exceptions are just thrown - // init() will deal with them. } // Overrides the default handler public void service ( Request req, Response res ) throws Exception { BaseInterceptor ri[]; ri=context.getContainer(). getInterceptors(Container.H_preInitCheck); for( int i=0; i< ri.length; i++ ) { int status = ri[i].preInitCheck(req, this); if(status != 0) { if(status >= 300){ contextM.handleStatus(req, res, status); } return; } } if( state!=STATE_READY ) { if( state!= STATE_DISABLED ) { init(); } if( state== STATE_DISABLED || state==STATE_DELAYED_INIT ) { // the init failed because of an exception Exception ex=getErrorException(); // save error info res.setErrorException(ex); res.setErrorURI(null); handleInitError( req, res, ex ); return; } } ri=context.getContainer(). getInterceptors(Container.H_postInitCheck); for( int i=0; i< ri.length; i++ ) { int status = ri[i].postInitCheck(req, this); if(status != 0) { contextM.handleStatus(req, res, status); return; } } super.service( req, res ); } protected void doSTMService(HttpServletRequest reqF, HttpServletResponse resF) throws Exception { Servlet sl = null; try { boolean newInstance = false; if ((sl = (Servlet)stmPool.get()) == null) { synchronized (this) { if (stmInstances < stmPoolSize) { stmInstances++; newInstance = true; } } if (newInstance) { sl = (Servlet)servletClass.newInstance(); sl.init(getServletInfo().getServletConfig()); } else { /* The pool is full, just synchronize on the initial instance. Ideally, we would the pain across all pooled instances to avoid a bottleneck on a single instance. */ sl = servlet; } } /* Since this may be the initial instance, we still need to synchronize here */ synchronized(sl) { sl.service(reqF, resF); } } finally { if (sl != null) { stmPool.put(sl); } } } protected void doService(Request req, Response res) throws Exception { // |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.