|
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.