tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cos...@locus.apache.org
Subject cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/util FileUtil.java
Date Sat, 30 Sep 2000 04:03:48 GMT
costin      00/09/29 21:03:47

  Modified:    src/facade22/org/apache/tomcat/facade
                        HttpServletRequestFacade.java
                        Servlet22Interceptor.java ServletContextFacade.java
                        WebXmlReader.java
               src/facade22/org/apache/tomcat/modules/facade22
                        JspInterceptor.java
               src/facade23/org/apache/tomcat/facade23
                        HttpServletRequestFacade.java
                        ServletContextFacade.java
               src/share/org/apache/tomcat/context DefaultCMSetter.java
               src/share/org/apache/tomcat/core BaseInterceptor.java
                        Context.java ContextManager.java Request.java
               src/share/org/apache/tomcat/request ReloadInterceptor.java
                        StaticInterceptor.java
               src/share/org/apache/tomcat/util FileUtil.java
  Log:
  Almost done with Context( first out of 8).
  
  Moved getRealPath() and getResource() to facade - both are likely to
  be specific to version and not used in core.
  
  GetRealPath() was called in StaticInterceptor and few places -
  it all ends up to safePath(), a very expensive operation - and it's
  bad to call it several times instead of once. Need to
  optimize SI. Anyway, it's better to have the bad code clearly
  visible.
  
  Also added more documentation to Context, re-aranged the code, added
  short comments to fields.
  
  Except for addContainer() and addServletMapping() everything is done
  ( from my point of view - I'm waiting for the next who likes some fun
  refactoring code - I hope there isn't too much left in Context :-)
  
  Revision  Changes    Path
  1.6       +3 -1      jakarta-tomcat/src/facade22/org/apache/tomcat/facade/HttpServletRequestFacade.java
  
  Index: HttpServletRequestFacade.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/facade22/org/apache/tomcat/facade/HttpServletRequestFacade.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- HttpServletRequestFacade.java	2000/09/26 04:58:19	1.5
  +++ HttpServletRequestFacade.java	2000/09/30 04:03:33	1.6
  @@ -362,7 +362,9 @@
        * @deprecated
        */
       public String getRealPath(String name) {
  -        return request.getContext().getRealPath(name);
  +	Context ctx=request.getContext();
  +        return FileUtil.safePath( ctx.getAbsolutePath(),
  +				  name);
       }
       
       // -------------------- Security --------------------
  
  
  
  1.3       +1 -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.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Servlet22Interceptor.java	2000/09/29 06:59:51	1.2
  +++ Servlet22Interceptor.java	2000/09/30 04:03:33	1.3
  @@ -153,7 +153,7 @@
       public int postRequest(Request rreq, Response rres ) {
   	//if( rreq.getContext() != ctx ) return; // throw
   
  -	log( "Recycling " + rreq );
  +	//	log( "Recycling " + rreq );
   	HttpServletRequest req=(HttpServletRequest)rreq.getFacade();
   	if( ! (req instanceof HttpServletRequestFacade))
   	    return 0;
  
  
  
  1.4       +20 -4     jakarta-tomcat/src/facade22/org/apache/tomcat/facade/ServletContextFacade.java
  
  Index: ServletContextFacade.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/facade22/org/apache/tomcat/facade/ServletContextFacade.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- ServletContextFacade.java	2000/09/26 04:58:19	1.3
  +++ ServletContextFacade.java	2000/09/30 04:03:33	1.4
  @@ -95,7 +95,7 @@
   
       // -------------------- Public facade methods --------------------
       public ServletContext getContext(String path) {
  -        Context target=context.getContext(path);
  +        Context target=contextM.getContext(context, path);
   	return (ServletContext)target.getFacade();
       }
   
  @@ -129,8 +129,10 @@
           return context.getMimeMap().getContentTypeFor(filename);
       }
   
  +    // Specific to servlet version and interpretation.
       public String getRealPath(String path) {
  -	return context.getRealPath( path );
  + 	return FileUtil.safePath( context.getAbsolutePath(),
  +				  path);
       }
   
       public InputStream getResourceAsStream(String path) {
  @@ -146,8 +148,22 @@
   	return is;
       }
   
  -    public URL getResource(String path)	throws MalformedURLException {
  -	return context.getResource( path );
  +    public URL getResource(String rpath) throws MalformedURLException {
  +	if (rpath == null) return null;
  +
  +	String absPath=context.getAbsolutePath();
  +	String realPath=FileUtil.safePath( absPath, rpath);
  +	if( realPath==null ) {
  +	    log( "Unsafe path " + absPath + " " + rpath );
  +	    return null;
  +	}
  +
  +	try {
  +            return new URL("file", null, 0,realPath );
  +	} catch( IOException ex ) {
  +	    log("getting resource " + rpath, ex);
  +	    return null;
  +	}
       }
   
       public RequestDispatcher getRequestDispatcher(String path) {
  
  
  
  1.3       +9 -5      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.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- WebXmlReader.java	2000/09/29 06:59:52	1.2
  +++ WebXmlReader.java	2000/09/30 04:03:33	1.3
  @@ -65,10 +65,6 @@
   	// mime-mapping - are build into MimeMap.
   	// Note that default mappings are based on existing registered types.
   
  -	// index pages - still use the hack, but it'll go away soon
  -	for( int i=0; i< defaultWelcomeList.length; i++ )
  -	    ctx.addWelcomeFile( defaultWelcomeList[i]);
  -	ctx.expectUserWelcomeFiles();
       }
   
   
  @@ -89,7 +85,6 @@
   	    return;
   	
   	processWebXmlFile(ctx , default_xml.getPath());
  -	ctx.expectUserWelcomeFiles();
       }
       
       public void contextInit(Context ctx) throws TomcatException {
  @@ -113,6 +108,15 @@
   	    if( inf_xml.exists() )
   		processWebXmlFile(ctx, inf_xml.getPath() );
   
  +	    // If the user haven't set any welcome file, use the
  +	    // defaults.
  +	    // If the user specifies welcome files, it's assumed he
  +	    // doesn't want extra
  +	    String newWF[]=ctx.getWelcomeFiles();
  +	    if( newWF==null || newWF.length==0 ) {
  +		for( int i=0; i< defaultWelcomeList.length; i++ )
  +		    ctx.addWelcomeFile( defaultWelcomeList[i]);
  +	    }
   	} catch (Exception e) {
   	    String msg = sm.getString("context.getConfig.e",ctx.getPath() + " " + ctx.getDocBase());
   	    log(msg, e);
  
  
  
  1.7       +7 -4      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.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- JspInterceptor.java	2000/09/29 06:59:56	1.6
  +++ JspInterceptor.java	2000/09/30 04:03:35	1.7
  @@ -65,6 +65,7 @@
   import java.net.*;
   
   import org.apache.tomcat.util.log.*;
  +import org.apache.tomcat.util.*;
   
   import org.apache.jasper.*;
   import org.apache.jasper.Constants;
  @@ -412,7 +413,8 @@
   	uri=req.getServletPath();
   	Context ctx=req.getContext();
   	outputDir = ctx.getWorkDir().getAbsolutePath();
  -	String jspFilePath=ctx.getRealPath( uri );
  +	String jspFilePath=FileUtil.safePath( ctx.getAbsolutePath(),
  +					      uri); 
   	jspSource = new File(jspFilePath);
   	
   	// extension
  @@ -838,9 +840,10 @@
        */
       public String getRealPath(String path)
       {
  -	log("GetRP " + path + " " +
  -			   req.getContext().getRealPath(path));
  -	return req.getContext().getRealPath(path);
  +	log("GetRP " + path);
  +	Context ctx=req.getContext();
  +	return FileUtil.safePath( ctx.getAbsolutePath(),
  +				  path);
       };
   
       void log(String s, Exception e) {
  
  
  
  1.5       +3 -1      jakarta-tomcat/src/facade23/org/apache/tomcat/facade23/HttpServletRequestFacade.java
  
  Index: HttpServletRequestFacade.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/facade23/org/apache/tomcat/facade23/HttpServletRequestFacade.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- HttpServletRequestFacade.java	2000/09/26 04:58:21	1.4
  +++ HttpServletRequestFacade.java	2000/09/30 04:03:36	1.5
  @@ -370,7 +370,9 @@
        * @deprecated
        */
       public String getRealPath(String name) {
  -        return request.getContext().getRealPath(name);
  +	Context ctx=request.getContext();
  +	return FileUtil.safePath( ctx.getAbsolutePath(),
  +				  name);
       }
       
       // -------------------- Security --------------------
  
  
  
  1.4       +19 -4     jakarta-tomcat/src/facade23/org/apache/tomcat/facade23/ServletContextFacade.java
  
  Index: ServletContextFacade.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/facade23/org/apache/tomcat/facade23/ServletContextFacade.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- ServletContextFacade.java	2000/09/26 04:58:22	1.3
  +++ ServletContextFacade.java	2000/09/30 04:03:37	1.4
  @@ -94,7 +94,7 @@
   
       // -------------------- Public facade methods --------------------
       public ServletContext getContext(String path) {
  -        Context target=context.getContext(path);
  +        Context target=contextM.getContext(context, path);
   	return (ServletContext)target.getFacade();
       }
   
  @@ -128,7 +128,8 @@
       }
   
       public String getRealPath(String path) {
  -	return context.getRealPath( path );
  +	return FileUtil.safePath( context.getAbsolutePath(),
  +				  path);
       }
   
       public InputStream getResourceAsStream(String path) {
  @@ -144,8 +145,22 @@
   	return is;
       }
   
  -    public URL getResource(String path)	throws MalformedURLException {
  -	return context.getResource( path );
  +    public URL getResource(String rpath)	throws MalformedURLException {
  +	if (rpath == null) return null;
  +
  +	String absPath=context.getAbsolutePath();
  +	String realPath=FileUtil.safePath( absPath, rpath);
  +	if( realPath==null ) {
  +	    log( "Unsafe path " + absPath + " " + rpath );
  +	    return null;
  +	}
  +
  +	try {
  +            return new URL("file", null, 0,realPath );
  +	} catch( IOException ex ) {
  +	    log("getting resource " + rpath, ex);
  +	    return null;
  +	}
       }
   
       public RequestDispatcher getRequestDispatcher(String path) {
  
  
  
  1.53      +31 -0     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.52
  retrieving revision 1.53
  diff -u -r1.52 -r1.53
  --- DefaultCMSetter.java	2000/09/29 07:00:55	1.52
  +++ DefaultCMSetter.java	2000/09/30 04:03:38	1.53
  @@ -80,6 +80,37 @@
       public DefaultCMSetter() {
       }
   
  +    public void addContext( ContextManager cm, Context ctx)
  +	throws TomcatException
  +    {
  +	// adjust context paths and loggers
  +
  +	String docBase=ctx.getDocBase();
  +	String absPath=ctx.getAbsolutePath();
  +	if( absPath==null ) {
  +	    if (FileUtil.isAbsolute( docBase ) )
  +		absPath=docBase;
  +	    else
  +		absPath = cm.getHome() + File.separator + docBase;
  +	    try {
  +		absPath = new File(absPath).getCanonicalPath();
  +	    } catch (IOException npe) {
  +	    }
  +	    ctx.setAbsolutePath( absPath );
  +	}
  +
  +	
  +	// this would belong to a logger interceptor ?
  +	Log loghelper=ctx.getLog();
  +	Log loghelperServlet=ctx.getServletLog();
  +	
  +	if( loghelper!=null && loghelper.getLogger() != null )
  +	    cm.addLogger( loghelper.getLogger() );
  +	if( loghelperServlet != null &&
  +	    loghelperServlet.getLogger() != null)
  +	    cm.addLogger( loghelperServlet.getLogger() );
  +    }
  +
       public void contextInit( Context ctx)
   	throws TomcatException
       {
  
  
  
  1.22      +15 -9     jakarta-tomcat/src/share/org/apache/tomcat/core/BaseInterceptor.java
  
  Index: BaseInterceptor.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/BaseInterceptor.java,v
  retrieving revision 1.21
  retrieving revision 1.22
  diff -u -r1.21 -r1.22
  --- BaseInterceptor.java	2000/09/29 07:00:59	1.21
  +++ BaseInterceptor.java	2000/09/30 04:03:39	1.22
  @@ -268,6 +268,9 @@
        *  The first interceptor in the chain for contextInit must read web.xml
        *  and set the context. When this method is called you can expect the
        *  context to be filled in with all the informations from web.xml.
  +     * 
  +     *  WebXmlReader needs to be the first interceptor in
  +     *  the contextInit chain.
        */
       public void contextInit(Context ctx)
   	throws TomcatException
  @@ -344,17 +347,20 @@
       }
   
   
  -    /** Called when a context is added to a CM. The context is probably not
  -     *  initialized yet, only path and docRoot are probably set.
  -     *
  -     *  If you need informations that are available in web.xml use
  -     *  contextInit()( a WebXmlReader needs to be the first interceptor in
  -     *  the contextInit chain ).
  +    /**
  +     *  Called when a context is added to a CM. The context is probably not
  +     *  initialized yet, only path, docRoot, host, and properties set before adding
  +     *  the context ( in server.xml for example ) are available.
        * 
  -     *  We do that to support ( eventualy ) a "lazy" init, where you have
  -     *  many contexts, most of them not in active use, and you'll init them
  -     *  at first request. ( for example an ISP with many users )
  +     *  At this stage mappers can start creating structures for the
  +     *  context ( the actual loading of the context may be delayed in
  +     *  future versions of tomcat until the first access ).
  +     *
  +     *  DefaultCMSetter will also adjust the logger and paths
  +     *  based on context manager properties.
        *
  +     *  Any activity that depends on web.xml must be done at
  +     *  init time.
        */
       public void addContext( ContextManager cm, Context ctx )
   	throws TomcatException
  
  
  
  1.123     +460 -545  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.122
  retrieving revision 1.123
  diff -u -r1.122 -r1.123
  --- Context.java	2000/09/29 07:01:00	1.122
  +++ Context.java	2000/09/30 04:03:39	1.123
  @@ -71,22 +71,23 @@
   import java.util.*;
   
   
  -/* Right now we have all the properties defined in web.xml.
  -   The interceptors will  go into Container ( every request will
  -   be associated with the final container, which will point back to the
  -   context). That will allow us to use a simpler and more "targeted"
  -   object model.
  -
  -   The only "hard" part is moving getResource() and getRealPath() in
  -   a different class, using a filesystem independent abstraction. 
  -   
  -*/
  -   
  -
   /**
    * Context represent a Web Application as specified by Servlet Specs.
    * The implementation is a repository for all the properties
    * defined in web.xml and tomcat specific properties.
  + * 
  + * This object has many properties, but doesn't do anything special
  + * except simple cashing.
  + *
  + * You need to set at least "path" and "base" before adding a
  + * context to a server. You can also set any other properties.
  + *
  + * At addContext() stage log and paths will be "fixed" based on
  + * context manager settings.
  + *
  + * At initContext() stage, web.xml will be read and all other
  + * properties will be set. WebXmlReader must be the first
  + * module in initContext() chain. 
    *
    * @author James Duncan Davidson [duncan@eng.sun.com]
    * @author James Todd [gonzo@eng.sun.com]
  @@ -95,9 +96,11 @@
    * @author costin@dnt.ro
    * @author Gal Shachor shachor@il.ibm.com
    */
  -public class Context implements LogAware {
  +public final class Context implements LogAware {
  +    // -------------------- Constants --------------------
  +    
       // Proprietary attribute names for contexts - defined
  -    // here so we can document them
  +    // here so we can document them ( will show in javadoc )
   
       /** Private tomcat attribute names
        */
  @@ -114,6 +117,9 @@
       /** Workdir - a place where the servlets are allowed to write
        */
       public static final String ATTRIB_WORKDIR="org.apache.tomcat.workdir";
  +    public static final String ATTRIB_WORKDIR1 = "javax.servlet.context.tempdir";
  +    public static final String ATTRIB_WORKDIR2 = "sun.servlet.workdir";
  +    
   
       /** This attribute will return the real context (
        *  org.apache.tomcat.core.Context).
  @@ -135,8 +141,11 @@
       // internal state / related objects
       private ContextManager contextM;
       private Object contextFacade;
  +    // print debugging information
  +    private int debug=0;
   
  -    boolean reloadable=true; 
  +    // enable reloading
  +    private boolean reloadable=true; 
   
       // XXX Use a better repository
       private Hashtable attributes = new Hashtable();
  @@ -147,56 +156,86 @@
       // Servlets loaded by this context( String->ServletWrapper )
       private Hashtable servlets = new Hashtable();
   
  -    // -------------------- from web.xml
  +    // Initial properties for the context
       private Hashtable initializationParameters = new Hashtable();
   
  -    // all welcome files that are added are treated as "system default"
  -    private boolean expectUserWelcomeFiles=false;
  -    private Vector welcomeFiles = new Vector();
  -    
  +    // WelcomeFiles
  +    private Vector welcomeFilesV=new Vector();
  +    // cached for faster access
  +    private String welcomeFiles[] = null;
  +
  +    // Defined error pages. 
       private Hashtable errorPages = new Hashtable();
  -    private String description = null;
  -    private boolean isDistributable = false;
  +
  +    // mime mappings
       private MimeMap mimeTypes = new MimeMap();
  +
  +    // Default session time out
       private int sessionTimeOut = -1;
   
  -    // taglibs
  -    Hashtable tagLibs=new Hashtable();
  -    // Env entries
  -    Hashtable envEntryTypes=new Hashtable();
  -    Hashtable envEntryValues=new Hashtable();
  +    private boolean isDistributable = false;
   
       // Maps specified in web.xml ( String url -> Handler  )
       private Hashtable mappings = new Hashtable();
  -    Hashtable constraints=new Hashtable();
   
  -    Hashtable containers=new Hashtable();
  +    // Security constraints ( String url -> Container )
  +    private Hashtable constraints=new Hashtable();
   
  -    Container defaultContainer = null; // generalization, will replace most of the
  -    // functionality. By using a default container we avoid a lot of checkings
  -    // and speed up searching, and we can get rid of special properties.
  -    //    private Handler defaultServlet = null;
  +    // All url patterns ( url_pattern -> properties )
  +    private Hashtable containers=new Hashtable();
   
  -    // Authentication properties
  -    String authMethod;
  -    String realmName;
  -    String formLoginPage;
  -    String formErrorPage;
  +    // Container used if no match is found
  +    // Also contains the special properties for
  +    // this context. 
  +    private Container defaultContainer = null;
   
  -    // verbosity level 
  -    int debug=0;
  +    // Authentication properties
  +    private String authMethod;
  +    private String realmName;
  +    private String formLoginPage;
  +    private String formErrorPage;
   
       // Servlet-Engine header ( default set by Servlet facade)
       private String engineHeader = null;
   
  -    // are servlets allowed to access internal objects? 
  -    boolean trusted=false;
  -
       // Virtual host name ( null if default )
  -    String vhost=null;
  +    private String vhost=null;
       // vhost aliases 
  -    Vector vhostAliases=new Vector();
  +    private Vector vhostAliases=new Vector();
  +
  +    // are servlets allowed to access internal objects? 
  +    private boolean trusted=false;
  +
  +    // log channels for context and servlets 
  +    private Log loghelper = new Log("tc_log", this);
  +    private Log loghelperServlet;
  +
  +    // servlet API implemented by this Context
  +    private String apiLevel="2.2";
  +
  +    // class loader for this context
  +    private ClassLoader classLoader;
  +    // Vector<URL>, using URLClassLoader conventions
  +    private Vector classPath=new Vector();
  +
  +    // true if a change was detected and this context
  +    // needs reload
  +    private boolean reload;
  +    // Tool used to control reloading
  +    private DependManager dependM;
  +
  +    // -------------------- from web.xml --------------------
  +    // Those properties are not directly used in context
  +    // operation, we just store them.
  +    private String description = null;
  +    private String icon=null;
  +    // taglibs
  +    private Hashtable tagLibs=new Hashtable();
  +    // Env entries
  +    private Hashtable envEntryTypes=new Hashtable();
  +    private Hashtable envEntryValues=new Hashtable();
   
  +    // -------------------- Constructor --------------------
       
       public Context() {
   	defaultContainer=new Container();
  @@ -204,17 +243,165 @@
   	defaultContainer.setPath( null ); // default container
       }
   
  +
  +    // -------------------- Active methods --------------------
  +
  +    // The main role of Context is to store the many properties
  +    // that a web application have.
  +
  +    // There are only few methods here that actually do something
  +    // ( and we try to keep the object "passive" - it is already
  +    // full of properties, no need to make it to complicated.
  +
  +    
  +    /**
  +     * Maps a named servlet to a particular path or extension.
  +     *
  +     * If the named servlet is unregistered, it will be added
  +     * and subsequently mapped. The servlet can be set by intereceptors
  +     * during addContainer() hook.
  +     *
  +     * If the mapping already exists it will be replaced by the new
  +     * mapping.
  +     */
  +    public final  void addServletMapping(String path, String servletName)
  +	throws TomcatException
  +    {
  +	if( mappings.get( path )!= null) {
  +	    log( "Removing duplicate " + path + " -> " + mappings.get(path) );
  +	    mappings.remove( path );
  +	    Container ct=(Container)containers.get( path );
  +	    removeContainer( ct );
  +	}
  +
  +	// sw may be null - in wich case interceptors may
  +	// set it 
  +        Handler sw = getServletByName(servletName);
  +	
  +	Container map=new Container();
  +	map.setContext( this );
  +	map.setHandlerName( servletName );
  +	map.setHandler( sw );
  +	map.setPath( path );
  +
  +	// callback - hooks are called. 
  +	contextM.addContainer( map );
  +
  +	sw = getServletByName(servletName);
  +	
  +	
  +	if (sw == null) {
  +	    // web.xml validation - a mapping with no servlet rollback
  +	    contextM.removeContainer( map );
  + 	    throw new TomcatException( "Mapping with invalid servlet  " +
  +				       path + " " + servletName );
  +	}
  +
  +	containers.put( path, map );
  +	mappings.put( path, sw );
  +
  +    }
  +
  +    /** Will add a new security constraint:
  +	For all paths:
  +	if( match(path) && match(method) && match( transport ) )
  +	then require("roles")
  +
  +	This is equivalent with adding a Container with the path,
  +	method and transport. If the container will be matched,
  +	the request will have to pass the security constraints.
  +	
  +    */
  +    public final  void addSecurityConstraint( String path[], String methods[],
  +				       String roles[], String transport)
  +	throws TomcatException
  +    {
  +	for( int i=0; i< path.length; i++ ) {
  +	    Container ct=new Container();
  +	    ct.setContext( this );
  +	    ct.setTransport( transport );
  +	    ct.setRoles( roles );
  +	    ct.setPath( path[i] );
  +	    ct.setMethods( methods );
  +
  +	    // XXX check if exists, merge if true.
  +	    constraints.put( path[i], ct );
  +	    //contextM.addSecurityConstraint( this, path[i], ct);
  +	    contextM.addContainer(  ct );
  +	}
  +    }
  +
  +    /** getAttribute( "org.apache.tomcat.*" ) may return something
  +	special
  +    */
  +    private Object getSpecialAttribute( String name ) {
  +	// deprecated - invalid and wrong prefix
  +	if( name.equals( ATTRIB_WORKDIR1 ) ) 
  +	    return getWorkDir();
  +	if( name.equals( ATTRIB_WORKDIR2 ) ) 
  +	    return getWorkDir();
  +
  +	// this saves 5 compare for non-special attributes
  +	if (name.startsWith( ATTRIB_PREFIX )) {
  +	    // XXX XXX XXX XXX Security - servlets may get too much access !!!
  +	    // right now we don't check because we need JspServlet to
  +	    // be able to access classloader and classpath
  +	    if( name.equals( ATTRIB_WORKDIR ) ) 
  +		return getWorkDir();
  +	    
  +	    if (name.equals("org.apache.tomcat.jsp_classpath")) {
  +		String separator = System.getProperty("path.separator", ":");
  +		StringBuffer cpath=new StringBuffer();
  +		URL classPaths[]=getClassPath();
  +		for(int i=0; i< classPaths.length ; i++ ) {
  +		    URL cp = classPaths[i];
  +		    if (cpath.length()>0) cpath.append( separator );
  +		    cpath.append(cp.getFile());
  +		}
  +		if( debug>9 ) log("Getting classpath " + cpath);
  +		return cpath.toString();
  +	    }
  +	    if(name.equals("org.apache.tomcat.classloader")) {
  +		return this.getClassLoader();
  +	    }
  +	    if(name.equals(ATTRIB_REAL_CONTEXT)) {
  +		if( ! allowAttribute(name) ) {
  +			return null;
  +		}
  +		return this;
  +	    }
  +	}
  +	return null; 
  +    }
  +    
  +    /** Check if "special" attributes can be used by
  +     *   user application. Only trusted apps can get 
  +     *   access to the implementation object.
  +     */
  +    public final  boolean allowAttribute( String name ) {
  +	// check if we can access this attribute.
  +	if( isTrusted() ) return true;
  +	log( "Attempt to access internal attribute in untrusted app",
  +	     null, Logger.ERROR);
  +	return false;
  +    }
  +
  +    // -------------------- Passive properties --------------------
  +    // Everything bellow is just get/set
  +    // for web application properties 
  +    // --------------------
  +    
  +    // -------------------- Facade --------------------
  +    
       /** Every context is associated with a facade. We don't know the exact
   	type of the facade, as a Context can be associated with a 2.2 ...
   	ServletContext.
  -
  -	I'm not sure if this method is good - it adds deps to upper layers.
        */
  -    public Object getFacade() {
  +    public final  Object getFacade() {
   	return contextFacade;
       }
   
  -    public void setFacade(Object obj) {
  +    public final  void setFacade(Object obj) {
           if(contextFacade!=null )
   	    log( "Changing facade " + contextFacade + " " +obj);
   	contextFacade=obj;
  @@ -225,41 +412,36 @@
   
       /** Returned the main server ( servlet container )
        */
  -    public ContextManager getContextManager() {
  +    public final  ContextManager getContextManager() {
   	return contextM;
       }
   
  -    public void setContextManager(ContextManager cm) {
  +    /** This method is called when the Context is added
  +	to a server. Some of the Context properties
  +	depend on the ContextManager, and will be adjusted
  +	by interceptors ( DefaultCMSetter )
  +    */
  +    public final  void setContextManager(ContextManager cm) {
   	contextM=cm;
  -	// let the contextmanager know about our local logger
  -	// ( and open it, adjust the path, etc )
  -	if( loghelper!=null && loghelper.getLogger() != null )
  -	    contextM.addLogger( loghelper.getLogger() );
  -	if( loghelperServlet != null &&
  -	    loghelperServlet.getLogger() != null)
  -	    contextM.addLogger( loghelperServlet.getLogger() );
       }
   
  -    /** The servlet API variant that will be used for requests in this
  -     *  context
  -     */ 
  -    public void setServletAPI( String s ) {
  -	if( s!=null &&
  -	    ( s.endsWith("23") || s.endsWith("2.3")) ) {
  -	} else {
  -	}
  +    /** Default container for this context.
  +     */
  +    public final  Container getContainer() {
  +	return defaultContainer;
       }
   
  +    // -------------------- Basic properties --------------------
   
       /** Base URL for this context
        */
  -    public String getPath() {
  +    public final  String getPath() {
   	return path;
       }
   
       /** Base URL for this context
        */
  -    public void setPath(String path) {
  +    public final  void setPath(String path) {
   	// config believes that the root path is called "/",
   	//
   	if( "/".equals(path) )
  @@ -267,6 +449,22 @@
   	this.path = path;
       }
   
  +    /**
  +     *  Make this context visible as part of a virtual host.
  +     *  The host is the "default" name, it may also have aliases.
  +     */
  +    public final  void setHost( String h ) {
  +	vhost=h;
  +    }
  +
  +    /**
  +     * Return the virtual host name, or null if we are in the
  +     * default context
  +     */
  +    public final  String getHost() {
  +	return vhost;
  +    }
  +    
       /** DocBase points to the web application files.
        *
        *  There is no restriction on the syntax and content of DocBase,
  @@ -276,295 +474,256 @@
        *
        *  "Basic" tomcat treats it as a file ( either absolute or relative to
        *  the CM home ).
  -     *
  -     *  If docBase is relative assume it is relative  to the context manager home.
        */
  -    public void setDocBase( String docB ) {
  +    public final  void setDocBase( String docB ) {
   	this.docBase=docB;
       }
  -
   
  -    public String getDocBase() {
  +    public final  String getDocBase() {
   	return docBase;
       }
   
       /** Return the absolute path for the docBase, if we are file-system
        *  based, null otherwise.
       */
  -    public String getAbsolutePath() {
  -	if( absPath!=null) return absPath;
  -
  -	if (FileUtil.isAbsolute( docBase ) )
  -	    absPath=docBase;
  -	else
  -	    absPath = contextM.getHome() + File.separator + docBase;
  -	try {
  -	    absPath = new File(absPath).getCanonicalPath();
  -	} catch (IOException npe) {
  -	}
  +    public final  String getAbsolutePath() {
   	return absPath;
       }
   
  -    // -------------------- Tomcat specific properties
  -    // workaround for XmlMapper unable to set anything but strings
  -    public void setReloadable( String s ) {
  -	reloadable=new Boolean( s ).booleanValue();
  +    /** Set the absolute path to this context.
  +     * 	If not set explicitely, it'll be docBase ( if absolute )
  +     *  or relative to "home" ( cm.getHome() ).
  +     *  DefaultCMSetter will "fix" the path.
  +     */
  +    public final  void setAbsolutePath(String s) {
  +	absPath=s;
       }
  -
  -    public void setReloadable( boolean b ) {
  +    
  +    // -------------------- Tomcat specific properties --------------------
  +    
  +    public final  void setReloadable( boolean b ) {
   	reloadable=b;
       }
   
       /** Should we reload servlets ?
        */
  -    public boolean getReloadable() {
  +    public final  boolean getReloadable() {
   	return reloadable;
       }
  -
  -    // -------------------- Web.xml properties --------------------
   
  -    public Enumeration getWelcomeFiles() {
  -	return welcomeFiles.elements();
  +    // -------------------- API level --------------------
  +    
  +    /** The servlet API variant that will be used for requests in this
  +     *  context
  +     */ 
  +    public final  void setServletAPI( String s ) {
  +	if( s==null ) return;
  +	if( s.endsWith("23") || s.endsWith("2.3")) {
  +	    apiLevel="2.3";
  +	} else if( ( s.endsWith("22") || s.endsWith("2.2")) ) {
  +	    apiLevel="2.2";
  +	} else {
  +	    log( "Unknown API " + s );
  +	}
       }
   
  -    /** @deprecated It is used as a hack to allow web.xml override default
  -	 welcome files.
  -	 Tomcat will first load the "default" web.xml and then this file.
  -    */
  -    public void removeWelcomeFiles() {
  -	if( ! this.welcomeFiles.isEmpty() )
  -	    this.welcomeFiles.removeAllElements();
  +    public final  String getServletAPI() {
  +	return apiLevel;
       }
  +    
  +    // -------------------- Welcome files --------------------
   
  -    /** If any new welcome file is added, remove the old list of
  -     *  welcome files and start a new one. This is used as a hack to
  -     *  allow a default web.xml file to specifiy welcome files.
  -     *  We should use a better mechanism! 
  +    /** Return welcome files defined in web.xml or the
  +     *  defaults, if user doesn't define any
        */
  -    public void expectUserWelcomeFiles() {
  -	expectUserWelcomeFiles = true;
  +    public final  String[] getWelcomeFiles() {
  +	if( welcomeFiles==null ) {
  +	    welcomeFiles=new String[ welcomeFilesV.size() ];
  +	    for( int i=0; i< welcomeFiles.length; i++ ) {
  +		welcomeFiles[i]=(String)welcomeFilesV.elementAt( i );
  +	    }
  +	}
  +	return welcomeFiles;
       }
  -    
   
  -    public void addWelcomeFile( String s) {
  -	// user specified at least one user welcome file, remove the system
  -	// files
  +    /** Add an welcome file. 
  +     */
  +    public final  void addWelcomeFile( String s) {
   	if (s == null ) return;
   	s=s.trim();
   	if(s.length() == 0)
   	    return;
  -	if(  expectUserWelcomeFiles  ) {
  -	    removeWelcomeFiles();
  -	    expectUserWelcomeFiles=false;
  -	} 
  -	welcomeFiles.addElement( s );
  +	welcomeFiles=null; // invalidate the cache
  +	welcomeFilesV.addElement( s );
       }
   
  -    /** Add a taglib declaration for this context
  -     */
  -    public void addTaglib( String uri, String location ) {
  -	//	log("Add taglib " + uri + "  " + location );
  -	tagLibs.put( uri, location );
  +    // -------------------- Init parameters --------------------
  +    
  +    public final  String getInitParameter(String name) {
  +        return (String)initializationParameters.get(name);
       }
   
  -    public String getTaglibLocation( String uri ) {
  -	return (String)tagLibs.get(uri );
  +    public final  void addInitParameter( String name, String value ) {
  +	initializationParameters.put(name, value );
       }
   
  -    public Enumeration getTaglibs() {
  -	return tagLibs.keys();
  +    public final  Enumeration getInitParameterNames() {
  +        return initializationParameters.keys();
       }
   
  -    /** Add Env-entry to this context
  +
  +    // --------------------  Attributes --------------------
  +
  +    /** Return an attribute value.
  +     *  "Special" attributes ( defined org.apache.tomcat )
  +     *  are computed
  +     * 
  +     *  XXX Use callbacks !!
        */
  -    public void addEnvEntry( String name,String type, String value, String description ) {
  -	log("Add env-entry " + name + "  " + type + " " + value + " " +description );
  -	if( name==null || type==null) throw new IllegalArgumentException();
  -	envEntryTypes.put( name, type );
  -	if( value!=null)
  -	    envEntryValues.put( name, value );
  +    public final  Object getAttribute(String name) {
  +	Object o=getSpecialAttribute( name );
  +	if ( o!=null ) return o;
  +	return attributes.get(name);    
       }
   
  -    public String getEnvEntryType(String name) {
  -	return (String)envEntryTypes.get(name);
  +    public final  Enumeration getAttributeNames() {
  +        return attributes.keys();
       }
   
  -    public String getEnvEntryValue(String name) {
  -	return (String)envEntryValues.get(name);
  +    public final  void setAttribute(String name, Object object) {
  +        attributes.put(name, object);
       }
   
  -    public Enumeration getEnvEntries() {
  -	return envEntryTypes.keys();
  +    public final  void removeAttribute(String name) {
  +        attributes.remove(name);
       }
   
  -    public String getInitParameter(String name) {
  -        return (String)initializationParameters.get(name);
  -    }
  +
  +    // -------------------- Web.xml properties --------------------
   
  -    /** @deprecated use addInitParameter
  +    /** Add a taglib declaration for this context
        */
  -    public void setInitParameter( String name, String value ) {
  -	initializationParameters.put(name, value );
  +    public final  void addTaglib( String uri, String location ) {
  +	tagLibs.put( uri, location );
       }
   
  -    public void addInitParameter( String name, String value ) {
  -	initializationParameters.put(name, value );
  +    public final  String getTaglibLocation( String uri ) {
  +	return (String)tagLibs.get(uri );
       }
   
  -    public Enumeration getInitParameterNames() {
  -        return initializationParameters.keys();
  +    public final  Enumeration getTaglibs() {
  +	return tagLibs.keys();
       }
   
  -        
  -    /** Workdir attribute - XXX is it specified anyway ? 
  +    /** Add Env-entry to this context
        */
  -    public static final String ATTRIB_WORKDIR1 = "javax.servlet.context.tempdir";
  -    // XXX deprecated, is anyone in the world using it ?
  -    public static final String ATTRIB_WORKDIR2 = "sun.servlet.workdir";
  -    
  -    public Object getAttribute(String name) {
  -	// deprecated 
  -	if( name.equals( ATTRIB_WORKDIR1 ) ) 
  -	    return getWorkDir();
  -	if( name.equals( ATTRIB_WORKDIR2 ) ) 
  -	    return getWorkDir();
  -
  -	
  -	if (name.startsWith( ATTRIB_PREFIX )) {
  -	    // XXX XXX XXX XXX Security - servlets may get too much access !!!
  -	    // right now we don't check because we need JspServlet to
  -	    // be able to access classloader and classpath
  -	    if( name.equals( ATTRIB_WORKDIR ) ) 
  -		return getWorkDir();
  -	    
  -	    if (name.equals("org.apache.tomcat.jsp_classpath")) {
  -		String separator = System.getProperty("path.separator", ":");
  -		StringBuffer cpath=new StringBuffer();
  -		URL classPaths[]=getClassPath();
  -		for(int i=0; i< classPaths.length ; i++ ) {
  -		    URL cp = classPaths[i];
  -		    if (cpath.length()>0) cpath.append( separator );
  -		    cpath.append(cp.getFile());
  -		}
  -		if( debug>9 ) log("Getting classpath " + cpath);
  -		return cpath.toString();
  -	    }
  -	    if(name.equals("org.apache.tomcat.classloader")) {
  -		return this.getClassLoader();
  -	    }
  -	    if(name.equals(ATTRIB_REAL_CONTEXT)) {
  -		if( ! allowAttribute(name) ) return null;
  -		return this;
  -	    }
  -	    // 	    if( name.equals(FacadeManager.FACADE_ATTRIBUTE)) {
  -	    // 		if( ! allowAttribute(name) ) return null;
  -	    // 		return this.getFacadeManager();
  -	    // 	    }
  -	    return null; // org.apache.tomcat namespace is reserved in tomcat
  -	} else {
  -            Object o = attributes.get(name);
  -            return attributes.get(name);
  -        }
  +    public final  void addEnvEntry( String name,String type, String value, String description ) {
  +	log("Add env-entry " + name + "  " + type + " " + value + " " +description );
  +	if( name==null || type==null) throw new IllegalArgumentException();
  +	envEntryTypes.put( name, type );
  +	if( value!=null)
  +	    envEntryValues.put( name, value );
       }
   
  -    public Enumeration getAttributeNames() {
  -        return attributes.keys();
  +    public final  String getEnvEntryType(String name) {
  +	return (String)envEntryTypes.get(name);
       }
   
  -    public void setAttribute(String name, Object object) {
  -        attributes.put(name, object);
  +    public final  String getEnvEntryValue(String name) {
  +	return (String)envEntryValues.get(name);
       }
   
  -    public void removeAttribute(String name) {
  -        attributes.remove(name);
  +    public final  Enumeration getEnvEntries() {
  +	return envEntryTypes.keys();
       }
   
  -    public String getDescription() {
  +    
  +    public final  String getDescription() {
           return this.description;
       }
   
  -    public void setDescription(String description) {
  +    public final  void setDescription(String description) {
           this.description = description;
       }
   
  -    public void setIcon( String icon ) {
  -
  +    public final  void setIcon( String icon ) {
  +	this.icon=icon;
       }
   
  -    public boolean isDistributable() {
  +    public final  boolean isDistributable() {
           return this.isDistributable;
       }
   
  -    public void setDistributable(boolean isDistributable) {
  +    public final  void setDistributable(boolean isDistributable) {
           this.isDistributable = isDistributable;
       }
   
  -    public void setDistributable(String s) {
  -	// XXX
  -    }
  -
  -    public int getSessionTimeOut() {
  +    public final  int getSessionTimeOut() {
           return this.sessionTimeOut;
       }
   
  -    public void setSessionTimeOut(int sessionTimeOut) {
  +    public final  void setSessionTimeOut(int sessionTimeOut) {
           this.sessionTimeOut = sessionTimeOut;
       }
  +
  +    // -------------------- Mime types --------------------
   
  -    public FileNameMap getMimeMap() {
  +    public final  FileNameMap getMimeMap() {
           return mimeTypes;
       }
   
  -    public void addContentType( String ext, String type) {
  +    public final  void addContentType( String ext, String type) {
   	mimeTypes.addContentType( ext, type );
       }
  +    
  +    // -------------------- Error pages --------------------
   
  -    public String getErrorPage(int errorCode) {
  +    public final  String getErrorPage(int errorCode) {
           return getErrorPage(String.valueOf(errorCode));
       }
   
  -    public void addErrorPage( String errorType, String value ) {
  +    public final  void addErrorPage( String errorType, String value ) {
   	this.errorPages.put( errorType, value );
       }
   
  -    public String getErrorPage(String errorCode) {
  +    public final  String getErrorPage(String errorCode) {
           return (String)errorPages.get(errorCode);
       }
   
   
  +    // -------------------- Auth --------------------
  +    
       /** Authentication method, if any specified
        */
  -    public String getAuthMethod() {
  +    public final  String getAuthMethod() {
   	return authMethod;
       }
   
       /** Realm to be used
        */
  -    public String getRealmName() {
  +    public final  String getRealmName() {
   	return realmName;
       }
   
  -    public String getFormLoginPage() {
  +    public final  String getFormLoginPage() {
   	return formLoginPage;
       }
   
  -    public String getFormErrorPage() {
  +    public final  String getFormErrorPage() {
   	return formErrorPage;
       }
   
  -    public void setFormLoginPage( String page ) {
  +    public final  void setFormLoginPage( String page ) {
   	formLoginPage=page;
       }
       
  -    public void setFormErrorPage( String page ) {
  +    public final  void setFormErrorPage( String page ) {
   	formErrorPage=page;
       }
   
  -    public void setLoginConfig( String authMethod, String realmName,
  +    public final  void setLoginConfig( String authMethod, String realmName,
   				String formLoginPage, String formErrorPage)
       {
  -	// 	log("Login config: " + authMethod + " " + realmName + " " +
  -	// 			   formLoginPage + " " + formErrorPage);
   	this.authMethod=authMethod;
   	this.realmName=realmName;
   	this.formLoginPage=formLoginPage;
  @@ -573,99 +732,7 @@
   
       // -------------------- Mappings --------------------
   
  -    /**
  -     * Maps a named servlet to a particular path or extension.
  -     *
  -     * If the named servlet is unregistered, it will be added
  -     * and subsequently mapped. The servlet can be set by intereceptors
  -     * during addContainer() hook.
  -     *
  -     * If the mapping already exists it will be replaced by the new
  -     * mapping.
  -     *
  -     * Note that the servlet 2.2 standard mapings are:
  -     *
  -     *    exact mapped servlet (eg /catalog)
  -     *    prefix mapped servlets (eg /foo/bar/*)
  -     *    extension mapped servlets (eg *jsp)
  -     *    default servlet
  -     *
  -     * XXX XXX XXX
  -     *
  -     */
  -    public void addServletMapping(String path, String servletName)
  -	throws TomcatException
  -    {
  -	if( mappings.get( path )!= null) {
  -	    log( "Removing duplicate " + path + " -> " + mappings.get(path) );
  -	    mappings.remove( path );
  -	    Container ct=(Container)containers.get( path );
  -	    removeContainer( ct );
  -	}
  -
  -	// sw may be null - in wich case interceptors may
  -	// set it 
  -        Handler sw = getServletByName(servletName);
  -	
  -	Container map=new Container();
  -	map.setContext( this );
  -	map.setHandlerName( servletName );
  -	map.setHandler( sw );
  -	map.setPath( path );
  -
  -	// callback - hooks are called. 
  -	contextM.addContainer( map );
  -
  -	sw = getServletByName(servletName);
  -	
  -	
  -	if (sw == null) {
  -	    // web.xml validation - a mapping with no servlet
  -	    // rollback
  -	    contextM.removeContainer( map );
  - 	    throw new TomcatException( "Mapping with invalid servlet name " +
  -				       path + " " + servletName );
  -	}
  -
  -	// override defaultServlet XXX do we need defaultServlet?
  -// 	if( "/".equals(path) )
  -// 	    defaultServlet = sw;
  -
  -	containers.put( path, map );
  -	mappings.put( path, sw );
  -
  -    }
  -
  -    /** Will add a new security constraint:
  -	For all paths:
  -	if( match(path) && match(method) && match( transport ) )
  -	then require("roles")
  -
  -	This is equivalent with adding a Container with the path,
  -	method and transport. If the container will be matched,
  -	the request will have to pass the security constraints.
  -	
  -    */
  -    public void addSecurityConstraint( String path[], String methods[],
  -				       String roles[], String transport)
  -	throws TomcatException
  -    {
  -	for( int i=0; i< path.length; i++ ) {
  -	    Container ct=new Container();
  -	    ct.setContext( this );
  -	    ct.setTransport( transport );
  -	    ct.setRoles( roles );
  -	    ct.setPath( path[i] );
  -	    ct.setMethods( methods );
  -
  -	    // XXX check if exists, merge if true.
  -	    constraints.put( path[i], ct );
  -	    //contextM.addSecurityConstraint( this, path[i], ct);
  -	    contextM.addContainer(  ct );
  -	}
  -    }
  -
  -    public Enumeration getContainers() {
  +    public final  Enumeration getContainers() {
   	return containers.elements();
       }
   
  @@ -673,98 +740,73 @@
        *  all URLs ( relative to this context ) having
        *	associated properties ( handlers, security, etc)
        */
  -    public Enumeration getContainerLocations() {
  +    public final  Enumeration getContainerLocations() {
   	return containers.keys();
       }
   
       /** Return the container ( properties ) associated
        *  with a path ( relative to this context )
        */
  -    public Container getContainer( String path ) {
  +    public final  Container getContainer( String path ) {
   	return (Container)containers.get(path);
       }
   
  -    /** Default container for this context.
  -     */
  -    public Container getContainer() {
  -	return defaultContainer;
  -    }
  -
       /** Remove a container
        */
  -    public void removeContainer( Container ct ) {
  +    public final  void removeContainer( Container ct ) {
   	containers.remove(ct.getPath());
       }
   
       // -------------------- Servlets management --------------------
  -
  -    /** Remove the servlet with a specific name
  -     */
  -    public void removeServletByName(String servletName)
  -	throws TomcatException
  -    {
  -	servlets.remove( servletName );
  -    }
  -
  -    /**
  -     *  
  -     */
  -    public Handler getServletByName(String servletName) {
  -	return (Handler)servlets.get(servletName);
  -    }
  -
  -
       /**
  -     * Add a servlet with the given name to the container. The
  -     * servlet will be loaded by the container's class loader
  -     * and instantiated using the given class name.
  -     *
  -     * Called to add a new servlet from web.xml or by interceptors
  -     * to dynamically add servlets and mappings ( for example
  -     * JspInterceptor is registering a new servlet after it compiles
  -     * the jsp page, and an exact map to avoid further overhead )
  -     *
  -     * Handlers are keyed by name.
  -     * XXX should be addHandler
  +     * Add a servlet. Servlets are mapped by name.
  +     * This method is used to maintain the list of declared
  +     * servlets, that can be used for mappings.
        */
  -    public void addServlet(Handler wrapper)
  +    public final  void addServlet(Handler wrapper)
       	throws TomcatException
       {
   	wrapper.setContext( this );
   	String name=wrapper.getName();
  -	//	log("Adding servlet " + name  + " " + wrapper);
   
           // check for duplicates
           if (getServletByName(name) != null) {
   	    log("Removing duplicate servlet " + name  + " " + wrapper);
               removeServletByName(name);
  -	    //	    getServletByName(name).destroy();
           }
   	servlets.put(name, wrapper);
       }
   
  +    /** Remove the servlet with a specific name
  +     */
  +    public final  void removeServletByName(String servletName)
  +	throws TomcatException
  +    {
  +	servlets.remove( servletName );
  +    }
  +
  +    /**
  +     *  
  +     */
  +    public final  Handler getServletByName(String servletName) {
  +	return (Handler)servlets.get(servletName);
  +    }
  +
  +
       
       /** Return all servlets registered with this Context
        *  The elements will be of type Handler ( or sub-types ) 
        */
  -    public Enumeration getServletNames() {
  +    public final  Enumeration getServletNames() {
   	return servlets.keys();
       }
   
       // -------------------- Loading and sessions --------------------
   
  -    ClassLoader classLoader;
  -    boolean reload;
  -    // Vector<URL>, using URLClassLoader conventions
  -    Vector classPath=new Vector();
  -    DependManager dependM;
  -    
       /** The current class loader. This value may change if reload
        *  is used, you shouldn't cache the result
        */
       public final ClassLoader getClassLoader() {
  -	// 	if( servletL!=null) // backward compat
  -	// 	    return servletL.getClassLoader();
   	return classLoader;
       }
   
  @@ -773,42 +815,27 @@
       }
   
       // temp. properties until reloading is separated.
  -    public boolean shouldReload() {
  -	// 	if( servletL!=null) // backward compat
  -	// 	    return servletL.shouldReload();
  +    public final  boolean shouldReload() {
   	if( dependM != null )
   	    return dependM.shouldReload();
   	return reload;
       }
   
  -    public void setReload( boolean b ) {
  +    public final  void setReload( boolean b ) {
   	reload=b;
       }
  -
  -    public void reload() {
  -	// 	if( servletL!=null) // backward compat
  -	// 	    servletL.reload();
  -	Enumeration sE=servlets.elements();
  -	while( sE.hasMoreElements() ) {
  -	    try {
  -		Handler sw=(Handler)sE.nextElement();
  -		// 		if( sw.getServletClassName() != null ) {
  -		// 		    // this is dynamicaly added, probably a JSP.
  -		// 		    // in any case, we can't save it
  -		sw.reload();
  -		//		}
  -	    } catch( Exception ex ) {
  -		log( "Reload exception: " + ex);
  -	    }
  -	}
  -	// XXX todo
  -    }
   
  -    public void addClassPath( URL url ) {
  +    // -------------------- ClassPath --------------------
  +    
  +    public final  void addClassPath( URL url ) {
   	classPath.addElement( url);
       }
   
  -    public URL[] getClassPath() {
  +    /** Returns the full classpath - concatenation
  +	of ContextManager classpath and locally specified
  +	class path
  +    */
  +    public final  URL[] getClassPath() {
   	if( classPath==null ) return new URL[0];
   	URL serverCP[]=contextM.getServerClassPath();
   	URL urls[]=new URL[classPath.size() + serverCP.length];
  @@ -822,43 +849,37 @@
   	return urls;
       }
   
  -    public void setDependManager(DependManager dm ) {
  +    // -------------------- Depend manager ( used for reloading ) -----------
  +    
  +    public final  void setDependManager(DependManager dm ) {
   	dependM=dm;
       }
   
  -    public DependManager getDependManager( ) {
  +    public final  DependManager getDependManager( ) {
   	return dependM;
       }
       
       /* -------------------- Utils  -------------------- */
  -    public void setDebug( int level ) {
  +    public final  void setDebug( int level ) {
   	if (level!=debug)
   	    log( "Setting debug to " + level );
   	debug=level;
       }
   
  -    public void setDebug( String level ) {
  -	try {
  -	    setDebug( Integer.parseInt(level) );
  -	} catch (Exception e) {
  -	    log("Trying to set debug to '" + level + "':", e, Logger.ERROR);
  -	}
  -    }
  -
  -    public int getDebug( ) {
  +    public final  int getDebug( ) {
   	return debug;
       }
  -
       
  -    public String toString() {
  +    public final  String toString() {
   	return "Ctx(" + (vhost==null ? "" : vhost + ":" )  +  path +  ")";
       }
   
       // ------------------- Logging ---------------
  -
  -    Log loghelper = new Log("tc_log", this);
  -    Log loghelperServlet;
   
  +    public final  String getId() {
  +	return ((vhost==null) ? "" : vhost + ":" )  +  path;
  +    }
  +    
       /** Internal log method
        */
       public final void log(String msg) {
  @@ -867,13 +888,13 @@
   
       /** Internal log method
        */
  -    public void log(String msg, Throwable t) {
  +    public final  void log(String msg, Throwable t) {
   	loghelper.log(msg, t);
       }
   
       /** Internal log method
        */
  -    public void log(String msg, Throwable t, int level) {
  +    public final  void log(String msg, Throwable t, int level) {
   	loghelper.log(msg, t, level);
       }
   
  @@ -882,186 +903,91 @@
        *  tomcat core ( internals ) and one is used by 
        *  servlets
        */
  -    public void logServlet( String msg , Throwable t ) {
  +    public final  void logServlet( String msg , Throwable t ) {
   	if (loghelperServlet == null) {
  -	    String pr= ((vhost==null) ? "" : vhost + ":" )  +  path;
  +	    String pr= getId();
   	    loghelperServlet = new Log("servlet_log", pr );
   	}
   	if (t == null)
   	    loghelperServlet.log(msg);	// uses level INFORMATION
   	else
   	    loghelperServlet.log(msg, t); // uses level ERROR
  -	// note: log(msg,t) is deprecated in ServletContext; that
  -	// means most servlet messages will arrive with level
  -	// INFORMATION.  So the "servlet_log" Logger should be
  -	// specified with verbosityLevel="INFORMATION" in server.xml
  -	// in order to see servlet log() messages.
       }
   
  -    public void setLogger(Logger logger) {
  +    public final  void setLogger(Logger logger) {
   	if (loghelper == null) {
  -	    String pr=((vhost==null ? "" : vhost + ":" )  +  path);
  +	    String pr=getId();
   	    loghelper = new Log("tc_log", pr );
   	}
   	loghelper.setLogger(logger);
       }
   
  -    public void setServletLogger(Logger logger) {
  +    public final  void setServletLogger(Logger logger) {
   	if (loghelperServlet == null) {
  -	    String pr=((vhost==null ? "" : vhost + ":" )  +  path);
  +	    String pr=getId();
   	    loghelperServlet = new Log("servlet_log",pr);
   	}
   	loghelperServlet.setLogger(logger);
       }
   
  -    public Log getLog() {
  +    public final  Log getLog() {
   	return loghelper;
       }
  -
  -    // -------------------- Path methods  --------------------
  -
  -    /**
  -     *   Find a context by doing a sub-request and mapping the request
  -     *   against the active rules ( that means you could use a /~costin
  -     *   if a UserHomeInterceptor is present )
  -     *
  -     *   XXX I think this should be in ContextManager
  -     */
  -    public Context getContext(String path) {
  -	// XXX Servlet checks should be done in facade
  -	if (! path.startsWith("/")) {
  -	    return null; // according to spec, null is returned
  -	    // if we can't  return a servlet, so it's more probable
  -	    // servlets will check for null than IllegalArgument
  -	}
  -	// absolute path
  -	Request lr=contextM.createRequest( path );
  -	if( vhost != null ) lr.setServerName( vhost );
  -	getContextManager().processRequest(lr);
  -        return lr.getContext();
  -    }
   
  -    /** Implements getResource()
  -     *  See getRealPath(), it have to be local to the current Context -
  -     *  and can't go to a sub-context. That means we don't need any overhead.
  -     *
  -     *  XXX XXX Don't use - must be moved at a higher layer ( facade ).
  -     *  or re-designed to support non-filesystem-based contexts. In
  -     *  any case, this method shouldn't be in core
  -     */
  -    public URL getResource(String rpath) throws MalformedURLException {
  -        if (rpath == null) return null;
  -
  -        URL url = null;
  -	String absPath=getAbsolutePath();
  -
  -	if ("".equals(rpath))
  -	    return new URL( "file", null, 0, absPath );
  -
  -	if ( ! rpath.startsWith("/")) 
  -	    rpath="/" + rpath;
  -
  -	String realPath=FileUtil.safePath( absPath, rpath);
  -	if( realPath==null ) {
  -	    log( "Unsafe path " + absPath + " " + rpath );
  -	    return null;
  -	}
  -	
  -	try {
  -            url=new URL("file", null, 0,realPath );
  -	    if( debug>9) log( "getResourceURL=" + url + " request=" + rpath );
  -	    return url;
  -	} catch( IOException ex ) {
  -	    log("getting resource " + rpath, ex);
  -	    return null;
  -	}
  +    public final  Log getServletLog() {
  +	return loghelperServlet;
       }
   
  -
  -    /**
  -     *  Return the absolute path, using the context base dir.
  -     *  The parameter is interpreted as relative to the context
  -     *  with a number of safety checks ( no .., etc)
  -     *
  -     *  If you want to find the path where an arbitrary request
  -     *  lead you need a sub request.
  -     *
  -     *  XXX XXX Don't use this method - it's better to just call
  -     *  safePath() when you need ( i.e. there are ways to factor
  -     *  out the security checks, that method is not good )
  -     */
  -    public String getRealPath( String path) {
  -	String base=getAbsolutePath();
  -	if( path==null ) return base;
  -
  -	String realPath=FileUtil.safePath( base, path );
  -	
  -	if( debug>5) {
  -	    log("Get real path " + path + " " + realPath + " " + base );
  -	}
  -	return realPath;
  -    }
  +    // -------------------- Path methods  --------------------
   
       /**  What is reported in the "Servlet-Engine" header
        *   for this context. It is set automatically by
        *   a facade interceptor.
        *   XXX Do we want to allow user to customize it ?
        */
  -    public void setEngineHeader(String s) {
  +    public final  void setEngineHeader(String s) {
           engineHeader=s;
       }
   
       /**  
        */
  -    public String getEngineHeader() {
  +    public final  String getEngineHeader() {
   	return engineHeader;
       }
  +
  +    // -------------------- Work dir --------------------
       
       /**
        *  Work dir is a place where servlets are allowed
        *  to write
        */
  -    public void setWorkDir(String workDir) {
  +    public final  void setWorkDir(String workDir) {
   	this.workDir = new File(workDir);
       }
   
       /**  
        */
  -    public File getWorkDir() {
  +    public final  File getWorkDir() {
   	return workDir;
       }
   
       /**  
        */
  -    public void setWorkDir(File workDir) {
  +    public final  void setWorkDir(File workDir) {
   	this.workDir = workDir;
       }
   
       // -------------------- Virtual host support --------------------
       
  -    /** Make this context visible as part of a virtual host.
  -     *  The host is the "default" name, it may also have aliases.
  -     */
  -    public void setHost( String h ) {
  -	vhost=h;
  -    }
  -
  -    /** Return the virtual host name, or null if we are in the
  -	default context
  -    */
  -    public String getHost() {
  -	return vhost;
  -    }
  -    
       /** Virtual host support - this context will be part of 
        *  a virtual host with the specified name. You should
        *  set all the aliases. XXX Not implemented
        */
  -    public void addHostAlias( String alias ) {
  +    public final  void addHostAlias( String alias ) {
   	vhostAliases.addElement( alias );
       }
   
  -    public Enumeration getHostAliases() {
  +    public final  Enumeration getHostAliases() {
   	return vhostAliases.elements();
       }
       // -------------------- Security - trusted code -------------------- 
  @@ -1069,25 +995,14 @@
       /** Mark the webapplication as trusted, i.e. it can
        *  access internal objects and manipulate tomcat core
        */
  -    public void setTrusted( boolean t ) {
  +    public final  void setTrusted( boolean t ) {
   	trusted=t;
       }
   
  -    public boolean isTrusted() {
  +    public final  boolean isTrusted() {
   	return trusted;
       }
   
  -    /** Check if "special" attributes can be used by
  -     *   user application. Only trusted apps can get 
  -     *   access to the implementation object.
  -     */
  -    public boolean allowAttribute( String name ) {
  -	// check if we can access this attribute.
  -	if( isTrusted() ) return true;
  -	log( "Illegal access to internal attribute ", null, Logger.ERROR);
  -	return false;
  -    }
  -
       // -------------------- Per-context interceptors ----------
   
       /** Add a per-context interceptor. The hooks defined will
  @@ -1095,14 +1010,14 @@
        *  contextMap hook is not called ( since the context is not
        *	known at that time
        */
  -    public void addInterceptor( BaseInterceptor ri ) {
  +    public final  void addInterceptor( BaseInterceptor ri ) {
           defaultContainer.addRequestInterceptor(ri);
       }
   
   
       // -------------------- Deprecated --------------------
       
  -    public void addRequestInterceptor( BaseInterceptor ri ) {
  +    public final  void addRequestInterceptor( BaseInterceptor ri ) {
           addInterceptor( ri );
       }
   }
  
  
  
  1.138     +23 -0     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.137
  retrieving revision 1.138
  diff -u -r1.137 -r1.138
  --- ContextManager.java	2000/09/29 07:01:01	1.137
  +++ ContextManager.java	2000/09/30 04:03:43	1.138
  @@ -1274,6 +1274,29 @@
   	return (Context)contexts.get(name);
       }
   
  +    
  +    /**
  +     *   Find a context by doing a sub-request and mapping the request
  +     *   against the active rules ( that means you could use a /~costin
  +     *   if a UserHomeInterceptor is present )
  +     *
  +     *   XXX I think this should be in ContextManager
  +     */
  +    public final  Context getContext(Context base, String path) {
  +	// XXX Servlet checks should be done in facade
  +	if (! path.startsWith("/")) {
  +	    return null; // according to spec, null is returned
  +	    // if we can't  return a servlet, so it's more probable
  +	    // servlets will check for null than IllegalArgument
  +	}
  +	// absolute path
  +	Request lr=this.createRequest( path );
  +	if( base.getHost() != null ) lr.setServerName( base.getHost() );
  +	this.processRequest(lr);
  +        return lr.getContext();
  +    }
  +
  +
       /**
        * Shut down and removes a context from service.
        *
  
  
  
  1.65      +3 -1      jakarta-tomcat/src/share/org/apache/tomcat/core/Request.java
  
  Index: Request.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/Request.java,v
  retrieving revision 1.64
  retrieving revision 1.65
  diff -u -r1.64 -r1.65
  --- Request.java	2000/09/29 07:01:03	1.64
  +++ Request.java	2000/09/30 04:03:43	1.65
  @@ -340,7 +340,9 @@
   	// info is present
   	pathTranslated=null;
   	if(path==null || "".equals( path ) ) return null;
  -	pathTranslated=context.getRealPath( path );
  +
  +	pathTranslated=FileUtil.safePath( context.getAbsolutePath(),
  +					  path);
   	return pathTranslated;
       }
   
  
  
  
  1.5       +11 -1     jakarta-tomcat/src/share/org/apache/tomcat/request/ReloadInterceptor.java
  
  Index: ReloadInterceptor.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/ReloadInterceptor.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ReloadInterceptor.java	2000/08/28 03:14:02	1.4
  +++ ReloadInterceptor.java	2000/09/30 04:03:45	1.5
  @@ -162,7 +162,17 @@
   		// user servlets, but still need work XXX.
   
   		// we also need to save context attributes.
  -		ctx.reload();
  +
  +		Enumeration sE=ctx.getServletNames();
  +		while( sE.hasMoreElements() ) {
  +		    try {
  +			String sN=(String)sE.nextElement();
  +			Handler sw=ctx.getServletByName( sN );
  +			sw.reload();
  +		    } catch( Exception ex ) {
  +			log( "Reload exception: " + ex);
  +		    }
  +		}
   
   		// send notification to all interceptors
   		// They may try to save up the state or take
  
  
  
  1.21      +12 -8     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.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- StaticInterceptor.java	2000/09/29 21:10:04	1.20
  +++ StaticInterceptor.java	2000/09/30 04:03:46	1.21
  @@ -126,7 +126,10 @@
   	// and a number of checks
   	String pathInfo=req.getServletPath();
   	if( pathInfo==null ) pathInfo="";
  -	String absPath=ctx.getRealPath( pathInfo );
  +
  +	String absPath=FileUtil.safePath( ctx.getAbsolutePath(),
  +					  pathInfo);
  +
   	if( absPath == null ) return 0;
   	String requestURI=req.getRequestURI();
   
  @@ -191,13 +194,12 @@
       }
   
       private String getWelcomeFile(Context context, File dir) {
  -        Enumeration enum = context.getWelcomeFiles();
  +        String wf[]= context.getWelcomeFiles();
   
  -	while (enum.hasMoreElements()) {
  -	    String fileName = (String)enum.nextElement();
  -	    File f = new File(dir, fileName);
  +	for( int i=0; i<wf.length; i++ ) {
  +	    File f = new File(dir, wf[i]);
   	    if (f.exists()) {
  -		return fileName;
  +		return wf[i];
   	    }
   	}
   	return null;
  @@ -237,7 +239,8 @@
   	String pathInfo=subReq.getServletPath();
   	String absPath = (String)subReq.getNote( realFileNote );
   	if( absPath==null )
  -	    absPath=ctx.getRealPath( pathInfo );
  +	    absPath=FileUtil.safePath( context.getAbsolutePath(),
  +				       pathInfo);
   
   	if( debug>0) log( "Requested file = " + absPath);
   	String base = ctx.getAbsolutePath();
  @@ -352,7 +355,8 @@
   	Context ctx=req.getContext();
   	String pathInfo=subReq.getServletPath();
   	if( pathInfo == null ) pathInfo="";
  -	String absPath=ctx.getRealPath( pathInfo );
  +	String absPath=FileUtil.safePath( context.getAbsolutePath(),
  +					  pathInfo);
   	File file = new File( absPath );
   	String requestURI=subReq.getRequestURI();
   	String base = ctx.getAbsolutePath();
  
  
  
  1.14      +5 -4      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.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- FileUtil.java	2000/09/29 07:01:51	1.13
  +++ FileUtil.java	2000/09/30 04:03:47	1.14
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/FileUtil.java,v 1.13 2000/09/29 07:01:51 costin Exp $
  - * $Revision: 1.13 $
  - * $Date: 2000/09/29 07:01:51 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/FileUtil.java,v 1.14 2000/09/30 04:03:47 costin Exp $
  + * $Revision: 1.14 $
  + * $Date: 2000/09/30 04:03:47 $
    *
    * ====================================================================
    *
  @@ -135,7 +135,8 @@
       public static String safePath( String base, String path ) {
   	// Hack for Jsp ( and other servlets ) that use rel. paths 
   	// if( ! path.startsWith("/") ) path="/"+ path;
  -
  +	if( path==null || path.equals("") ) return base;
  +	
   	String normP=path;
   	if( path.indexOf('\\') >=0 )
   	    normP= path.replace('\\', '/');
  
  
  

Mime
View raw message