You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@locus.apache.org on 2000/04/26 20:57:38 UTC
cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/util FileUtil.java
costin 00/04/26 11:57:37
Modified: src/share/org/apache/tomcat/context DefaultCMSetter.java
WebXmlReader.java
src/share/org/apache/tomcat/core ContextManager.java
ServletWriterFacade.java package.html
src/share/org/apache/tomcat/request SimpleMapper1.java
src/share/org/apache/tomcat/startup Tomcat.java
src/share/org/apache/tomcat/util FileUtil.java
Log:
- Renamed TomcatHome to InstallDir in ContextManager ( it generates
a lot of confusion ). Old methods still exist, but will be removed if
nobody is using them.
- moved deprecated methods at the end, preparing for removal.
- Added comments in ContextManager and more comments in package.html about
how it works.
Problem to be resolved:
Port/HostName do not belong here - tomcat can't guess what is the real
name and port for the default server ( unless it's working as a standalone
http server). The only use for those properties is in generating the
temp. work dir name. I think we should remove them ( the adapter will provide
the real values for request ).
Revision Changes Path
1.30 +2 -2 jakarta-tomcat/src/share/org/apache/tomcat/context/DefaultCMSetter.java
Index: DefaultCMSetter.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/context/DefaultCMSetter.java,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -r1.29 -r1.30
--- DefaultCMSetter.java 2000/04/25 17:54:10 1.29
+++ DefaultCMSetter.java 2000/04/26 18:57:34 1.30
@@ -114,10 +114,10 @@
// ( getHome returns the "instance" of tomcat, it may have it's own log, work, webapps,
// getTomcatHome is where tomcat is installed )
// Note: home defaults to tomcat.home if none is set...
- File f=new File( cm.getTomcatHome() + "/conf/web.xml");
+ File f=new File( cm.getInstallDir() + "/conf/web.xml");
if( ! f.exists() ) {
throw new TomcatException( "Wrong tomcat home " +
- cm.getTomcatHome());
+ cm.getInstallDir());
}
// update the workdir
String workDir=cm.getWorkDir();
1.18 +1 -1 jakarta-tomcat/src/share/org/apache/tomcat/context/WebXmlReader.java
Index: WebXmlReader.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/context/WebXmlReader.java,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- WebXmlReader.java 2000/03/28 00:04:02 1.17
+++ WebXmlReader.java 2000/04/26 18:57:34 1.18
@@ -36,7 +36,7 @@
// try the default ( installation )
if( ! default_xml.exists() ) {
- String tchome=ctx.getContextManager().getTomcatHome();
+ String tchome=ctx.getContextManager().getInstallDir();
if( tchome != null )
default_xml=new File( tchome + "/conf/web.xml");
}
1.75 +525 -393 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.74
retrieving revision 1.75
diff -u -r1.74 -r1.75
--- ContextManager.java 2000/04/25 17:54:13 1.74
+++ ContextManager.java 2000/04/26 18:57:35 1.75
@@ -72,83 +72,194 @@
import java.net.*;
import java.util.*;
+/* XXX The main function of CM is to serve as an entry point into
+ tomcat and manage a list of resources that are part of the servlet
+ processing. ( manage == keep a list and provide centralized access ).
+
+ It also have helper functions for common callbacks - but we need to
+ review and change that.
+*/
+/*
+ * It is possible to extend and override some of the methods ( this is not
+ * "final" ), but this is an extreme case and shouldn't be used - if you want
+ * to extend the server you should use interceptors.
+ * Another extreme case is having more than one ContextManager instances.
+ * Each will corespond to a separate servlet engine/container that will work
+ * independent of each other in the same VM ( each having possible multiple
+ * virtual hosts, etc). Both uses are not forbiden, but shouldn't be used
+ * unless there is real need for that - and if that happen we should
+ * add interfaces to express the use cases.
+ */
+
/**
- * A collection class representing the Contexts associated with a particular
- * Server. The managed Contexts can be accessed by path.
+ * 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 is a helper that will direct the request processing flow
+ * from its arrival from the server/protocl adapter ( in service() ).
+ * It is also responsible for controlling the request processing steps, from
+ * request parsing and mapping, auth, autorization, pre/post service, actual
+ * invocation and logging.
+ *
+ * It will also store properties that are global to the servlet container -
+ * like root directory, install dir, work dir.
*
- * It also store global default properties - the server name and port ( returned by
- * getServerName(), etc) and workdir.
*
* @author James Duncan Davidson [duncan@eng.sun.com]
* @author James Todd [gonzo@eng.sun.com]
* @author Harish Prabandham
+ * @author costin@eng.sun.com
*/
-public class ContextManager {
+public class ContextManager {
+
/**
* The string constants for this ContextManager.
*/
private StringManager sm = StringManager.getManager("org.apache.tomcat.core");
+ /** Global interceptors - all requests that will be served by this
+ engine will pass those filters
+ */
private Vector requestInterceptors = new Vector();
private Vector contextInterceptors = new Vector();
- // cache - faster access
+ // cache - faster access to interceptors, using [] instead of Vector
ContextInterceptor cInterceptors[];
RequestInterceptor rInterceptors[];
- /**
- * The set of Contexts associated with this ContextManager,
- * keyed by context paths.
- * @deprecated - the server shouldn't make any assumptions about
- * the key.
+ /** Adapters for the incoming protocol
*/
- private Hashtable contexts = new Hashtable();
+ Vector connectors=new Vector();
+
/** Contexts managed by this server
*/
private Vector contextsV=new Vector();
- public static final String DEFAULT_HOSTNAME="localhost";
- public static final int DEFAULT_PORT=8080;
- public static final String DEFAULT_WORK_DIR="work";
-
- /**
- * The virtual host name for the Server this ContextManager
- * is associated with.
- */
- String hostname;
+ int debug=0;
- /**
- * The port number being listed to by the Server this ContextManager
- * is associated with.
+ // Global properties for this tomcat instance:
+
+ /** Private workspace for this server
*/
- int port;
-
- int debug=0;
String workDir;
- // Instalation directory
+ /** The base directory where this instance runs.
+ * It can be different from the install directory to
+ * allow one install per system and multiple users
+ */
String home;
- String tomcatHome;
- Vector connectors=new Vector();
+ /** The directory where tomcat is installed
+ */
+ String installDir;
+ /** Default work dir, relative to home
+ */
+ public static final String DEFAULT_WORK_DIR="work";
/**
* Construct a new ContextManager instance with default values.
*/
public ContextManager() {
}
+
+
+ // -------------------- Setable properties: tomcat directories --------------------
+
+ /**
+ * The home of the tomcat instance - you can have multiple
+ * users running tomcat, with a shared install directory.
+ * Every instance will have its own logs, webapps directory
+ * and local config, all relative to this directory.
+ */
+ public void setHome(String home) {
+ this.home=FileUtil.getCanonicalPath( home );
+ log( "Setting home to " + this.home );
+ }
+
+ /**
+ * The home of the tomcat instance - you can have multiple
+ * users running tomcat, with a shared install directory.
+ * Every instance will have its own logs, webapps directory
+ * and local config, all relative to this directory.
+ *
+ * If no home is configured we'll try the install dir
+ * XXX clean up the order and process of guessing - maybe we can
+ * just throw error instead of guessing wrong.
+ */
+ public String getHome() {
+ if(home!=null) return home;
+
+ // If none defined, assume tomcat.home is used as base.
+ if( installDir != null )
+ home=FileUtil.getCanonicalPath( installDir );
+
+ if(home!=null) return home;
+
+ // try at least the system property
+ home=FileUtil.getCanonicalPath( System.getProperty("tomcat.home") );
+ if(home!=null) return home;
+
+ home=FileUtil.getCanonicalPath( "." ); // try current dir - we should throw an exception
+ return home;
+ }
+
+ /** Get installation directory, where libraries and default files
+ * are located. If path specified is relative,
+ * evaluate it relative to the current working directory.
+ */
+ public String getInstallDir() {
+ if(installDir!= null) return installDir;
+
+ installDir=System.getProperty("tomcat.home");
+ if(installDir!= null) return installDir;
+
+ // If the property is not set ( for example JNI worker ) assume
+ // at least home is set up corectly.
+ installDir=getHome();
+ return installDir;
+ }
+
+ /** Set installation directory, where libraries and default files
+ * are located. If path specified is relative,
+ * evaluate it relative to the current working directory.
+ */
+ public void setInstallDir( String tH ) {
+ installDir=tH;
+ }
+
+ /**
+ * WorkDir property - where all working files will be created
+ */
+ public void setWorkDir( String wd ) {
+ if(debug>0) log("set work dir " + wd);
+ this.workDir=wd;
+ }
+
+ /**
+ * WorkDir property - where all working files will be created
+ */
+ public String getWorkDir() {
+ if( workDir==null)
+ workDir=getHome() + File.separator + DEFAULT_WORK_DIR;
+ return workDir;
+ }
- // -------------------- Context repository --------------------
+ // -------------------- Support functions --------------------
- /** Set default settings ( interceptors, connectors, loader, manager )
+ /**
+ * Set default settings ( interceptors, connectors, loader, manager )
* It is called from init if no connector is set up - note that we
* try to avoid any "magic" - you either set up everything ( using
* server.xml or alternatives) or you don't set up and then defaults
* will be used.
*
* Set interceptors or call setDefaults before adding contexts.
+ *
+ * This is mostly used to allow "0 config" case ( you just want the
+ * reasonable defaults and nothing else ).
*/
public void setDefaults() {
if(connectors.size()==0) {
@@ -177,40 +288,30 @@
}
}
-
- /**
- * Get the names of all the contexts in this server.
- * @deprecated Path is not "unique key".
- */
- public Enumeration getContextNames() {
- return contexts.keys();
- }
-
- /** Return the list of contexts managed by this server
- */
- public Enumeration getContexts() {
- return contextsV.elements();
- }
-
/** Init() is called after the context manager is set up
- * and configured.
+ * and configured. It will init all internal components
+ * to be ready for start.
+ *
+ * There is a difference between Context and Adapters - the
+ * adapter has start/stop, the Context has init/shutdown(destroy
+ * may be a better name ? ). ( Initializing is different from starting.)
*/
public void init() throws TomcatException {
- String cp=System.getProperty( "java.class.path");
- log( "Tomcat install = " + getTomcatHome());
+ log( "Tomcat install = " + getInstallDir());
log( "Tomcat home = " + home);
- if(debug>0 ) log( "Tomcat classpath = " + cp );
- // long time=System.currentTimeMillis();
+ if(debug>0 ) log( "Tomcat classpath = " + System.getProperty( "java.class.path" ));
+
+ setAccount( ACC_INIT_START, System.currentTimeMillis());
+
ContextInterceptor cI[]=getContextInterceptors();
for( int i=0; i< cI.length; i++ ) {
cI[i].engineInit( this );
}
-
+
// init contexts
Enumeration enum = getContexts();
- Context context=null;
while (enum.hasMoreElements()) {
- context = (Context)enum.nextElement();
+ Context context = (Context)enum.nextElement();
try {
initContext( context );
} catch (TomcatException ex ) {
@@ -222,18 +323,32 @@
}
}
}
- // log("Time to initialize: "+ (System.currentTimeMillis()-time), Logger.INFORMATION);
+ setAccount( ACC_INIT_END, System.currentTimeMillis() );
}
+ /** Will shutdown all contexts
+ */
+ public void shutdown() throws TomcatException {
+ Enumeration enum = getContexts();
+ while (enum.hasMoreElements()) {
+ removeContext((Context)enum.nextElement());
+ }
+
+ ContextInterceptor cI[]=getContextInterceptors();
+ for( int i=0; i< cI.length; i++ ) {
+ cI[i].engineShutdown( this );
+ }
+ }
/**
- * Initializes this context to take on requests. This action
+ * 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 may only be called once and must be called
- * before any requests are handled by this context and after setContextManager()
- * is called.
+ * <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 added a new context.
*/
public void initContext( Context ctx ) throws TomcatException {
ContextInterceptor cI[]=getContextInterceptors();
@@ -241,11 +356,16 @@
cI[i].contextInit( ctx );
}
}
-
+
+ /** Stop the context and release all resources.
+ */
public void shutdownContext( Context ctx ) throws TomcatException {
- // shut down and servlet
+ // XXX This is here by accident, it should be moved as part
+ // of a normal context interceptor that will handle all standard
+ // start/stop actions
+
+ // shut down and servlets
Enumeration enum = ctx.getServletNames();
-
while (enum.hasMoreElements()) {
String key = (String)enum.nextElement();
ServletWrapper wrapper = ctx.getServletByName( key );
@@ -259,42 +379,32 @@
}
}
- /** Will start the connectors and begin serving requests
+ /** Will start the connectors and begin serving requests.
+ * It must be called after init.
*/
- public void start() throws Exception {//TomcatException {
+ public void start() throws Exception {// XXX TomcatException {
Enumeration connE=getConnectors();
while( connE.hasMoreElements() ) {
((ServerConnector)connE.nextElement()).start();
}
}
- public void stop() throws Exception {//TomcatException {
+ /** Will stop all connectors
+ */
+ public void stop() throws Exception {// XXX TomcatException {
if(debug>0) log("Stopping context manager ");
Enumeration connE=getConnectors();
while( connE.hasMoreElements() ) {
((ServerConnector)connE.nextElement()).stop();
- }
-
- ContextInterceptor cI[]=getContextInterceptors();
- Enumeration enum = getContextNames();
- while (enum.hasMoreElements()) {
- removeContext((String)enum.nextElement());
}
+ shutdown();
}
- /**
- * Gets a context by it's name, or <code>null</code> if there is
- * no such context.
- *
- * @param name Name of the requested context
- * @deprecated Use an external iterator to find the context that
- * matches your conditions.
- *
+ // -------------------- Contexts --------------------
+ /** Return the list of contexts managed by this server
*/
- public Context getContext(String name) {
- // System.out.println("Using deprecated getContext");
- // /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
- return (Context)contexts.get(name);
+ public Enumeration getContexts() {
+ return contextsV.elements();
}
/**
@@ -327,27 +437,6 @@
contextsV.addElement( ctx );
}
- /**
- * Shut down and removes a context from service.
- *
- * @param name Name of the Context to be removed
- * @deprecated Use removeContext( Context ).
- */
- public void removeContext(String name) throws TomcatException {
- Context context = (Context)contexts.get(name);
- log( "Removing context " + context.toString());
-
- ContextInterceptor cI[]=getContextInterceptors();
- for( int i=0; i< cI.length; i++ ) {
- cI[i].removeContext( this, context );
- }
-
- if(context != null) {
- shutdownContext( context );
- contexts.remove(name);
- }
- }
-
/** Shut down and removes a context from service
*/
public void removeContext( Context context ) throws TomcatException {
@@ -363,7 +452,9 @@
shutdownContext( context );
contextsV.removeElement(context);
}
-
+
+ /** Notify interceptors that a new container was added.
+ */
public void addContainer( Container container )
throws TomcatException
{
@@ -373,6 +464,8 @@
}
}
+ /** Notify interceptors that a container was removed.
+ */
public void removeContainer( Container container )
throws TomcatException
{
@@ -449,236 +542,210 @@
}
return cInterceptors;
}
+ // -------------------- Request processing / subRequest --------------------
+ // -------------------- Main request processing methods --------------------
- public void addLogger(Logger logger) {
- // Will use this later once I feel more sure what I want to do here.
- // -akv
- // firstLog=false;
- // if("tc_log".equals( logger.getName()) cmLog=logger;
+ /** Prepare the req/resp pair for use in tomcat.
+ * Call it after you create the request/response objects
+ */
+ public void initRequest( Request req, Response resp ) {
+ // used to be done in service(), but there is no need to do it
+ // every time.
+ // We may add other special calls here.
+ // XXX Maybe make it a callback?
+ resp.setRequest( req );
+ req.setResponse( resp );
+ req.setContextManager( this );
}
+
+ /** This is the entry point in tomcat - the connectors ( or any other
+ * component able to generate Request/Response implementations ) will
+ * call this method to get it processed.
+ * XXX make sure the alghoritm is right, deal with response codes
+ */
+ public void service( Request rrequest, Response rresponse ) {
+ try {
+ /* assert rrequest/rresponse are set up
+ corectly - have cm, and one-one relation
+ */
+ // wront request - parsing error
+ int status=rresponse.getStatus();
+ if( status < 400 )
+ status= processRequest( rrequest );
+
+ if(status==0)
+ status=authenticate( rrequest, rresponse );
+ if(status == 0)
+ status=authorize( rrequest, rresponse );
+ if( status == 0 ) {
+ rrequest.getWrapper().handleRequest(rrequest, rresponse);
+ } else {
+ // something went wrong
+ handleError( rrequest, rresponse, null, status );
+ }
+ } catch (Throwable t) {
+ handleError( rrequest, rresponse, t, 0 );
+ }
+ try {
+ rresponse.finish();
+ rrequest.recycle();
+ rresponse.recycle();
+ } catch( Throwable ex ) {
+ if(debug>0) log( "Error closing request " + ex);
+ }
+ return;
+ }
- // -------------------- Defaults for all contexts --------------------
- /** The root directory of tomcat
+ /** Will find the ServletWrapper for a servlet, assuming we already have
+ * the Context. This is also used by Dispatcher and getResource - where the Context
+ * is already known.
*/
- public String getHome() {
- if(home!=null) return home;
+ public int processRequest( Request req ) {
+ if(debug>9) log("ProcessRequest: "+req.toString());
- // If none defined, assume tomcat.home is used as base.
- home=getCanonicalPath( tomcatHome );
- if(home!=null) return home;
+ for( int i=0; i< requestInterceptors.size(); i++ ) {
+ ((RequestInterceptor)requestInterceptors.elementAt(i)).contextMap( req );
+ }
- // try at least the system property
- home=getCanonicalPath( System.getProperty("tomcat.home") );
- if(home!=null) return home;
+ for( int i=0; i< requestInterceptors.size(); i++ ) {
+ ((RequestInterceptor)requestInterceptors.elementAt(i)).requestMap( req );
+ }
+
+ if(debug>9) log("After processing: "+req.toString());
- home=getCanonicalPath( "." ); // try current dir - we should throw an exception
- return home;
+ return 0;
}
-
- /** Tomcat installation directory, where libraries and default files are located
+
+ /** Call all authentication callbacks. If any of them is able to identify the user
+ * it will set the principal in req.
*/
- public String getTomcatHome() {
- if(tomcatHome!= null) return tomcatHome;
-
- tomcatHome=System.getProperty("tomcat.home");
- if(tomcatHome!= null) return tomcatHome;
+ public int authenticate( Request req, Response res ) {
+ for( int i=0; i< requestInterceptors.size(); i++ ) {
+ ((RequestInterceptor)requestInterceptors.elementAt(i)).authenticate( req, res );
+ }
+ return 0;
+ }
- // If the property is not set ( for example JNI worker ) assume
- // at least home is set up corectly.
- tomcatHome=getHome();
- return tomcatHome;
+ /** Call all authorization callbacks. The "require valid user" attributes are probably
+ * set during the mapping stage ( for efficiency), but it can be done here too.
+ */
+ int authorize( Request req, Response res ) {
+ for( int i=0; i< requestInterceptors.size(); i++ ) {
+ int err = ((RequestInterceptor)requestInterceptors.elementAt(i)).authorize( req, res );
+ if ( err != 0 ) return err;
+ }
+ return 0;
}
- public void setTomcatHome( String tH ) {
- tomcatHome=tH;
+ /** Call beforeBody callbacks. Before body allows you do do various actions before
+ the first byte of the response is sent. After all those callbacks are called
+ tomcat may send the status and headers
+ */
+ int doBeforeBody( Request req, Response res ) {
+ for( int i=0; i< requestInterceptors.size(); i++ ) {
+ ((RequestInterceptor)requestInterceptors.elementAt(i)).beforeBody( req, res );
+ }
+ return 0;
}
- // Used in few places.
- static String getCanonicalPath(String name ) {
- if( name==null ) return null;
- File f = new File(name);
- try {
- return f.getCanonicalPath();
- } catch (IOException ioe) {
- ioe.printStackTrace();
- return name; // oh well, we tried...
- }
+ /** Call beforeCommit callbacks. This allows interceptors to manipulate the
+ buffer before it gets sent.
+ XXX Add a standard way to access the body. The method was not used too
+ much, we need a review and maybe change in parameters.
+ */
+ int doBeforeCommit( Request req, Response res ) {
+ for( int i=0; i< requestInterceptors.size(); i++ ) {
+ ((RequestInterceptor)requestInterceptors.elementAt(i)).beforeCommit( req, res );
+ }
+ return 0;
}
-
- /**
- * Set installation directory. If path specified is relative,
- * evaluate it relative to the current working directory.
- *
- * This is used for the home attribute and it's used to find webapps
- * and conf. Note that libs are probably already configured, so it will
- * not affect that.
- */
- public void setHome(String home) {
- this.home=getCanonicalPath( home );
- log( "Setting home to " + this.home );
- }
-
- /**
- * Sets the port number on which this server listens.
- *
- * @param port The new port number
- * @deprecated
- */
- public void setPort(int port) {
- this.port=port;
- }
-
- /**
- * Gets the port number on which this server listens.
- * @deprecated
- */
- public int getPort() {
- if(port==0) port=DEFAULT_PORT;
- return port;
- }
- /**
- * Sets the virtual host name of this server.
- *
- * @param host The new virtual host name
- * @deprecated
- */
- public void setHostName( String host) {
- this.hostname=host;
- }
-
- /**
- * Gets the virtual host name of this server.
- * @deprecated
- */
- public String getHostName() {
- if(hostname==null)
- hostname=DEFAULT_HOSTNAME;
- return hostname;
- }
-
- /**
- * WorkDir property - where all temporary files will be created
- */
- public void setWorkDir( String wd ) {
- if(debug>0) log("set work dir " + wd);
- this.workDir=wd;
- }
-
- public String getWorkDir() {
- if( workDir==null)
- workDir=DEFAULT_WORK_DIR;
- return workDir;
- }
-
- // -------------------- Request processing / subRequest --------------------
-
- /** Common for all connectors, needs to be shared in order to avoid
- code duplication
+ /** Call afterBody callbacks. It is called after the servlet finished sending the
+ response ( either closeing the stream or ending ). You can deal with connection
+ reuse or do other actions
*/
- public void service( Request rrequest, Response rresponse ) {
- try {
- /* assert rrequest/rresponse are set up
- corectly - have cm, and one-one relation
- */
-
- // wront request - parsing error
- int status=rresponse.getStatus();
-
- if( status < 400 )
- status= processRequest( rrequest );
-
- if(status==0)
- status=authenticate( rrequest, rresponse );
- if(status == 0)
- status=authorize( rrequest, rresponse );
- if( status == 0 ) {
- rrequest.getWrapper().handleRequest(rrequest, rresponse);
- } else {
- // something went wrong
- handleError( rrequest, rresponse, null, status );
- }
- } catch (Throwable t) {
- handleError( rrequest, rresponse, t, 0 );
- }
- try {
- rresponse.finish();
- rrequest.recycle();
- rresponse.recycle();
- } catch( Throwable ex ) {
- if(debug>0) log( "Error closing request " + ex);
+ int doAfterBody( Request req, Response res ) {
+ for( int i=0; i< requestInterceptors.size(); i++ ) {
+ ((RequestInterceptor)requestInterceptors.elementAt(i)).afterBody( req, res );
}
- // log( "Done with request " + rrequest );
- // System.out.print("C");
- return;
+ return 0;
}
+
+ // -------------------- Sub-Request mechanism --------------------
- /** Will find the ServletWrapper for a servlet, assuming we already have
- * the Context. This is used by Dispatcher and getResource - where the Context
- * is already known.
+ /** Create a new sub-request in a given context, set the context "hint"
+ * This is a particular case of sub-request that can't get out of
+ * a context ( and we know the context before - so no need to compute it again)
+ *
+ * Note that session and all stuff will still be computed.
*/
- public int processRequest( Request req ) {
- if(debug>9) log("ProcessRequest: "+req.toString());
+ public Request createRequest( Context ctx, String urlPath ) {
+ // assert urlPath!=null
- for( int i=0; i< requestInterceptors.size(); i++ ) {
- ((RequestInterceptor)requestInterceptors.elementAt(i)).contextMap( req );
- }
+ // deal with paths with parameters in it
+ String contextPath=ctx.getPath();
+ String origPath=urlPath;
- for( int i=0; i< requestInterceptors.size(); i++ ) {
- ((RequestInterceptor)requestInterceptors.elementAt(i)).requestMap( req );
+ // append context path
+ if( !"".equals(contextPath) && !"/".equals(contextPath)) {
+ if( urlPath.startsWith("/" ) )
+ urlPath=contextPath + urlPath;
+ else
+ urlPath=contextPath + "/" + urlPath;
+ } else {
+ // root context
+ if( !urlPath.startsWith("/" ) )
+ urlPath= "/" + urlPath;
}
-
- if(debug>9) log("After processing: "+req.toString());
-
-
- return 0;
- }
- int authenticate( Request req, Response res ) {
- for( int i=0; i< requestInterceptors.size(); i++ ) {
- ((RequestInterceptor)requestInterceptors.elementAt(i)).authenticate( req, res );
- }
- return 0;
+ if( debug >4 ) log("createRequest " + origPath + " " + urlPath );
+ Request req= createRequest( urlPath );
+ String host=ctx.getHost();
+ if( host != null) req.setServerName( host );
+ return req;
}
- int authorize( Request req, Response res ) {
- for( int i=0; i< requestInterceptors.size(); i++ ) {
- int err = ((RequestInterceptor)requestInterceptors.elementAt(i)).authorize( req, res );
- if ( err != 0 ) return err;
+ /** Create a new sub-request, deal with query string
+ */
+ public Request createRequest( String urlPath ) {
+ String queryString=null;
+ int i = urlPath.indexOf("?");
+ int len=urlPath.length();
+ if (i>-1) {
+ if(i<len)
+ queryString =urlPath.substring(i + 1, urlPath.length());
+ urlPath = urlPath.substring(0, i);
}
- return 0;
- }
-
+ ///*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
- int doBeforeBody( Request req, Response res ) {
- for( int i=0; i< requestInterceptors.size(); i++ ) {
- ((RequestInterceptor)requestInterceptors.elementAt(i)).beforeBody( req, res );
- }
- return 0;
- }
+ /** Creates an "internal" request
+ */
+ RequestImpl lr = new RequestImpl();
+ // RequestAdapterImpl reqA=new RequestAdapterImpl();
+ //lr.setRequestAdapter( reqA);
+ lr.setRequestURI( urlPath );
+ lr.setQueryString( queryString );
+ // lr.processQueryString();
- int doBeforeCommit( Request req, Response res ) {
- for( int i=0; i< requestInterceptors.size(); i++ ) {
- ((RequestInterceptor)requestInterceptors.elementAt(i)).beforeCommit( req, res );
- }
- return 0;
+ // lr.setContext( ctx );
+
+ // XXX set query string too
+ return lr;
}
- int doAfterBody( Request req, Response res ) {
- for( int i=0; i< requestInterceptors.size(); i++ ) {
- ((RequestInterceptor)requestInterceptors.elementAt(i)).afterBody( req, res );
- }
- return 0;
- }
+ // -------------------- Error handling --------------------
+ /** General error handling mechanism. It will try to find an error handler
+ * or use the default handler.
+ * XXX very complex - need a rewrite.
+ */
void handleError( Request req, Response res , Throwable t, int code ) {
Context ctx = req.getContext();
if(ctx==null) {
ctx=getContext("");
}
if(ctx.getDebug() > 4 ) ctx.log("In error handler " + code + " " + t + " / " + req );
- // /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
String path=null;
ServletWrapper errorServlet=null;
@@ -687,7 +754,6 @@
errorServlet=ctx.getServletByName("tomcat.errorPage");
} else if( req.getAttribute("javax.servlet.error.status_code") != null ||
req.getAttribute("javax.servlet.error.exception_type")!=null) {
- // /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
if( ctx.getDebug() > 0 ) ctx.log( "Error: exception inside exception servlet " +
req.getAttribute("javax.servlet.error.status_code") + " " +
req.getAttribute("javax.servlet.error.exception_type"));
@@ -774,98 +840,9 @@
}
return;
- }
-
- // -------------------- Sub-Request mechanism --------------------
-
- /** Create a new sub-request in a given context, set the context "hint"
- * This is a particular case of sub-request that can't get out of
- * a context ( and we know the context before - so no need to compute it again)
- *
- * Note that session and all stuff will still be computed.
- */
- Request createRequest( Context ctx, String urlPath ) {
- // assert urlPath!=null
-
- // deal with paths with parameters in it
- String contextPath=ctx.getPath();
- String origPath=urlPath;
-
- // append context path
- if( !"".equals(contextPath) && !"/".equals(contextPath)) {
- if( urlPath.startsWith("/" ) )
- urlPath=contextPath + urlPath;
- else
- urlPath=contextPath + "/" + urlPath;
- } else {
- // root context
- if( !urlPath.startsWith("/" ) )
- urlPath= "/" + urlPath;
- }
-
- if( debug >4 ) log("createRequest " + origPath + " " + urlPath );
- Request req= createRequest( urlPath );
- String host=ctx.getHost();
- if( host != null) req.setServerName( host );
- return req;
}
-
- /** Create a new sub-request, deal with query string
- */
- public Request createRequest( String urlPath ) {
- String queryString=null;
- int i = urlPath.indexOf("?");
- int len=urlPath.length();
- if (i>-1) {
- if(i<len)
- queryString =urlPath.substring(i + 1, urlPath.length());
- urlPath = urlPath.substring(0, i);
- }
- ///*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
-
- /** Creates an "internal" request
- */
- RequestImpl lr = new RequestImpl();
- // RequestAdapterImpl reqA=new RequestAdapterImpl();
- //lr.setRequestAdapter( reqA);
- lr.setRequestURI( urlPath );
- lr.setQueryString( queryString );
- // lr.processQueryString();
-
- // lr.setContext( ctx );
-
- // XXX set query string too
- return lr;
- }
-
- /** Prepare the req/resp pair for use in tomcat.
- Call it after you create the request/response objects
- */
- public void initRequest( Request req, Response resp ) {
- // used to be done in service(), but there is no need to do it
- // every time.
- // We may add other special calls here.
- // XXX Maybe make it a callback?
- resp.setRequest( req );
- req.setResponse( resp );
- req.setContextManager( this );
- }
-
- // -------------------- Support for notes
+ // -------------------- Support for notes --------------------
- // used to allow interceptors to set specific per/request, per/container
- // and per/CM informations.
-
- // This will allow us to remove all "specialized" methods in
- // Request and Container/Context, without losing the functionality.
-
- // Remember - Interceptors are not supposed to have internal state
- // and minimal configuration, all setup is part of the "core", under
- // central control.
-
- // We use indexed notes instead of attributes for performance -
- // this is internal to tomcat and most of the time in critical path
-
/** Note id counters. Synchronized access is not necesarily needed
* ( the initialization is in one thread ), but anyway we do it
*/
@@ -881,6 +858,18 @@
String noteDescription[][]=new String[3][MAX_NOTES];
+ /** used to allow interceptors to set specific per/request, per/container
+ * and per/CM informations.
+ *
+ * This will allow us to remove all "specialized" methods in
+ * Request and Container/Context, without losing the functionality.
+ * Remember - Interceptors are not supposed to have internal state
+ * and minimal configuration, all setup is part of the "core", under
+ * central control.
+ * We use indexed notes instead of attributes for performance -
+ * this is internal to tomcat and most of the time in critical path
+ */
+
/** Create a new note id. Interceptors will get an Id at init time for
* all notes that it needs.
*
@@ -899,7 +888,7 @@
return noteDescription[noteType][noteId];
}
- // -------------------- Per-server notes
+ // -------------------- Per-server notes --------------------
Object notes[]=new Object[MAX_NOTES];
public void setNote( int pos, Object value ) {
@@ -913,9 +902,16 @@
// -------------------- Logging and debug --------------------
boolean firstLog = true;
Logger cmLog = null;
-
-
+
+ public void addLogger(Logger logger) {
+ // Will use this later once I feel more sure what I want to do here.
+ // -akv
+ // firstLog=false;
+ // if("tc_log".equals( logger.getName()) cmLog=logger;
+ }
+
+
public void setDebug( int level ) {
if( level != 0 ) System.out.println( "Setting level to " + level);
debug=level;
@@ -926,10 +922,7 @@
}
public final void log(String msg) {
- // if( msg.startsWith( "<l:" ))
doLog( msg );
- //else
- //doLog("<l:tc>" + msg + "</l:tc>");
}
public final void doLog(String msg) {
@@ -956,6 +949,145 @@
}
}
+ // -------------------- Accounting --------------------
+ // XXX Can be implemented as note !
+
+ public static final int ACC_INIT_START=0;
+ public static final int ACC_INIT_END=0;
+
+ public static final int ACCOUNTS=7;
+ long accTable[]=new long[ACCOUNTS];
+
+ public void setAccount( int pos, long value ) {
+ accTable[pos]=value;
+ }
+
+ public long getAccount( int pos ) {
+ return accTable[pos];
+ }
+
+ // -------------------- DEPRECATED --------------------
+ // XXX host and port are used only to construct a unique
+ // work-dir for contexts, using them and the path
+ // Since nobody sets them - I guess we can just drop them
+ // anyway.
+ // XXX ask and find if there is any other use!
+ public static final String DEFAULT_HOSTNAME="localhost";
+ public static final int DEFAULT_PORT=8080;
+ String hostname;
+ int port;
+
+ /**
+ * Sets the port number on which this server listens.
+ *
+ * @param port The new port number
+ * @deprecated
+ */
+ public void setPort(int port) {
+ /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+ this.port=port;
+ }
+
+ /**
+ * Gets the port number on which this server listens.
+ * @deprecated
+ */
+ public int getPort() {
+ // /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+ if(port==0) port=DEFAULT_PORT;
+ return port;
+ }
+
+ /**
+ * Sets the virtual host name of this server.
+ *
+ * @param host The new virtual host name
+ * @deprecated
+ */
+ public void setHostName( String host) {
+ /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+ this.hostname=host;
+ }
+
+ /**
+ * Gets the virtual host name of this server.
+ * @deprecated
+ */
+ public String getHostName() {
+ // /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+ if(hostname==null)
+ hostname=DEFAULT_HOSTNAME;
+ return hostname;
+ }
+ // -------------------- DEPRECATED --------------------
+
+ /**
+ * The set of Contexts associated with this ContextManager,
+ * keyed by context paths.
+ * @deprecated - the server shouldn't make any assumptions about
+ * the key.
+ */
+ private Hashtable contexts = new Hashtable();
+
+ /**
+ * Get the names of all the contexts in this server.
+ * @deprecated Path is not "unique key".
+ */
+ public Enumeration getContextNames() {
+ /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+ return contexts.keys();
+ }
+
+ /**
+ * Gets a context by it's name, or <code>null</code> if there is
+ * no such context.
+ *
+ * @param name Name of the requested context
+ * @deprecated Use an external iterator to find the context that
+ * matches your conditions.
+ *
+ */
+ public Context getContext(String name) {
+ // System.out.println("Using deprecated getContext");
+ // /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+ return (Context)contexts.get(name);
+ }
+
+ /**
+ * Shut down and removes a context from service.
+ *
+ * @param name Name of the Context to be removed
+ * @deprecated Use removeContext( Context ).
+ */
+ public void removeContext(String name) throws TomcatException {
+ /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+ Context context = (Context)contexts.get(name);
+ log( "Removing context " + context.toString());
+
+ ContextInterceptor cI[]=getContextInterceptors();
+ for( int i=0; i< cI.length; i++ ) {
+ cI[i].removeContext( this, context );
+ }
+
+ if(context != null) {
+ shutdownContext( context );
+ contexts.remove(name);
+ }
+ }
+
+ /** @deprecated
+ */
+ public void setTomcatHome( String s ) {
+ // /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+ setInstallDir( s );
+ }
+
+ /** @deprecated
+ */
+ public String getTomcatHome() {
+ ///*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+ return getInstallDir();
+ }
}
1.2 +306 -1 jakarta-tomcat/src/share/org/apache/tomcat/core/ServletWriterFacade.java
Index: ServletWriterFacade.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ServletWriterFacade.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ServletWriterFacade.java 2000/04/17 21:02:27 1.1
+++ ServletWriterFacade.java 2000/04/26 18:57:35 1.2
@@ -72,7 +72,7 @@
* that we spend too much time in that area ).
*
* This will also help us control the multi-buffering ( since all writers have
- * 8k or more of un-recyclable buffers). Recycling is good !
+ * 8k or more of un-recyclable buffers).
*
* @author Costin Manolache [costin@eng.sun.com]
*/
@@ -137,3 +137,308 @@
}
+// -------------------- From Crimson !
+
+//
+// Delegating to a converter module will always be slower than
+// direct conversion. Use a similar approach for any other
+// readers that need to be particularly fast; only block I/O
+// speed matters to this package. For UTF-16, separate readers
+// for big and little endian streams make a difference, too;
+// fewer conditionals in the critical path!
+//
+abstract class BaseReader extends Reader
+{
+ protected InputStream instream;
+ protected byte buffer [];
+ protected int start, finish;
+
+ BaseReader (InputStream stream)
+ {
+ super (stream);
+
+ instream = stream;
+ buffer = new byte [8192];
+ }
+
+ public boolean ready () throws IOException
+ {
+ return instream == null
+ || (finish - start) > 0
+ || instream.available () != 0;
+ }
+
+ // caller shouldn't read again
+ public void close () throws IOException
+ {
+ if (instream != null) {
+ instream.close ();
+ start = finish = 0;
+ buffer = null;
+ instream = null;
+ }
+ }
+}
+
+//
+// We want this reader, to make the default encoding be as fast
+// as we can make it. JDK's "UTF8" (not "UTF-8" till JDK 1.2)
+// InputStreamReader works, but 20+% slower speed isn't OK for
+// the default/primary encoding.
+//
+final class Utf8Reader extends BaseReader
+{
+ // 2nd half of UTF-8 surrogate pair
+ private char nextChar;
+
+ Utf8Reader (InputStream stream)
+ {
+ super (stream);
+ }
+
+ public int read (char buf [], int offset, int len) throws IOException
+ {
+ int i = 0, c = 0;
+
+ if (len <= 0)
+ return 0;
+
+ // avoid many runtime bounds checks ... a good optimizer
+ // (static or JIT) will now remove checks from the loop.
+ if ((offset + len) > buf.length || offset < 0)
+ throw new ArrayIndexOutOfBoundsException ();
+
+ // Consume remaining half of any surrogate pair immediately
+ if (nextChar != 0) {
+ buf [offset + i++] = nextChar;
+ nextChar = 0;
+ }
+
+ while (i < len) {
+ // stop or read data if needed
+ if (finish <= start) {
+ if (instream == null) {
+ c = -1;
+ break;
+ }
+ start = 0;
+ finish = instream.read (buffer, 0, buffer.length);
+ if (finish <= 0) {
+ this.close ();
+ c = -1;
+ break;
+ }
+ }
+
+ //
+ // RFC 2279 describes UTF-8; there are six encodings.
+ // Each encoding takes a fixed number of characters
+ // (1-6 bytes) and is flagged by a bit pattern in the
+ // first byte. The five and six byte-per-character
+ // encodings address characters which are disallowed
+ // in XML documents, as do some four byte ones.
+ //
+
+ //
+ // Single byte == ASCII. Common; optimize.
+ //
+ c = buffer [start] & 0x0ff;
+ if ((c & 0x80) == 0x00) {
+ // 0x0000 <= c <= 0x007f
+ start++;
+ buf [offset + i++] = (char) c;
+ continue;
+ }
+
+ //
+ // Multibyte chars -- check offsets optimistically,
+ // ditto the "10xx xxxx" format for subsequent bytes
+ //
+ int off = start;
+
+ try {
+ // 2 bytes
+ if ((buffer [off] & 0x0E0) == 0x0C0) {
+ c = (buffer [off++] & 0x1f) << 6;
+ c += buffer [off++] & 0x3f;
+
+ // 0x0080 <= c <= 0x07ff
+
+ // 3 bytes
+ } else if ((buffer [off] & 0x0F0) == 0x0E0) {
+ c = (buffer [off++] & 0x0f) << 12;
+ c += (buffer [off++] & 0x3f) << 6;
+ c += buffer [off++] & 0x3f;
+
+ // 0x0800 <= c <= 0xffff
+
+ // 4 bytes
+ } else if ((buffer [off] & 0x0f8) == 0x0F0) {
+ c = (buffer [off++] & 0x07) << 18;
+ c += (buffer [off++] & 0x3f) << 12;
+ c += (buffer [off++] & 0x3f) << 6;
+ c += buffer [off++] & 0x3f;
+
+ // 0x0001 0000 <= c <= 0x001f ffff
+
+ // Unicode supports c <= 0x0010 ffff ...
+ if (c > 0x0010ffff)
+ throw new CharConversionException (
+ "UTF-8 encoding of character 0x00"
+ + Integer.toHexString (c)
+ + " can't be converted to Unicode."
+ );
+
+ else if (c > 0xffff) {
+ // Convert UCS-4 char to surrogate pair (UTF-16)
+ c -= 0x10000;
+ nextChar = (char) (0xDC00 + (c & 0x03ff));
+ c = 0xD800 + (c >> 10);
+ }
+ // 5 and 6 byte versions are XML WF errors, but
+ // typically come from mislabeled encodings
+ } else
+ throw new CharConversionException (
+ "Unconvertible UTF-8 character"
+ + " beginning with 0x"
+ + Integer.toHexString (
+ buffer [start] & 0xff)
+ );
+
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // off > length && length >= buffer.length
+ c = 0;
+ }
+
+ //
+ // if the buffer held only a partial character,
+ // compact it and try to read the rest of the
+ // character. worst case involves three
+ // single-byte reads -- quite rare.
+ //
+ if (off > finish) {
+ System.arraycopy (buffer, start,
+ buffer, 0, finish - start);
+ finish -= start;
+ start = 0;
+ off = instream.read (buffer, finish,
+ buffer.length - finish);
+ if (off < 0) {
+ this.close ();
+ throw new CharConversionException (
+ "Partial UTF-8 char");
+ }
+ finish += off;
+ continue;
+ }
+
+ //
+ // check the format of the non-initial bytes
+ //
+ for (start++; start < off; start++) {
+ if ((buffer [start] & 0xC0) != 0x80) {
+ this.close ();
+ throw new CharConversionException (
+ "Malformed UTF-8 char -- "
+ + "is an XML encoding declaration missing?"
+ );
+ }
+ }
+
+ //
+ // If this needed a surrogate pair, consume ASAP
+ //
+ buf [offset + i++] = (char) c;
+ if (nextChar != 0 && i < len) {
+ buf [offset + i++] = nextChar;
+ nextChar = 0;
+ }
+ }
+ if (i > 0)
+ return i;
+ return (c == -1) ? -1 : 0;
+ }
+}
+
+//
+// We want ASCII and ISO-8859 Readers since they're the most common
+// encodings in the US and Europe, and we don't want performance
+// regressions for them. They're also easy to implement efficiently,
+// since they're bitmask subsets of UNICODE.
+//
+// XXX haven't benchmarked these readers vs what we get out of JDK.
+//
+final class AsciiReader extends BaseReader
+{
+ AsciiReader (InputStream in) { super (in); }
+
+ public int read (char buf [], int offset, int len) throws IOException
+ {
+ int i, c;
+
+ if (instream == null)
+ return -1;
+
+ // avoid many runtime bounds checks ... a good optimizer
+ // (static or JIT) will now remove checks from the loop.
+ if ((offset + len) > buf.length || offset < 0)
+ throw new ArrayIndexOutOfBoundsException ();
+
+ for (i = 0; i < len; i++) {
+ if (start >= finish) {
+ start = 0;
+ finish = instream.read (buffer, 0, buffer.length);
+ if (finish <= 0) {
+ if (finish <= 0)
+ this.close ();
+ break;
+ }
+ }
+ c = buffer [start++];
+ if ((c & 0x80) != 0)
+ throw new CharConversionException (
+ "Illegal ASCII character, 0x"
+ + Integer.toHexString (c & 0xff)
+ );
+ buf [offset + i] = (char) c;
+ }
+ if (i == 0 && finish <= 0)
+ return -1;
+ return i;
+ }
+}
+
+final class Iso8859_1Reader extends BaseReader
+{
+ Iso8859_1Reader (InputStream in) { super (in); }
+
+ public int read (char buf [], int offset, int len) throws IOException
+ {
+ int i;
+
+ if (instream == null)
+ return -1;
+
+ // avoid many runtime bounds checks ... a good optimizer
+ // (static or JIT) will now remove checks from the loop.
+ if ((offset + len) > buf.length || offset < 0)
+ throw new ArrayIndexOutOfBoundsException ();
+
+ for (i = 0; i < len; i++) {
+ if (start >= finish) {
+ start = 0;
+ finish = instream.read (buffer, 0, buffer.length);
+ if (finish <= 0) {
+ if (finish <= 0)
+ this.close ();
+ break;
+ }
+ }
+ buf [offset + i] = (char) (0x0ff & buffer [start++]);
+ }
+ if (i == 0 && finish <= 0)
+ return -1;
+ return i;
+ }
+}
+
1.3 +77 -43 jakarta-tomcat/src/share/org/apache/tomcat/core/package.html
Index: package.html
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/package.html,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- package.html 2000/04/17 21:02:27 1.2
+++ package.html 2000/04/26 18:57:35 1.3
@@ -1,45 +1,79 @@
<html>
-<head>
-<title>The servlet engine implementation</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-</head>
-
-<body bgcolor="#FFFFFF">
-<h2>Components</h2>
-
-<dl>
-
-<dt>Facades
-<dd>For every object exposed in the servlet specification tomcat use a
-Facade. It have few important advantages:
-<ul>
-<li>Security - the user should have no way to access the real implementation
-objects, except one controled way ( HttpRequestFacade.getRealRequest() ).
-When policy-based security will be added that will allow the user to declare a
-"trusted" servlet, and no other servlet will be able to access internal objects.
-<li>Future evolution of Servlet API - the API changed and will probably change,
-by adding new methods and new semantics. Facades makes very simple to make sure
-we respect the spec, without having to change the core too much.
-That may allow supporting multiple servlet API versions ( but it's not a goal -
-each context has it's own classloader and it may be possible to load a different
-JDK and set of facades ).
-<li>Decouple the API and the web server. Tomcat.core allows integration with
-web servers, and it's modeled after APIs like Apache's, ISAPI and NSAPI.
-</ul>
-
-</dd>
-
-<dt>Request,Response
-<dd>
-
-<dt>Context, Container, ServletWrapper
-<dd>
-
-<dt>ContextManager
-<dd>
-
-</dl>
-
-
-</body>
+ <head>
+ <title>The servlet engine implementation</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ </head>
+
+ <body bgcolor="#FFFFFF">
+ <h2>Components</h2>
+
+ <dl>
+
+ <dt>ContextManager</dt>
+ <dd>
+ <ul>
+ <li>maintains a list of adapters</li>
+ <li>is the entry point for adapters and any component that can generate
+ a Request/Response and wants to use servlets.</li>
+ <li>is the control point that handles callback calls and notifications.</li>
+ <li>maintains a list of webapps that are configured in the system.</li>
+ </ul>
+ </dd>
+
+ <dt>Request,Response</dt>
+ <dd>Internal representations, containing various attributes associated with
+ the request during processing.
+ </dd>
+
+ <dt>Interceptors</dt>
+ <dd>
+ Request processing involves several stages - parsing, matching using url
+ patterns, authentication and authorization, calling the handler and various
+ callbacks before, after and during the handler.
+ An interceptor defines callbacks ( or hooks ) for one or several actions
+ and is able to alter that function.
+ In fact, most of the processing logic is implemented as interceptor
+ callbacks, in an event-based system.
+ </dd>
+
+ <dt>Context, Container</dt>
+ <dd>
+ Container represents a group of URLs sharing common properties like handler,
+ security, normal properties. Context is a particular case that is associated
+ with a web application and keeps all the properties defined in the spec.
+ We are slowly moving toward use of Container, it can also represent group
+ of contexts, virtual hosts, etc.
+ It is not a good idea to introduce sub-classes for every type of group,
+ the isA property is not allways clearly cut.
+ </dd>
+
+ <dt>ServletWrapper</dt>
+ <dd>
+ A normal servlet or JSP, plus all the surounding logic.
+ </dd>
+
+
+ <dt>Facades</dt>
+ <dd>For every object exposed in the servlet specification tomcat use a
+ Facade. It have few important advantages:
+ <ul>
+ <li>Security - the user should have no way to access the real implementation
+ objects, except one controled way ( HttpRequestFacade.getRealRequest() ).
+ When policy-based security will be added that will allow the user to declare a
+ "trusted" servlet, and no other servlet will be able to access internal objects.</li>
+ <li>Future evolution of Servlet API - the API changed and will probably change,
+ by adding new methods and new semantics. Facades makes very simple to make sure
+ we respect the spec, without having to change the core too much.
+ That may allow supporting multiple servlet API versions ( but it's not a goal -
+ each context has it's own classloader and it may be possible to load a different
+ JDK and set of facades ).</li>
+ <li>Decouple the API and the web server. Tomcat.core allows integration with
+ web servers, and it's modeled after APIs like Apache's, ISAPI and NSAPI.</li>
+ </ul>
+
+ </dd>
+ </dl>
+
+
+ </body>
</html>
1.3 +3 -3 jakarta-tomcat/src/share/org/apache/tomcat/request/SimpleMapper1.java
Index: SimpleMapper1.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/SimpleMapper1.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- SimpleMapper1.java 2000/04/25 17:54:19 1.2
+++ SimpleMapper1.java 2000/04/26 18:57:36 1.3
@@ -172,11 +172,11 @@
// beeing late
// Add all context that are set in CM
- Enumeration enum=cm.getContextNames();
+ Enumeration enum=cm.getContexts();
while( enum.hasMoreElements() ) {
- String name=(String) enum.nextElement();
+
try {
- Context ctx=cm.getContext( name );
+ Context ctx=(Context)enum.nextElement();
addContext( cm, ctx );
} catch (TomcatException ex ) {
ex.printStackTrace();
1.23 +1 -1 jakarta-tomcat/src/share/org/apache/tomcat/startup/Tomcat.java
Index: Tomcat.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/startup/Tomcat.java,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -r1.22 -r1.23
--- Tomcat.java 2000/04/25 17:54:29 1.22
+++ Tomcat.java 2000/04/26 18:57:36 1.23
@@ -155,7 +155,7 @@
tchome = "."; // Assume current working directory
}
// Home will be identical to tomcat home if default config is used.
- cm.setTomcatHome(tchome);
+ cm.setInstallDir(tchome);
return (new File(tchome, DEFAULT_CONFIG));
}
1.6 +17 -3 jakarta-tomcat/src/share/org/apache/tomcat/util/FileUtil.java
Index: FileUtil.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/FileUtil.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- FileUtil.java 2000/03/16 20:43:26 1.5
+++ FileUtil.java 2000/04/26 18:57:36 1.6
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/FileUtil.java,v 1.5 2000/03/16 20:43:26 costin Exp $
- * $Revision: 1.5 $
- * $Date: 2000/03/16 20:43:26 $
+ * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/FileUtil.java,v 1.6 2000/04/26 18:57:36 costin Exp $
+ * $Revision: 1.6 $
+ * $Date: 2000/04/26 18:57:36 $
*
* ====================================================================
*
@@ -65,6 +65,7 @@
package org.apache.tomcat.util;
import java.io.File;
+import java.io.IOException;
/*
* FileUtil contains utils for dealing with Files. Some of these are
@@ -202,5 +203,18 @@
}
return path;
}
+
+ // Used in few places.
+ public static String getCanonicalPath(String name ) {
+ if( name==null ) return null;
+ File f = new File(name);
+ try {
+ return f.getCanonicalPath();
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ return name; // oh well, we tried...
+ }
+ }
+
}