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;
}
/**