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/01/14 05:08:12 UTC

cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/servlets DefaultErrorPage.java

costin      00/01/13 20:08:11

  Modified:    src/share/org/apache/tomcat/core Context.java
                        ServletWrapper.java
               src/share/org/apache/tomcat/request MapperInterceptor.java
  Added:       src/share/org/apache/tomcat/core JspWrapper.java
               src/share/org/apache/tomcat/servlets DefaultErrorPage.java
  Log:
  Split ServletWrapper in 3:
  - JspWrapper will handle the very special case of Jsps declared in web.xml -
  it has strange code, and need a rewrite, but it shouldn't affect the rest of core
  
  - DefaultErrorHandler contains all the error reporting code that used to be in
  ServletWrapper - it should be possible now to customize the error page ( more
  details, etc) - assuming you add Class.forName() and a bit of code.
  
  - ServletWrapper - just servlet informations, plus load/init/destroy + service calling.
  
  Revision  Changes    Path
  1.31      +18 -13    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.30
  retrieving revision 1.31
  diff -u -r1.30 -r1.31
  --- Context.java	2000/01/13 18:56:04	1.30
  +++ Context.java	2000/01/14 04:08:10	1.31
  @@ -715,16 +715,15 @@
       }
   
   
  -    // -------------------- 
  -    public void addJSP(String name, String path) {
  -        addJSP(name, null, path);
  -    }
  -
  +    // --------------------
  +    
  +    /** Add a jsp to the "pre-defined" list ( used by web.xml )
  +     */
       public void addJSP(String name, String path, String description) {
           // XXX
           // check for duplicates!
   
  -        ServletWrapper wrapper = new ServletWrapper(this);
  +        JspWrapper wrapper = new JspWrapper(this);
   
   	wrapper.setServletName(name);
   	wrapper.setServletDescription(description);
  @@ -780,12 +779,18 @@
   	    sw.length > 0);
       }
   
  +    /** Will remove a JSP from the list of "declared" jsps.
  +     *  Called only by deployment descriptor - to deal with
  +     *  duplicated mappings -
  +     *  XXX Find out if we really need that - it can be avoided!
  +     */
       public void removeJSP(String path) {
   	Enumeration enum = servlets.keys();
   	while (enum.hasMoreElements()) {
   	    String key = (String)enum.nextElement();
   	    ServletWrapper sw = (ServletWrapper)servlets.get(key);
  -	    if (path.equals(sw.getPath()))
  +	    if( (sw instanceof JspWrapper ) &&
  +		path.equals( ((JspWrapper)sw).getPath()))
   	        removeServlet( sw );
   	}
       }
  @@ -814,13 +819,14 @@
           ServletWrapper sw = (ServletWrapper)servlets.get(servletName);
   
   	if (sw == null) {
  +	    System.out.println("Servlet not registered " + servletName );
   	    // XXX
   	    // this might be a bit aggressive
   
  -	    if (! servletName.startsWith("/")) {
  -	        addServlet(servletName, null, servletName);
  +	    if ( servletName.startsWith("/")) {
  +	        addJSP(servletName, servletName, null);
   	    } else {
  -	        addJSP(servletName, servletName);
  +	        addServlet(servletName, null, servletName);
   	    }
   
   	    sw = (ServletWrapper)servlets.get(servletName);
  @@ -996,10 +1002,9 @@
   	    String key = (String)enum.nextElement();
   	    ServletWrapper sw = (ServletWrapper)servlets.get(key);
   
  -	    if (sw.getPath() != null &&
  -	        sw.getPath().equals(path)) {
  +	    if( (sw instanceof JspWrapper ) &&
  +		path.equals( ((JspWrapper)sw).getPath()))
   	        servletWrappers.addElement(sw);
  -	    }
   	}
   
   	ServletWrapper[] wrappers =
  
  
  
  1.13      +120 -283  jakarta-tomcat/src/share/org/apache/tomcat/core/ServletWrapper.java
  
  Index: ServletWrapper.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ServletWrapper.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- ServletWrapper.java	2000/01/13 23:28:27	1.12
  +++ ServletWrapper.java	2000/01/14 04:08:11	1.13
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ServletWrapper.java,v 1.12 2000/01/13 23:28:27 costin Exp $
  - * $Revision: 1.12 $
  - * $Date: 2000/01/13 23:28:27 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ServletWrapper.java,v 1.13 2000/01/14 04:08:11 costin Exp $
  + * $Revision: 1.13 $
  + * $Date: 2000/01/14 04:08:11 $
    *
    * ====================================================================
    *
  @@ -60,8 +60,6 @@
    * [Additional notices, if required by prior licensing conditions]
    *
    */ 
  -
  -
   package org.apache.tomcat.core;
   
   import org.apache.tomcat.util.*;
  @@ -72,11 +70,13 @@
   import javax.servlet.http.*;
   
   /**
  + * Class used to represent a servlet inside a Context.
    * 
    * @author James Duncan Davidson [duncan@eng.sun.com]
    * @author Jason Hunter [jch@eng.sun.com]
    * @author James Todd [gonzo@eng.sun.com]
    * @author Harish Prabandham
  + * @author costin@dnt.ro
    */
   
   //
  @@ -84,27 +84,35 @@
   // Please talk to harishp@eng.sun.com before making any changes.
   //
   public class ServletWrapper {
  +    protected StringManager sm = StringManager.getManager("org.apache.tomcat.core");
   
  -    private StringManager sm =
  -        StringManager.getManager(Constants.Package);
  -    private Context context;
  -    private String description = null;
  -    private String servletClassName;
  -    private Class servletClass;
  -    private File servletClassFile;
  -    private String path = null;
  -    private Servlet servlet;
  -    private long lastAccessed;
  -    private ServletConfigImpl config;
  -    private boolean isReloadable = false;
  -    private long classFileLastMod = 0;
  -    private int serviceCount = 0;
  +    protected Context context;
  +
  +    // servletName is stored in config!
  +    protected String servletClassName; // required
  +    protected ServletConfigImpl config;
  +    protected Servlet servlet;
  +    protected Class servletClass;
  +    
  +    // optional informations
  +    protected String description = null;
   
  +    // Usefull info for class reloading
  +    protected boolean isReloadable = false;
  +    // information + make sure destroy is called when no other servlet
  +    // is running ( this have to be revisited !) 
  +    protected long lastAccessed;
  +    protected int serviceCount = 0;
  +
       ServletWrapper(Context context) {
           this.context = context;
           config = new ServletConfigImpl(context);
       }
   
  +    protected Context getContext() {
  +	return context;
  +    }
  +
       void setReloadable(boolean reloadable) {
   	isReloadable = reloadable;
       }
  @@ -125,168 +133,63 @@
           this.description = description;
       }
   
  -    public String getPath() {
  -        return this.path;
  -    }
  -
  -    public void setPath(String path) {
  -        this.path = path;
  -    }
  -
  -    void setServletClassFile(File servletClassFile) {
  -	this.servletClassFile = servletClassFile;
  -	classFileLastMod = servletClassFile.lastModified();
  -
  -	config.setServletClassName(this.servletClassFile.getName());
  -    }
  -
       public String getServletClass() {
           return this.servletClassName;
       }
   
       public void setServletClass(String servletClassName) {
           this.servletClassName = servletClassName;
  -
   	config.setServletClassName(servletClassName);
       }
   
  -    void setServletClass(Class servletClass) {
  -	this.servletClass = servletClass;
  -
  -	config.setServletClassName(this.servletClass.getName());
  -    }
  -
       void setInitArgs(Hashtable initArgs) {
           config.setInitArgs(initArgs);
       }
   
       void destroy() {
  -	// Fancy sync logic is to make sure that no threads are in the
  -	// handlerequest when this is called and, furthermore, that
  -	// no threads go through handle request after this method starts!
  -	
   	if (servlet != null) {
   	    synchronized (this) {
  -		// Wait until there are no outstanding service calls,
  -		// or until 30 seconds have passed (to avoid a hang)
  -
  -		while (serviceCount > 0) {
  -		    try {
  -		        wait(30000);
  -
  -			break;
  -		    } catch (InterruptedException e) { }
  -		}
  -		
  +		waitForDestroy();
   		try {
   		    handleDestroy( context, servlet );
   		} catch(IOException ioe) {
  +		    ioe.printStackTrace();
   		    // Should never come here...
   		} catch(ServletException se) {
  +		    se.printStackTrace();
   		    // Should never come here...
   		}
   	    }
   	}
       }
   
  -    private void loadJsp( String path )
  -    	throws ClassNotFoundException, InstantiationException,
  -	IllegalAccessException, ServletException
  -    {
  -	// XXX XXX XXX
  -	// core shouldn't depend on a particular connector!
  -	// need to find out what this code does!
  -	
  -	// XXX XXX find a better way !!!
  -	RequestAdapterImpl reqA=new RequestAdapterImpl();
  -	ResponseAdapterImpl resA=new ResponseAdapterImpl();
  -	
  -	RequestImpl request = new RequestImpl();
  -	ResponseImpl response = new ResponseImpl();
  -	request.recycle();
  -	response.recycle();
  -	
  -	request.setRequestAdapter( reqA );
  -	response.setResponseAdapter( resA );
  -	
  -	request.setResponse(response);
  -	response.setRequest(request);
  -	
  -	String requestURI = path + "?" +
  -	    Constants.JSP.Directive.Compile.Name + "=" +
  -	    Constants.JSP.Directive.Compile.Value;
  -	
  -	reqA.setRequestURI(context.getPath() + path);
  -	reqA.setQueryString( Constants.JSP.Directive.Compile.Name + "=" +
  -			     Constants.JSP.Directive.Compile.Value );
  -	
  -	request.setContext(context);
  -	request.updatePaths();
  -	request.getSession(true);
  -	
  -	RequestDispatcher rd =
  -	    config.getServletContext().getRequestDispatcher(requestURI);
  -	
  -	try {
  -	    rd.forward(request.getFacade(), response.getFacade());
  -	} catch (ServletException se) {
  -	} catch (IOException ioe) {
  -	}
  -    } 
  -    
  +    /** Load and init a the servlet pointed by this wrapper
  +     */
       public void loadServlet()
   	throws ClassNotFoundException, InstantiationException,
   	IllegalAccessException, ServletException
       {
  -        // Check if this is a JSP, they get special treatment
  -
  -        if (path != null &&
  -            servletClass == null &&
  -            servletClassName == null) {
  -	    loadJsp( path );
  -	}  else {
  -	    if (servletClass == null) {
  -	        if (servletClassName == null) {
  -		    String msg = sm.getString("wrapper.load.noclassname");
  -
  -		    throw new IllegalStateException(msg);
  -	        }
  -
  -	        servletClass = context.getLoader().loadServlet(this,
  -                    servletClassName);
  -	    }
  -
  -            // make sure we have a classname or class def
  -            //if (servletClassName == null || servletClass == null) {
  -            //    String msg = sm.getString("wrapper.load.noclassname");
  -            //    throw new IllegalStateException(msg);
  -	    // }
  -	    //Class c = context.getLoader().loadServlet(this,
  -	    //servletClassName);
  -
  -	    servlet = (Servlet)servletClass.newInstance();
  +	if (servletClass == null) {
  +	    if (servletClassName == null) 
  +		throw new IllegalStateException(sm.getString("wrapper.load.noclassname"));
   
  -	    config.setServletClassName(servlet.getClass().getName());
  +	    servletClass = context.getLoader().loadServlet(this,
  +							   servletClassName);
  +	}
  +	
  +	servlet = (Servlet)servletClass.newInstance();
   
  -	    try {
  -	        final Servlet sinstance = servlet;
  -	        final ServletConfigImpl servletConfig = config;
  +	config.setServletClassName(servlet.getClass().getName());
   
  -	        handleInit(context, servlet, servletConfig);
  -	    } catch(IOException ioe) {
  +	try {
  +	    final Servlet sinstance = servlet;
  +	    final ServletConfigImpl servletConfig = config;
  +	    
  +	    handleInit(context, servlet, servletConfig);
  +	} catch(IOException ioe) {
  +	    ioe.printStackTrace();
   	    // Should never come here...
  -	    }
  -        }
  -    }
  -
  -    private Context getContext() {
  -	return context;
  -    }
  -
  -    private boolean isJsp() {
  -	return path != null &&
  -	    servletClass == null &&
  -	    servletClassName == null;
  +	}
       }
   
       public void handleRequest(final HttpServletRequestFacade request,
  @@ -294,115 +197,44 @@
   	throws IOException
       {
           synchronized (this) {
  -	    if ( isJsp() ) {
  -		System.out.println("XXX XXX XXX " +path );
  -                String requestURI = path + request.getPathInfo();
  -	        RequestDispatcher rd = request.getRequestDispatcher(requestURI);
  -		
  +	    if (servlet == null) {
   		try {
  -		    // Watch out, ugly code ahead...
  -		    // We need to do a forward or include here, but we can't
  -		    // easily determine which.  So we try a forward, and if
  -		    // there's an IllegalStateException thrown, then we know
  -		    // we should have tried an include, so we do the include.
  -		    // It's so ugly I have to giggle.
  -		    // All this to support dispatching to named JSPs!
  -		    if (! response.getRealResponse().isStarted())
  -		        rd.forward(request, response);
  -		    else
  -			rd.include(request, response);
  -
  -		} catch (ServletException se) {
  -		    se.printStackTrace();
  -		    response.sendError(404);
  -		} catch (IOException ioe) {
  -		    ioe.printStackTrace();
  -		    response.sendError(404);
  -		}
  -		
  -		return;
  -	    } else {
  -	        if (servlet == null) {
  -		    try {
  -		        loadServlet();
  -		    } catch (ClassNotFoundException e) {
  -		        response.sendError(404, "Class not found " + servletClassName);
  -
  -			return;
  -		    } catch (Exception e) {
  -		        // Make sure the servlet will never
  -		        // service a request
  -
  -		        servlet = null;
  -		    
  -			// XXX
  -			// check to see what kind of exception it was --
  -			// maybe it should be reported to the user
  -			// differently or at least logged differently
  -		    
  -			// XXX
  -			// we really need to pick up an error file on
  -			// a per context basis or, failing that from the
  -			// classpath
  -		    
  -			sendInternalServletError(e, response);
  -
  -			return;
  -		    }
  +		    loadServlet();
  +		} catch (ClassNotFoundException e) {
  +		    response.sendError(404, "Class not found " + servletClassName);
  +		    return;
  +		} catch (Exception e) {
  +		    // Make sure the servlet will never
  +		    // service a request
  +		    servlet = null;
  +		    sendInternalServletError(e, request, response);
  +		    return;
   		}
   	    }
   	}
   
           try {
   	    synchronized(this) {
  +		// logic for un-loading
   		serviceCount++;
   	    }
  -
  +	    
   	    Context context = getContext();
   
   	    handleInvocation( context, servlet, request, response );
  -	} catch (ServletException e) {
  -            // XXX
  -	    // check to see if it's unavailable and set internal status
  -	    // appropriately
   
  +	} catch (ServletException e) {
   	    // XXX
   	    // if it's an unvailable exception, we probably want
   	    // to paint a different screen
  -
               handleException(request, response, e);
  -
  -	    return;
           } catch (SocketException e) {
  -	    // XXX
  -	    // Catch and eat all SocketExceptions
  -	    // *Should* only eat client disconnected socket exceptions
  -
  -	    return;
  +	    // replace with Log:
  +	    System.out.println("Socket Exception : " + e.getMessage());
           } catch (Throwable e) {
  -	    // if we are in an include, then we should rethrow the
  -	    // exception
  -
   	    // XXX
  -	    // we need a better way of dealing with figuring out
  -	    // if we are in an include -- this particular gem
  -	    // will pass IllegalStateException when we are in
  -	    // an include 'cause users will like to know when
  -	    // that happens in their included servlet
  -	    
  -	    //if (e instanceof IllegalStateException) {
  -	    //    String str = (String)request.getAttribute
  -	    //    (Constants.Attribute.RequestURI);
  -	    //    if (str != null) {
  -	    //        throw (IllegalStateException)e;
  -	    //    }
  -	    //}
  -	    
  -	    // XXX
   	    // decide which exceptions we should not eat at this point
               handleException(request, response, e);
  -
  -	    return;
   	} finally {
   	    synchronized(this) {
   		serviceCount--;
  @@ -412,8 +244,9 @@
       }
   
       public void handleException(HttpServletRequestFacade request,
  -        HttpServletResponseFacade response,
  -    Throwable t) {
  +				HttpServletResponseFacade response,
  +				Throwable t)
  +    {
           Context context = request.getRealRequest().getContext();
           ServletContextFacade contextFacade = context.getFacade();
   
  @@ -428,7 +261,7 @@
               path = context.getErrorPage(name);
               clazz = clazz.getSuperclass();
           }
  -
  +	
           // If path is non-null, we should do a forward
           // Don't do a forward if exception_type is already defined though to
           // avoid an infinite loop.
  @@ -448,70 +281,55 @@
                   t.getMessage());
   
               try {
  -                try {
  -                    // A forward would be ideal, so reset and try it
  +		// A forward would be ideal, so reset and try it
   
  -                    response.getRealResponse().reset();
  -                    rd.forward(request, response);
  -                } catch (IllegalStateException ise) {
  -                    // Oops, too late for a forward; settle for an include
  +		response.getRealResponse().reset();
   
  -                    rd.include(request, response);
  -                }
  +		if (response.getRealResponse().isStarted()) 
  +		    rd.include(request, response);
  +		else
  +		    rd.forward(request, response);
               } catch (IOException e) {
  +		e.printStackTrace();
                   // Shouldn't get here
               } catch (ServletException e) {
  +		e.printStackTrace();
                   // Shouldn't get here
               }
           } else {
               try {
  -                sendInternalServletError(t, response);
  -            } catch (IOException e) {
  -                // ???
  +		sendInternalServletError( t, request, response);
  +	    } catch (IOException e) {
  +                e.printStackTrace();
  +		// ???
               }
           }
       }
  -
  -    void sendInternalServletError(Throwable e,
  -        HttpServletResponseFacade response)
  -    throws IOException {
  -	StringWriter sw = new StringWriter();
  -	PrintWriter pw = new PrintWriter(sw);
  -
  -	pw.println("<b>Internal Servlet Error:</b><br>");
  -        pw.println("<pre>");
  -	e.printStackTrace(pw);
  -	pw.println("</pre>");
   
  -        if (e instanceof ServletException) {
  -	    printRootCause((ServletException) e, pw);
  -	}
  -
  -	response.sendError(500, sw.toString());
  -    }
  -
  -    void printRootCause(ServletException e, PrintWriter out) {
  -        Throwable cause = e.getRootCause();
  -
  -	if (cause != null) {
  -	    out.println("<b>Root cause:</b>");
  -	    out.println("<pre>");
  -	    cause.printStackTrace(out);
  -	    out.println("</pre>");
  +    void sendInternalServletError( Throwable t, HttpServletRequestFacade request,
  +				   HttpServletResponseFacade response )
  +	throws IOException
  +    {
  +	// Used to communicate with Default Error Page
  +		request.setAttribute("tomcat.error.throwable", t);
  +		// XXX need to make this configurable, any servlet
  +		// can act as the default error handler
   
  -	    if (cause instanceof ServletException) {
  -		printRootCause((ServletException)cause, out);  // recurse
  -	    }
  -	}
  +		// Need to do a normal servlet invocation!
  +		try {
  +		    Servlet errorP=new org.apache.tomcat.servlets.DefaultErrorPage();
  +		    errorP.service(request,response);
  +		} catch(Exception ex) {
  +		    System.out.println("FATAL: error in error handler");
  +		    ex.printStackTrace();
  +		}
       }
  -
  +    
       /** Call the init method and all init interceptors
        */
  -    private void handleInit(Context context, Servlet servlet, ServletConfig servletConfig )
  +    protected void handleInit(Context context, Servlet servlet, ServletConfig servletConfig )
   	throws ServletException, IOException
       {
  -	Stack iStack = new Stack();
  -
   	Vector v=context.getInitInterceptors();
   	for( int i=0; i<v.size(); i++ ) {
   	    try { 
  @@ -536,7 +354,7 @@
       /** Call destroy(), with all interceptors before and after in the
   	right order;
       */
  -    private void handleDestroy(Context context, Servlet servlet )
  +    protected void handleDestroy(Context context, Servlet servlet )
   	throws ServletException, IOException
       {
   	Vector v=context.getDestroyInterceptors();
  @@ -564,7 +382,7 @@
       /** Call service(), with all interceptors before and after in the
   	right order;
       */
  -    private void handleInvocation(Context ctx, Servlet servlet,
  +    protected void handleInvocation(Context ctx, Servlet servlet,
   				  HttpServletRequestFacade request, HttpServletResponseFacade response )
   	throws ServletException, IOException
       {
  @@ -594,4 +412,23 @@
   	    }
   	}
       }
  +
  +    // Fancy sync logic is to make sure that no threads are in the
  +    // handlerequest when this is called and, furthermore, that
  +    // no threads go through handle request after this method starts!
  +    protected void waitForDestroy() {
  +	// Wait until there are no outstanding service calls,
  +	// or until 30 seconds have passed (to avoid a hang)
  +	
  +	// XXX wrong logic !
  +	while (serviceCount > 0) {
  +	    try {
  +		wait(30000);
  +		
  +		break;
  +	    } catch (InterruptedException e) { }
  +	}
  +    }
  +    
  +
   }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/core/JspWrapper.java
  
  Index: JspWrapper.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/JspWrapper.java,v 1.1 2000/01/14 04:08:10 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2000/01/14 04:08:10 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  
  package org.apache.tomcat.core;
  
  import org.apache.tomcat.util.*;
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  /* It is used:
     - Context addJsp/removeJsp - to "name" jsps for use in web.xml
     - Context.loadOnStartup 
     - MapperInterceptor - to map between "declared" jsps that are used in mappings
  
     It is a very strange class - we need to revisit the way we implement
     the "mapping to jsp" - for now it's just out in a separate class to not
     affect the rest of the code.
  */
  
  
  /**
   * Specialized wrapper for Jsp - used only by Context when a Jsp is declared
   * in web.xml
   * The only use of this class is in load on Startup, and to keep the extra path info.
   * 
   * @author James Duncan Davidson [duncan@eng.sun.com]
   * @author Jason Hunter [jch@eng.sun.com]
   * @author James Todd [gonzo@eng.sun.com]
   * @author Harish Prabandham
   * @author costin@dnt.ro
   */
  public class JspWrapper extends ServletWrapper {
  
      private String path = null;
  
      JspWrapper(Context context) {
          super(context);
      }
  
      public String getPath() {
          return this.path;
      }
  
      public void setPath(String path) {
          this.path = path;
      }
  
      
      public void loadServlet()
  	throws ClassNotFoundException, InstantiationException,
  	IllegalAccessException, ServletException
      {
          // Check if this is a declared JSP, they get special treatment
  	if( servletClass!=null || servletClassName !=null)
  	    super.loadServlet();
  
  	// A Jsp initialized in web.xml -
  
  	// Log ( since I never saw this code called, let me know if it does
  	// for you )
  	System.out.println("Initializing JSP with JspWrapper");
  	
  	// Ugly code to trick JSPServlet into loading this.
  
  	// XXX XXX XXX
  	// core shouldn't depend on a particular connector!
  	// need to find out what this code does!
  	
  	// XXX XXX find a better way !!!
  	RequestAdapterImpl reqA=new RequestAdapterImpl();
  	ResponseAdapterImpl resA=new ResponseAdapterImpl();
  	
  	RequestImpl request = new RequestImpl();
  	ResponseImpl response = new ResponseImpl();
  	request.recycle();
  	response.recycle();
  	
  	request.setRequestAdapter( reqA );
  	response.setResponseAdapter( resA );
  	
  	request.setResponse(response);
  	response.setRequest(request);
  	
  	String requestURI = path + "?" +
  	    Constants.JSP.Directive.Compile.Name + "=" +
  	    Constants.JSP.Directive.Compile.Value;
  	
  	reqA.setRequestURI(context.getPath() + path);
  	reqA.setQueryString( Constants.JSP.Directive.Compile.Name + "=" +
  			     Constants.JSP.Directive.Compile.Value );
  	
  	request.setContext(context);
  	request.updatePaths();
  	request.getSession(true);
  	
  	RequestDispatcher rd =
  	    config.getServletContext().getRequestDispatcher(requestURI);
  	
  	try {
  	    rd.forward(request.getFacade(), response.getFacade());
  	} catch (ServletException se) {
  	} catch (IOException ioe) {
  	}
      }
  
      public void handleRequest(final HttpServletRequestFacade request,
  			      final HttpServletResponseFacade response)
  	throws IOException
      {
          synchronized (this) {
  	    // Check if this is a JSP, they get special treatment
  	    if( servletClass!=null || servletClassName !=null)
  		super.handleRequest(request, response);
  
  	    // "Special" JSP
  	    String requestURI = path + request.getPathInfo();
  	    RequestDispatcher rd = request.getRequestDispatcher(requestURI);
  	    
  	    try {
  		// Watch out, ugly code ahead...
  		// We need to do a forward or include here, but we can't
  		// easily determine which.  So we try a forward, and if
  		// there's an IllegalStateException thrown, then we know
  		// we should have tried an include, so we do the include.
  		// It's so ugly I have to giggle.
  		// All this to support dispatching to named JSPs!
  		if (! response.getRealResponse().isStarted())
  		    rd.forward(request, response);
  		else
  		    rd.include(request, response);
  		
  	    } catch (ServletException se) {
  		se.printStackTrace();
  		response.sendError(404);
  	    } catch (IOException ioe) {
  		ioe.printStackTrace();
  		response.sendError(404);
  	    }
  	    
  	    return;
  	    // I have no ideea how it works - but the code should be
  	    // equivalent with the original in ServletWrapper.
  	}
      }
  }
  
  
  
  1.6       +3 -3      jakarta-tomcat/src/share/org/apache/tomcat/request/MapperInterceptor.java
  
  Index: MapperInterceptor.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/MapperInterceptor.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- MapperInterceptor.java	2000/01/11 02:06:55	1.5
  +++ MapperInterceptor.java	2000/01/14 04:08:11	1.6
  @@ -252,11 +252,11 @@
   
               while (stillSearching) {
                   if (wrapper != null &&
  -                    wrapper.getPath() != null &&
  +                    wrapper instanceof JspWrapper  &&
                       wrapper.getServletClass() == null) {
  -                        req.setResourceName( wrapper.getPath() );
  +                        req.setResourceName( ((JspWrapper)wrapper).getPath() );
                           wrapper = getMatch(context,
  -					   wrapper.getPath() + (pathInfo == null ? "" : pathInfo),
  +					   ((JspWrapper)wrapper).getPath() + (pathInfo == null ? "" : pathInfo),
   					   req);
                           req.setMappedPath(  req.getServletPath() );
   
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/servlets/DefaultErrorPage.java
  
  Index: DefaultErrorPage.java
  ===================================================================
  /*
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  package org.apache.tomcat.servlets;
  
  import org.apache.tomcat.util.*;
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  /*
    Right now it is not well-integrated, and it's not configurable.
    If someone needs to customize this it should be easy to
    take the steps to do Class.forName() and all rest.
  
    This code was originally hardcoded in ServletWrapper ( where
    service() is called.
   */
  
  /**
   *  Report an error - if no other error page was set up or
   *  if an error happens in an error page.
   */
  public class DefaultErrorPage extends HttpServlet {
  
      public void service(HttpServletRequest request,
  			HttpServletResponse response)
  	throws ServletException, IOException
      {
  	StringWriter sw = new StringWriter();
  	PrintWriter pw = new PrintWriter(sw);
  
  	Throwable e= (Throwable)request.getAttribute("tomcat.error.throwable");
  	
  	pw.println("<b>Internal Servlet Error:</b><br>");
          pw.println("<pre>");
  	if( e != null ) 
  	    e.printStackTrace(pw);
  	pw.println("</pre>");
  
          if (e instanceof ServletException) {
  	    printRootCause((ServletException) e, pw);
  	}
  	
  	response.sendError(500, sw.toString());
      }
  
      /** A bit of recursion - print all traces in the stack
       */
      void printRootCause(ServletException e, PrintWriter out) {
          Throwable cause = e.getRootCause();
  
  	if (cause != null) {
  	    out.println("<b>Root cause:</b>");
  	    out.println("<pre>");
  	    cause.printStackTrace(out);
  	    out.println("</pre>");
  
  	    if (cause instanceof ServletException) {
  		printRootCause((ServletException)cause, out);  // recurse
  	    }
  	}
      }
  }