You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by la...@apache.org on 2001/06/11 05:42:31 UTC

cvs commit: jakarta-tomcat/src/share/org/apache/jasper/servlet JspServlet.java

larryi      01/06/10 20:42:31

  Modified:    src/share/org/apache/jasper/compiler Compiler.java
                        PluginGenerator.java
               src/share/org/apache/jasper/resources messages.properties
               src/share/org/apache/jasper/runtime BodyContentImpl.java
               src/share/org/apache/jasper/servlet JspServlet.java
  Log:
  Port updates to Jasper from tomcat_32 branch to main branch
  
  Revision  Changes    Path
  1.24      +4 -4      jakarta-tomcat/src/share/org/apache/jasper/compiler/Compiler.java
  
  Index: Compiler.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/jasper/compiler/Compiler.java,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- Compiler.java	2001/03/02 04:51:30	1.23
  +++ Compiler.java	2001/06/11 03:42:27	1.24
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/jasper/compiler/Compiler.java,v 1.23 2001/03/02 04:51:30 costin Exp $
  - * $Revision: 1.23 $
  - * $Date: 2001/03/02 04:51:30 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/jasper/compiler/Compiler.java,v 1.24 2001/06/11 03:42:27 larryi Exp $
  + * $Revision: 1.24 $
  + * $Date: 2001/06/11 03:42:27 $
    *
    * ====================================================================
    * 
  @@ -143,7 +143,7 @@
           //  - compiling the generated servlets (pass -encoding to javac).
           // XXX - There are really three encodings of interest.
   
  -        String jspEncoding = "8859_1";          // default per JSP spec
  +        String jspEncoding = "ISO-8859-1";          // default per JSP spec
   
   	// We try UTF8 by default. If it fails, we use the java encoding 
   	// specified for JspServlet init parameter "javaEncoding".
  
  
  
  1.11      +9 -4      jakarta-tomcat/src/share/org/apache/jasper/compiler/PluginGenerator.java
  
  Index: PluginGenerator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/jasper/compiler/PluginGenerator.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- PluginGenerator.java	2001/03/10 01:18:01	1.10
  +++ PluginGenerator.java	2001/06/11 03:42:28	1.11
  @@ -1,4 +1,8 @@
   /*
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/jasper/compiler/PluginGenerator.java,v 1.11 2001/06/11 03:42:28 larryi Exp $
  + * $Revision: 1.11 $
  + * $Date: 2001/06/11 03:42:28 $
  + *
    * ====================================================================
    * 
    * The Apache Software License, Version 1.1
  @@ -270,11 +274,11 @@
   	writer.indent ();
   	writer.print ("out.print (\"<EMBED type=\\\"");
   	if (type.equals ("applet")) 
  -	    writer.print ("application/x-java-applet;");
  +	    writer.print ("application/x-java-applet");
   	else if (type.equals ("bean"))
  -	    writer.print ("application/x-java-bean;");
  +	    writer.print ("application/x-java-bean");
   	if (jreversion != null) {
  -	    writer.print ("version=");
  +	    writer.print (";version=");
   	    writer.print (jreversion);
   	}
   	writer.print ("\\\" ");
  @@ -317,8 +321,9 @@
   	writer.indent ();
   	writer.print ("out.println (");
   	writer.print (" _jspxNSString [i][0] + ");
  -	writer.print ("\"=\"");
  +	writer.print ("\"=\\\"\"");
   	writer.print (" + _jspxNSString[i][1]");
  +	writer.print (" + \"\\\"\"");
   	writer.print (");");
   	writer.println ();
   	writer.popIndent ();
  
  
  
  1.25      +2 -1      jakarta-tomcat/src/share/org/apache/jasper/resources/messages.properties
  
  Index: messages.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/jasper/resources/messages.properties,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- messages.properties	2001/01/14 20:45:40	1.24
  +++ messages.properties	2001/06/11 03:42:29	1.25
  @@ -1,4 +1,4 @@
  -# $Id: messages.properties,v 1.24 2001/01/14 20:45:40 larryi Exp $
  +# $Id: messages.properties,v 1.25 2001/06/11 03:42:29 larryi Exp $
   #
   # Default localized string information
   # Localized this the Default Locale as is en_US
  @@ -214,3 +214,4 @@
   jsp.error.unterminated.user.tag=Unterminated user-defined tag: ending tag {0} not found or incorrectly nested 
   jsp.error.invalid.javaEncoding=Invalid java encodings. Tried {0} and then {1}. Both failed.
   jsp.error.needAlternateJavaEncoding=Default java encoding {0} is invalid on your java platform. An alternate can be specified via the 'javaEncoding' parameter of JspServlet.
  +jsp.error.badcount=Internal error.  Attempted to decrement the reference count for an unreferenced JSP.
  
  
  
  1.11      +6 -9      jakarta-tomcat/src/share/org/apache/jasper/runtime/BodyContentImpl.java
  
  Index: BodyContentImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/jasper/runtime/BodyContentImpl.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- BodyContentImpl.java	2001/03/23 02:21:20	1.10
  +++ BodyContentImpl.java	2001/06/11 03:42:29	1.11
  @@ -112,15 +112,12 @@
   
           char[] tmp = null;
   
  -	//XXX Should it be multiple of DEFAULT_BUFFER_SIZE??
  -
  -	if (len <= Constants.DEFAULT_BUFFER_SIZE) {
  -	    bufferSize = bufferSize * 2;
  -	    tmp = new char [bufferSize];
  -	} else {
  -	    bufferSize += len;
  -	    tmp = new char [bufferSize];
  -	}
  +        if(len <= bufferSize){ 
  +            bufferSize *= 2; 
  +        }else{ 
  +            bufferSize += len; 
  +        } 
  +        tmp = new char[bufferSize]; 
   	System.arraycopy(cb, 0, tmp, 0, cb.length);
   	cb = tmp;
   	tmp = null;
  
  
  
  1.9       +238 -90   jakarta-tomcat/src/share/org/apache/jasper/servlet/JspServlet.java
  
  Index: JspServlet.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/jasper/servlet/JspServlet.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- JspServlet.java	2001/02/22 20:32:00	1.8
  +++ JspServlet.java	2001/06/11 03:42:30	1.9
  @@ -91,16 +91,99 @@
    *
    * @author Anil K. Vijendran
    * @author Harish Prabandham
  + * @author Marc A. Saegesser
    */
   public class JspServlet extends HttpServlet {
   
       Log loghelper = Log.getLog("JASPER_LOG", "JspServlet");
   
  +    /**
  +     * Adds reference counting to the JSP implementation servlet.  This
  +     * is required to handle the case where a JSP implementation servlet
  +     * is executing requests on several threads when a new implementation
  +     * arrives (the JSP source was updated).  We need to wait until all
  +     * the requests complete before calling the implementation servlet's
  +     * destroy() method.
  +     */
  +    class JspCountedServlet extends HttpServlet
  +    {
  +        private Servlet servlet = null;
  +        private int threadCount = 0;
  +        private boolean destroyed = false;
  +
  +        public JspCountedServlet(Servlet servlet)
  +        {
  +            this.servlet = servlet;
  +        }
  +
  +        public void init(ServletConfig config) throws ServletException, JasperException
  +        {
  +            try{
  +                servlet.init(config);
  +            }catch(NullPointerException e){
  +                throw new JasperException(e);
  +            }
  +        }
  +
  +        public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException, JasperException
  +        {
  +            try{
  +                incrementCount();
  +                servlet.service(req, res);
  +            }catch(NullPointerException e){
  +                throw new JasperException(e);
  +            }finally{
  +                decrementCount();
  +            }
  +        }
  +
  +        /*
  +         * Flags this servlet for destrction once all active requests have completed.
  +         * After calling this method it is invalid to call service().
  +         */
  +        public void destroy()
  +        {
  +            destroyed = true;
  +            if(getCount() == 0)
  +                doDestroy();
  +        }
  +
  +        private void doDestroy()
  +        {
  +            try{
  +                servlet.destroy();
  +                servlet = null;
  +            }catch(NullPointerException e){
  +            }
  +        }
  +
  +        private synchronized void incrementCount()
  +        {
  +            threadCount++;
  +        }
  +
  +        private synchronized void decrementCount()
  +        {
  +            if(threadCount <= 0){
  +                Constants.message("jsp.error.badcount", Log.ERROR);
  +                return;
  +            }
  +
  +            --threadCount;
  +            if(threadCount == 0 && destroyed)
  +                doDestroy();
  +        }
  +
  +        private synchronized int getCount()
  +        {
  +            return threadCount;
  +        }
  +    }
  +
       class JspServletWrapper {
  -        Servlet theServlet;
  +        JspCountedServlet theServlet;
   	String jspUri;
   	boolean isErrorPage;
  -	// ServletWrapper will set this 
   	Class servletClass;
   	
   	JspServletWrapper(String jspUri, boolean isErrorPage) {
  @@ -109,23 +192,46 @@
   	    this.theServlet = null;
   	}
   	
  -	private void load() throws JasperException, ServletException {
  -	    try {
  -		// Class servletClass = (Class) loadedJSPs.get(jspUri);
  -		// This is to maintain the original protocol.
  -		destroy();
  -
  -		theServlet = (Servlet) servletClass.newInstance();
  -	    } catch (Exception ex) {
  -		throw new JasperException(ex);
  -	    }
  -	    theServlet.init(JspServlet.this.config);
  -	    if (theServlet instanceof HttpJspBase)  {
  -                HttpJspBase h = (HttpJspBase) theServlet;
  -                h.setClassLoader(JspServlet.this.parentClassLoader);
  -	    }
  -	}
  -	
  +        public synchronized void instantiateServlet(Class servletClass) throws JasperException, ServletException
  +        {
  +            try {
  +                this.servletClass = servletClass;
  +
  +                // If we're replacing an existing JSP Implementation class, then
  +                // schedule it for destruction
  +                if(theServlet != null)
  +                    theServlet.destroy();
  +
  +                // Create an instance of the JSP implementation class
  +                Servlet servlet = (Servlet) servletClass.newInstance();
  +                // Set the class loader
  +                if(servlet instanceof HttpJspBase) {
  +                    ((HttpJspBase)servlet).setClassLoader(JspServlet.this.parentClassLoader);
  +                }
  +
  +                // Wrap this servlet in a counted servlet
  +                theServlet = new JspCountedServlet(servlet);
  +
  +                // Call the JSP Implementation servlet's init() method.  This
  +                // will cause the page's jspInit() method to be invoked if one exists.
  +                theServlet.init(JspServlet.this.config);
  +
  +            } catch(Exception ex) {
  +                throw new JasperException(ex);
  +            }
  +
  +        }
  +
  +        public synchronized Servlet getServlet()
  +        {
  +            return theServlet;
  +        }
  +
  +        public synchronized boolean isInstantiated()
  +        {
  +            return theServlet != null;
  +        }
  +
   	private void loadIfNecessary(HttpServletRequest req, HttpServletResponse res) 
               throws JasperException, ServletException, FileNotFoundException 
           {
  @@ -151,10 +257,7 @@
                                 }, 
                                 Log.INFORMATION);
   
  -            if (loadJSP(jspUri, cp, isErrorPage, req, res) 
  -                    || theServlet == null) {
  -                load();
  -            }
  +            loadJSP(jspUri, cp, isErrorPage, req, res);
   	}
   	
   	public void service(HttpServletRequest request, 
  @@ -162,21 +265,23 @@
   			    boolean precompile)
   	    throws ServletException, IOException, FileNotFoundException 
   	{
  +            Servlet servlet = null;
               try {
                   loadIfNecessary(request, response);
  +                servlet = getServlet();
   
   		// If a page is to only to be precompiled return.
   		if (precompile)
   		    return;
   
  -		if (theServlet instanceof SingleThreadModel) {
  +		if (servlet instanceof SingleThreadModel) {
   		    // sync on the wrapper so that the freshness
   		    // of the page is determined right before servicing
   		    synchronized (this) {
  -			theServlet.service(request, response);
  +			servlet.service(request, response);
   		    }
   		} else {
  -		    theServlet.service(request, response);
  +		    servlet.service(request, response);
   		}
   
               } catch (FileNotFoundException ex) {
  @@ -218,10 +323,11 @@
               }
   	}
   
  -	public void destroy() {
  -	    if (theServlet != null)
  -		theServlet.destroy();
  -	}
  +        public void destroy()
  +        {
  +            if(theServlet != null)
  +                theServlet.destroy();
  +        }
       }
   	
   	
  @@ -275,7 +381,6 @@
                                     "<none>"
                                 }, Log.DEBUG);
   	}
  -	//	System.out.println("JspServlet: init " + config.getServletName() );
   	if( loader==null ) {
   	    if( jdk12 ) {
   		try {
  @@ -310,12 +415,19 @@
   	throws ServletException, IOException
       {
   	boolean isErrorPage = exception != null;
  -	
  -	JspServletWrapper wrapper = (JspServletWrapper) jsps.get(jspUri);
  -	if (wrapper == null) {
  -	    wrapper = new JspServletWrapper(jspUri, isErrorPage);
  -	    jsps.put(jspUri, wrapper);
  -	}
  +        JspServletWrapper wrapper = null;
  +
  +        /*
  +         * Several threads may be handling requests for the same jspUri.
  +         * Only one of them is allowed to create the JspServletWrapper.
  +         */
  +        synchronized(jsps){
  +            wrapper = (JspServletWrapper) jsps.get(jspUri);
  +            if (wrapper == null) {
  +                wrapper = new JspServletWrapper(jspUri, isErrorPage);
  +                jsps.put(jspUri, wrapper);
  +            }
  +        }
   	
   	wrapper.service(request, response, precompile);
       }
  @@ -325,8 +437,13 @@
           throws ServletException 
       {
           boolean precompile = false;
  -        String precom = request.getParameter(Constants.PRECOMPILE);
  +        String precom = null;
           String qString = request.getQueryString();
  +        // Avoid calling getParameter() unless precompile string is found
  +        // in query string.  Allows post data to remain unread per the
  +        // servlet spec if the precompile string is not found.
  +        if (qString != null && qString.indexOf(Constants.PRECOMPILE) >= 0)
  +            precom = request.getParameter(Constants.PRECOMPILE);
           
           if (precom != null) {
               if (precom.equals("true")) 
  @@ -337,9 +454,8 @@
   		    // This is illegal.
   		    throw new ServletException("Can't have request parameter " +
   					       Constants.PRECOMPILE + " set to " + precom);
  -		}
  -	    }
  -        else if (qString != null && (qString.startsWith(Constants.PRECOMPILE) ||
  +            }
  +        } else if (qString != null && (qString.startsWith(Constants.PRECOMPILE) ||
                                        qString.indexOf("&" + Constants.PRECOMPILE)
                                        != -1))
               precompile = true;
  @@ -384,11 +500,15 @@
   		    jasperLog.log("\t      RequestURI: "+request.getRequestURI());
   		    jasperLog.log("\t     QueryString: "+request.getQueryString());
   		    jasperLog.log("\t  Request Params: ");
  -		    Enumeration e = request.getParameterNames();
  -		    while (e.hasMoreElements()) {
  -			String name = (String) e.nextElement();
  -			jasperLog.log("\t\t "+name+" = "+request.getParameter(name));
  -		    }
  +                    if ( request.getMethod().equals("POST") )
  +                        jasperLog.log("Parameters not read because method is POST");
  +                    else {
  +                        Enumeration e = request.getParameterNames();
  +                        while (e.hasMoreElements()) {
  +                            String name = (String) e.nextElement();
  +                            jasperLog.log("\t\t "+name+" = "+request.getParameter(name));
  +                        }
  +                    }
   		}
               serviceJspFile(request, response, jspUri, null, precompile);
   	} catch (RuntimeException e) {
  @@ -442,61 +562,89 @@
        *  @param classpath explicitly set the JSP compilation path.
        *  @return true if JSP files is newer
        */
  +
  +    /*
  +     * A word about the thread synchronization below.  The call to 
  +     * compiler.isOutDated() is outside the synchronization block on purpose.  
  +     * The expectation is that for the vast majority of cases the JSP source file 
  +     * will not have changed and there will be no need to recompile the 
  +     * implementation class.  For those cases when a compile is required, we 
  +     * enter a block that is synchronized on the JspServletWrapper object for 
  +     * this JSP page.  Because the initial out dated check is unsynchronized, it 
  +     * is possible for more than one request to attempt to enter the synchronized 
  +     * compile block.  The compile() method contains performs an outdated check 
  +     * of its own.  The first thread into the block will cause a compile, the 
  +     * subsequent threads will essentially skip the compilation and instantiation 
  +     * steps.  
  +     * 
  +     * One other thing to note is that there is a window of time between the 
  +     * compiler.compile() call and the end of the synchronized block where a new 
  +     * thread entering doLoadJSP() will be told that that implementation class is 
  +     * up to date even though the code in the synchronized block has not 
  +     * completed loading and instantiating the class.  In this case doLoadJSP() 
  +     * will return false without attempting to compile the class.  This is OK 
  +     * because the JspServletWrapper.getServlet() method used by the 
  +     * JspServletWrapper.service() method is synchronized.  Thus, the service 
  +     * method will not receive the servlet class until it has been completely loaded and 
  +     * instantiated.  
  +     * 
  +     * The bottom line is that we avoid synchronizing a fairly expensive 
  +     * operation (isOutDated) but pay a small price of some unnecessary 
  +     * compilation attempts in the atypical case of a modified JSP file.  
  +     */
       protected boolean doLoadJSP(String jspUri, String classpath, 
  -	boolean isErrorPage, HttpServletRequest req, HttpServletResponse res) 
  -	throws JasperException, FileNotFoundException 
  +                                boolean isErrorPage, HttpServletRequest req, HttpServletResponse res) 
  +    throws JasperException, FileNotFoundException 
       {
  -	JspServletWrapper jsw=(JspServletWrapper) jsps.get(jspUri);
  -	if( jsw==null ) {
  -	    throw new JasperException("Can't happen - JspServletWrapper=null");
  -	}
  -	//	Class jspClass = (Class) loadedJSPs.get(jspUri);
  -	boolean firstTime = jsw.servletClass == null;
  -   JspCompilationContext ctxt = new JspEngineContext(loader, classpath,
  -                                                     context, jspUri, 
  -                                                     isErrorPage, options,
  -                                                     req, res);
  -	boolean outDated = false; 
  +        JspServletWrapper jsw=(JspServletWrapper) jsps.get(jspUri);
  +        if( jsw==null ) {
  +            throw new JasperException("Can't happen - JspServletWrapper=null");
  +        }
  +        JspCompilationContext ctxt = new JspEngineContext(loader, classpath,
  +                                                          context, jspUri, 
  +                                                          isErrorPage, options,
  +                                                          req, res);
  +        boolean outDated = false; 
  +
  +        Compiler compiler = null;
  +        synchronized(jsw){
  +            /*
  +             * Creating a compiler opens the associated .class file (if it exists)
  +             * and reads the actual class name.  If we allow a compiler to be
  +             * created while a compile is going on then bad things can happen.
  +             */
  +            compiler = ctxt.createCompiler();
  +        }
   
  -        Compiler compiler = ctxt.createCompiler();
  -        
           try {
  +
  +
               outDated = compiler.isOutDated();
  -            if ( (jsw.servletClass == null) || outDated ) {
  -                synchronized ( this ) {
  -                    if ((jsw.servletClass == null) ||
  -			(compiler.isOutDated() ))  {
  -                        outDated = compiler.compile();
  +            if(!jsw.isInstantiated() || outDated ) {
  +                synchronized(jsw){
  +                    outDated = compiler.compile();
  +                    if(!jsw.isInstantiated() || outDated) {
  +                        if( null ==ctxt.getServletClassName() ) {
  +                            compiler.computeServletClassName();
  +                        }
  +                        jsw.instantiateServlet(loader.loadClass(ctxt.getFullClassName()));
                       }
  -		}
  +                }
               }
  -        } catch (FileNotFoundException ex) {
  -			  compiler.removeGeneratedFiles();
  +        } catch(FileNotFoundException ex) {
  +            compiler.removeGeneratedFiles();
               throw ex;
  -        } catch (JasperException ex) {
  +        } catch(JasperException ex) {
               throw ex;
  -        } catch (Exception ex) {
  -	    throw new JasperException(Constants.getString("jsp.error.unable.compile"),
  +        } catch(ClassNotFoundException cex) {
  +                throw new JasperException(Constants.getString("jsp.error.unable.load"), 
  +                                          cex);
  +        } catch(Exception ex) {
  +            throw new JasperException(Constants.getString("jsp.error.unable.compile"),
                                         ex);
  -	}
  +        }
   
  -	// Reload only if it's outdated
  -	if((jsw.servletClass == null) || outDated) {
  -	    try {
  -		if( null ==ctxt.getServletClassName() ) {
  -		    compiler.computeServletClassName();
  -		}
  -		jsw.servletClass = loader.loadClass(ctxt.getFullClassName());
  -                        //loadClass(ctxt.getFullClassName(), true);
  -	    } catch (ClassNotFoundException cex) {
  -		throw new JasperException(Constants.getString("jsp.error.unable.load"), 
  -					  cex);
  -	    }
  -	    
  -	    //	    loadedJSPs.put(jspUri, jspClass);
  -	}
  -	
  -	return outDated;
  +        return outDated;
       }
   
           /**