glenn 02/05/05 21:33:16 Modified: jasper2/src/share/org/apache/jasper EmbededServletOptions.java JspC.java JspEngineContext.java Options.java jasper2/src/share/org/apache/jasper/compiler Compiler.java Generator.java JspCompiler.java PageInfo.java ParserController.java jasper2/src/share/org/apache/jasper/resources messages.properties jasper2/src/share/org/apache/jasper/runtime HttpJspBase.java jasper2/src/share/org/apache/jasper/servlet JasperLoader.java JspServlet.java JspServletWrapper.java Added: jasper2/src/share/org/apache/jasper/compiler JspRuntimeContext.java Log: Reduced amount of code within the JspServlet synchronized block, should improve performance slightly. Added ability to remove the JspServletWrapper and the class file for its JSP when a JSP file no longer exists. Added removal of JSP java source file to Compiler.removeGeneratedFiles(). Moved the normalizing of the java class output directory from JspServletWrapper to JspEngineContext where it belongs. Moved obtaining the parentClassLoader, codeSource, classpath, and permissionCollection from the JspServlet to JspDependency. The servlet init method for the JSP was not getting called on the first load of the JSP page if the page were already compiled. This has been fixed. Refactored the code in JspServletWrapper for loadJSP to remove nested try/catch blocks and the overhead from several method calls. The outdated check for recompile now includes checking of compile time included files using <%@ include file="..." %>. The data about what pages were compile time includes is generated as part of the Servlet code for the JSP. This is alot cleaner than my original proposal of storing the data in a separate file. Added the JspRuntimeContext background thread. It checks for changes to the JSP file and compile time included files. If changed, it recompiles the JSP in the background. This will allow the previous compiled JSP class to be used until the page has been recompiled and the new class is available. This will remove any request latency seen due to JSP recompiles. The background thread is only started if the web application context is a directory, reloading is enabled, and development is false. If the webapp is running directly from a war file there is no need to check for recompiles. Added two Jasper init parameters: development - set to true to force an outdated check on each page request instead of using background thread. checkInterval - Number of seconds background thread should wait before checking if JSP's are out dated. Passes all jsp watchdog tests except for the broken test case. Revision Changes Path 1.3 +51 -3 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/EmbededServletOptions.java Index: EmbededServletOptions.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/EmbededServletOptions.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- EmbededServletOptions.java 29 Apr 2002 22:39:46 -0000 1.2 +++ EmbededServletOptions.java 6 May 2002 04:33:15 -0000 1.3 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/EmbededServletOptions.java,v 1.2 2002/04/29 22:39:46 remm Exp $ - * $Revision: 1.2 $ - * $Date: 2002/04/29 22:39:46 $ + * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/EmbededServletOptions.java,v 1.3 2002/05/06 04:33:15 glenn Exp $ + * $Revision: 1.3 $ + * $Date: 2002/05/06 04:33:15 $ * * ==================================================================== * @@ -78,6 +78,12 @@ * @author Pierre Delisle */ public final class EmbededServletOptions implements Options { + + /** + * Is Jasper being used in development mode? + */ + public boolean development = false; + /** * Do you want to keep the generated Java files around? */ @@ -111,6 +117,11 @@ public boolean classDebugInfo = false; /** + * Background compile thread check interval in seconds. + */ + public int checkInterval = 300; + + /** * JSP reloading check ? */ public boolean reloading = true; @@ -190,6 +201,20 @@ } /** + * Background JSP compile thread check intervall + */ + public int getCheckInterval() { + return checkInterval; + } + + /** + * Is Jasper being used in development mode? + */ + public boolean getDevelopment() { + return development; + } + + /** * JSP reloading check ? */ public boolean getReloading() { @@ -290,6 +315,29 @@ else if (debugInfo.equalsIgnoreCase("false")) this.classDebugInfo = false; else Constants.message ("jsp.warning.classDebugInfo", Logger.WARNING); + } + + String checkInterval = config.getInitParameter("checkInterval"); + if (checkInterval != null) { + try { + this.checkInterval = new Integer(checkInterval).intValue(); + if (this.checkInterval == 0) { + this.checkInterval = 300; + Constants.message("jsp.warning.checkInterval", + Logger.WARNING); + } + } catch(NumberFormatException ex) { + Constants.message ("jsp.warning.checkInterval", Logger.WARNING); + } + } + + String development = config.getInitParameter("development"); + if (development != null) { + if (development.equalsIgnoreCase("true")) + this.development = true; + else if (development.equalsIgnoreCase("false")) + this.development = false; + else Constants.message ("jsp.warning.development", Logger.WARNING); } String reloading = config.getInitParameter("reloading"); 1.3 +17 -3 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/JspC.java Index: JspC.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/JspC.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- JspC.java 29 Apr 2002 22:39:46 -0000 1.2 +++ JspC.java 6 May 2002 04:33:15 -0000 1.3 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/JspC.java,v 1.2 2002/04/29 22:39:46 remm Exp $ - * $Revision: 1.2 $ - * $Date: 2002/04/29 22:39:46 $ + * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/JspC.java,v 1.3 2002/05/06 04:33:15 glenn Exp $ + * $Revision: 1.3 $ + * $Date: 2002/05/06 04:33:15 $ * * ==================================================================== * @@ -182,6 +182,20 @@ public boolean getClassDebugInfo() { // compile with debug info + return false; + } + + /** + * Background compilation check intervals in seconds + */ + public int getCheckInterval() { + return 300; + } + + /** + * Is Jasper being used in development mode? + */ + public boolean getDevelopment() { return false; } 1.6 +177 -45 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/JspEngineContext.java Index: JspEngineContext.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/JspEngineContext.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- JspEngineContext.java 1 May 2002 02:40:37 -0000 1.5 +++ JspEngineContext.java 6 May 2002 04:33:15 -0000 1.6 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/JspEngineContext.java,v 1.5 2002/05/01 02:40:37 glenn Exp $ - * $Revision: 1.5 $ - * $Date: 2002/05/01 02:40:37 $ + * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/JspEngineContext.java,v 1.6 2002/05/06 04:33:15 glenn Exp $ + * $Revision: 1.6 $ + * $Date: 2002/05/06 04:33:15 $ * * ==================================================================== * @@ -65,29 +65,38 @@ package org.apache.jasper; -import java.io.IOException; import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.jasper.Constants; +import org.apache.jasper.JasperException; import org.apache.jasper.compiler.JspReader; +import org.apache.jasper.compiler.JspRuntimeContext; import org.apache.jasper.compiler.ServletWriter; -import org.apache.jasper.servlet.JasperLoader; - import org.apache.jasper.compiler.Compiler; import org.apache.jasper.compiler.JspCompiler; import org.apache.jasper.compiler.SunJavaCompiler; import org.apache.jasper.compiler.JavaCompiler; - import org.apache.jasper.logging.Logger; +import org.apache.jasper.servlet.JasperLoader; +import org.apache.jasper.servlet.JspServletWrapper; + /** - * A place holder for various things that are used through out the JSP - * engine. This is a per-request/per-context data structure. Some of - * the instance variables are set at different points. + * The context data and methods required to compile a + * specific JSP page. * * @author Anil K. Vijendran * @author Harish Prabandham @@ -98,75 +107,70 @@ private JspReader reader; private ServletWriter writer; private ServletContext context; - private URLClassLoader loader; + private URLClassLoader jspLoader; private Compiler jspCompiler; - private String classpath; // for compiling JSPs. private boolean isErrPage; private String jspUri; private String baseURI; private String outDir; + private URL [] outUrls = new URL[1]; + private Class servletClass; private String servletClassName; private String servletPackageName = Constants.JSP_PACKAGE_NAME; private String servletJavaFileName; private String contentType; private Options options; - - public JspEngineContext(URLClassLoader loader, String classpath, - ServletContext context, String jspUri, - boolean isErrPage, Options options) { - this.loader = loader; - this.classpath = classpath; + private JspRuntimeContext rctxt; + private boolean reload = true; + private int removed = 0; + private JspServletWrapper jsw; + + public JspEngineContext(JspRuntimeContext rctxt, ServletContext context, + String jspUri, JspServletWrapper jsw, + boolean isErrPage, Options options) + throws JasperException { + this.rctxt = rctxt; this.context = context; this.jspUri = jspUri; + this.jsw = jsw; baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1); this.isErrPage = isErrPage; this.options = options; + createOutdir(); + createCompiler(); } private void createOutdir() { - File outDir = null; + File outDir = null; try { URL outURL = options.getScratchDir().toURL(); - String outURI = outURL.toString(); + String outURI = outURL.toString(); if( outURI.endsWith("/") ) { - outURI = outURI + + outURI = outURI + jspUri.substring(1,jspUri.lastIndexOf("/")+1); } else { - outURI = outURI + + outURI = outURI + jspUri.substring(0,jspUri.lastIndexOf("/")+1);; } - outURL = new URL(outURI); - outDir = new File(outURL.getFile()); + outURL = new URL(outURI); + outDir = new File(normalize(outURL.getFile())); if( !outDir.exists() ) { outDir.mkdirs(); } this.outDir = outDir.toString() + File.separator; + outUrls[0] = new URL(outDir.toURL().toString() + File.separator); } catch(Exception e) { throw new IllegalStateException("No output directory: " + e.getMessage()); - } + } } /** * The classpath that is passed off to the Java compiler. */ public String getClassPath() { - URL [] urls = loader.getURLs(); - StringBuffer cpath = new StringBuffer(); - String sep = System.getProperty("path.separator"); - - for(int i = 0; i < urls.length; i++) { - // Tomcat 4 can use URL's other than file URL's, - // a protocol other than file: will generate a - // bad file system path, so only add file: - // protocol URL's to the classpath. - if( urls[i].getProtocol().equals("file") ) { - cpath.append((String)urls[i].getFile()+sep); - } - } - - return cpath.toString() + classpath; + return rctxt.getClassPath(); } /** @@ -195,7 +199,7 @@ * this JSP. */ public ClassLoader getClassLoader() { - return Thread.currentThread().getContextClassLoader(); + return rctxt.getParentClassLoader(); } /** @@ -213,7 +217,7 @@ public String getOutputDir() { return outDir; } - + /** * Get the scratch directory to place generated code for javac. * @@ -278,6 +282,7 @@ return options; } + public void setContentType(String contentType) { this.contentType = contentType; } @@ -313,7 +318,7 @@ */ public Compiler createCompiler() throws JasperException { - if (jspCompiler != null) { + if (jspCompiler != null ) { return jspCompiler; } @@ -338,13 +343,75 @@ javac.setCompilerPath(compilerPath); } - jspCompiler = new JspCompiler(this); + jspCompiler = new JspCompiler(this,jsw); jspCompiler.setJavaCompiler(javac); return jspCompiler; + } + public void compile() throws JasperException, FileNotFoundException { + + if (jspCompiler.isOutDated()) { + try { + jspCompiler.compile(); + reload = true; + } catch (Exception ex) { + throw new JasperException( + Constants.getString("jsp.error.unable.compile"),ex); + } + } } - + + public Class load() throws JasperException, FileNotFoundException { + + try { + if (servletClass == null || options.getDevelopment()) { + compile(); + } + jspLoader = new JasperLoader + (outUrls, + getServletPackageName() + "." + getServletClassName(), + rctxt.getParentClassLoader(), + rctxt.getPermissionCollection(), + rctxt.getCodeSource()); + servletClass = jspLoader.loadClass( + getServletPackageName() + "." + getServletClassName()); + } catch (FileNotFoundException ex) { + jspCompiler.removeGeneratedFiles(); + throw ex; + } catch (ClassNotFoundException cex) { + throw new JasperException( + Constants.getString("jsp.error.unable.load"),cex); + } catch (JasperException ex) { + throw ex; + } catch (Exception ex) { + throw new JasperException + (Constants.getString("jsp.error.unable.compile"), ex); + } + removed = 0; + reload = false; + return servletClass; + } + + public boolean isReload() { + return reload; + } + + public void incrementRemoved() { + if (removed > 1) { + jspCompiler.removeGeneratedFiles(); + rctxt.removeWrapper(jspUri); + } + removed++; + } + + public boolean isRemoved() { + if (removed > 1 ) { + return true; + } + return false; + } + /** * Get the full value of a URI relative to this compilations context */ @@ -385,4 +452,69 @@ options.getTldLocationsCache().getLocation(uri); return location; } + + /** + * Return a context-relative path, beginning with a "/", that represents + * the canonical version of the specified path after ".." and "." elements + * are resolved out. If the specified path attempts to go outside the + * boundaries of the current context (i.e. too many ".." path elements + * are present), return <code>null</code> instead. + * + * @param path Path to be normalized + */ + protected String normalize(String path) { + + if (path == null) { + return null; + } + + String normalized = path; + + // Normalize the slashes and add leading slash if necessary + if (normalized.indexOf('\\') >= 0) { + normalized = normalized.replace('\\', '/'); + } + if (!normalized.startsWith("/")) { + normalized = "/" + normalized; + } + + // Resolve occurrences of "//" in the normalized path + while (true) { + int index = normalized.indexOf("//"); + if (index < 0) { + break; + } + normalized = normalized.substring(0, index) + + normalized.substring(index + 1); + } + + // Resolve occurrences of "/./" in the normalized path + while (true) { + int index = normalized.indexOf("/./"); + if (index < 0) { + break; + } + normalized = normalized.substring(0, index) + + normalized.substring(index + 2); + } + + // Resolve occurrences of "/../" in the normalized path + while (true) { + int index = normalized.indexOf("/../"); + if (index < 0) { + break; + } + if (index == 0) { + return (null); // Trying to go outside our context + } + int index2 = normalized.lastIndexOf('/', index - 1); + normalized = normalized.substring(0, index2) + + normalized.substring(index + 3); + } + + // Return the normalized path that we have completed + return (normalized); + + } + } 1.4 +13 -3 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/Options.java Index: Options.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/Options.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- Options.java 29 Apr 2002 22:39:46 -0000 1.3 +++ Options.java 6 May 2002 04:33:15 -0000 1.4 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/Options.java,v 1.3 2002/04/29 22:39:46 remm Exp $ - * $Revision: 1.3 $ - * $Date: 2002/04/29 22:39:46 $ + * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/Options.java,v 1.4 2002/05/06 04:33:15 glenn Exp $ + * $Revision: 1.4 $ + * $Date: 2002/05/06 04:33:15 $ * * ==================================================================== * @@ -101,6 +101,16 @@ * Should we include debug information in compiled class? */ public boolean getClassDebugInfo(); + + /** + * Background compile thread check interval in seconds + */ + public int getCheckInterval(); + + /** + * Is Jasper being used in development mode? + */ + public boolean getDevelopment(); /** * JSP reloading check ? 1.4 +14 -6 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Compiler.java Index: Compiler.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Compiler.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- Compiler.java 24 Apr 2002 02:21:05 -0000 1.3 +++ Compiler.java 6 May 2002 04:33:15 -0000 1.4 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Compiler.java,v 1.3 2002/04/24 02:21:05 kinman Exp $ - * $Revision: 1.3 $ - * $Date: 2002/04/24 02:21:05 $ + * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Compiler.java,v 1.4 2002/05/06 04:33:15 glenn Exp $ + * $Revision: 1.4 $ + * $Date: 2002/05/06 04:33:15 $ * * ==================================================================== * @@ -105,8 +105,7 @@ // Setup page info area pageInfo = new PageInfo(new BeanRepository(ctxt.getClassLoader())); - String javaFileName = mangler.getJavaFileName(); - ctxt.setServletJavaFileName(javaFileName); + String javaFileName = ctxt.getServletJavaFileName(); Constants.message("jsp.message.java_file_name_is", new Object[] { javaFileName }, @@ -242,6 +241,7 @@ */ public void setMangler(Mangler mangler) { this.mangler = mangler; + ctxt.setServletJavaFileName(mangler.getJavaFileName()); } /** @@ -304,11 +304,19 @@ */ public void removeGeneratedFiles() { try { - // XXX Should we delete the generated .java file too? String classFileName = mangler.getClassFileName(); if (classFileName != null) { File classFile = new File(classFileName); classFile.delete(); + } + } catch (Exception e) { + //Remove as much as possible, ignore possible exceptions + } + try { + String javaFileName = mangler.getJavaFileName(); + if (javaFileName != null) { + File javaFile = new File(javaFileName); + javaFile.delete(); } } catch (Exception e) { //Remove as much as possible, ignore possible exceptions 1.10 +37 -4 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Generator.java Index: Generator.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Generator.java,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- Generator.java 4 May 2002 01:21:59 -0000 1.9 +++ Generator.java 6 May 2002 04:33:15 -0000 1.10 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Generator.java,v 1.9 2002/05/04 01:21:59 kinman Exp $ - * $Revision: 1.9 $ - * $Date: 2002/05/04 01:21:59 $ + * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Generator.java,v 1.10 2002/05/06 04:33:15 glenn Exp $ + * $Revision: 1.10 $ + * $Date: 2002/05/06 04:33:15 $ * * ==================================================================== * @@ -203,8 +203,41 @@ // Static initializations (none yet) here + // Static data for getIncludes() + out.printil("private static java.util.Vector _jspx_includes;"); + out.println(); + out.println(); + List includes = pageInfo.getIncludes(); + iter = includes.iterator(); + if( !includes.isEmpty() ) { + out.printil("static {"); + out.pushIndent(); + out.printin( + "_jspx_includes = new java.util.Vector("); + out.print(""+includes.size()); + out.println(");"); + while (iter.hasNext()) { + out.printin("_jspx_includes.add(\""); + out.print((String)iter.next()); + out.println("\");"); + } + out.popIndent(); + out.printil("}"); + out.println(); + out.println(); + } + // Constructor (empty so far) here - // Other methods here + + // Method used to get compile time include file dependencies + out.printil("public java.util.List getIncludes() {"); + out.pushIndent(); + out.printil("return _jspx_includes;"); + out.popIndent(); + out.printil("}"); + out.println(); + out.println(); + out.printil("private void addTagToVector(java.util.Vector tags, int index, javax.servlet.jsp.tagext.Tag tag) {"); out.pushIndent(); out.printil("if (index + 1 > tags.size())"); 1.5 +75 -23 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/JspCompiler.java Index: JspCompiler.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/JspCompiler.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- JspCompiler.java 1 May 2002 15:02:38 -0000 1.4 +++ JspCompiler.java 6 May 2002 04:33:15 -0000 1.5 @@ -58,11 +58,15 @@ import java.io.File; import java.io.FileNotFoundException; import java.net.URL; +import java.util.Iterator; +import java.util.List; import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.JspEngineContext; import org.apache.jasper.Constants; import org.apache.jasper.JasperException; - +import org.apache.jasper.runtime.HttpJspBase; +import org.apache.jasper.servlet.JspServletWrapper; import org.apache.jasper.logging.Logger; /** @@ -79,18 +83,22 @@ */ public class JspCompiler extends Compiler implements Mangler { - String javaFileName, classFileName; - String realClassName; + private String javaFileName; + private String classFileName; + private String realClassName; + private String jsp; + private String outputDir; - String jsp; - String outputDir; + private JspServletWrapper jsw; Logger.Helper loghelper = new Logger.Helper("JASPER_LOG", "JspCompiler"); - public JspCompiler(JspCompilationContext ctxt) throws JasperException { + public JspCompiler(JspCompilationContext ctxt, JspServletWrapper jsw) + throws JasperException { super(ctxt); this.jsp = ctxt.getJspFile(); + this.jsw = jsw; this.outputDir = ctxt.getOutputDir(); setMangler(this); } @@ -104,19 +112,28 @@ } public final String getJavaFileName() { - if( javaFileName!=null ) return javaFileName; + + if( javaFileName!=null ) { + return javaFileName; + } + javaFileName = getClassName() + ".java"; - if (outputDir != null && !outputDir.equals("")) + if (outputDir != null && !outputDir.equals("")) { javaFileName = outputDir + javaFileName; + } return javaFileName; } public final String getClassFileName() { - if( classFileName!=null) return classFileName; + + if( classFileName!=null) { + return classFileName; + } classFileName = getClassName() + ".class"; - if (outputDir != null && !outputDir.equals("")) + if (outputDir != null && !outputDir.equals("")) { classFileName = outputDir + File.separatorChar + classFileName; + } return classFileName; } @@ -137,14 +154,15 @@ } for (int i = iSep; i < iEnd; i++) { char ch = jsp.charAt(i); - if (Character.isLetterOrDigit(ch)) + if (Character.isLetterOrDigit(ch)) { modifiedClassName.append(ch); - else if (ch == '.') + } else if (ch == '.') { modifiedClassName.append('$'); - else + } else { modifiedClassName.append(mangleChar(ch)); + } } - return (modifiedClassName.toString()); + return modifiedClassName.toString(); } @@ -158,10 +176,12 @@ int nzeros = 5 - s.length(); char[] result = new char[6]; result[0] = '_'; - for (int i = 1; i <= nzeros; i++) + for (int i = 1; i <= nzeros; i++) { result[i] = '0'; - for (int i = nzeros+1, j = 0; i < 6; i++, j++) + } + for (int i = nzeros+1, j = 0; i < 6; i++, j++) { result[i] = s.charAt(j); + } return new String(result); } @@ -173,11 +193,12 @@ public boolean isOutDated() { long jspRealLastModified = 0; - try { URL jspUrl = ctxt.getResource(jsp); - if (jspUrl == null) - return true; + if (jspUrl == null) { + ((JspEngineContext)ctxt).incrementRemoved(); + return false; + } jspRealLastModified = jspUrl.openConnection().getLastModified(); } catch (Exception e) { e.printStackTrace(); @@ -185,11 +206,42 @@ } File classFile = new File(getClassFileName()); - if (classFile.exists()) - return classFile.lastModified() < jspRealLastModified; + if (!classFile.exists()) { + return true; + } + long classLastModified = classFile.lastModified(); + if (classLastModified < jspRealLastModified) { + return true; + } - return true; + // Determine if compile time includes have been changed + HttpJspBase servlet = jsw.getServlet(); + if (servlet == null) { + return false; + } + List includes = servlet.getIncludes(); + if (includes == null) { + return false; + } + Iterator it = includes.iterator(); + while (it.hasNext()) { + String include = (String)it.next(); + try { + URL includeUrl = ctxt.getResource(include); + if (includeUrl == null) { + return true; + } + if (includeUrl.openConnection().getLastModified() > + classLastModified) { + return true; + } + } catch (Exception e) { + e.printStackTrace(); + return true; + } + } + return false; } -} +} 1.3 +13 -3 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/PageInfo.java Index: PageInfo.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/PageInfo.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- PageInfo.java 19 Apr 2002 20:35:01 -0000 1.2 +++ PageInfo.java 6 May 2002 04:33:15 -0000 1.3 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/PageInfo.java,v 1.2 2002/04/19 20:35:01 kinman Exp $ - * $Revision: 1.2 $ - * $Date: 2002/04/19 20:35:01 $ + * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/PageInfo.java,v 1.3 2002/05/06 04:33:15 glenn Exp $ + * $Revision: 1.3 $ + * $Date: 2002/05/06 04:33:15 $ * * ==================================================================== * @@ -73,6 +73,7 @@ class PageInfo { private Vector imports; + private Vector includes; private BeanRepository beanRepository; private Hashtable tagLibraries; @@ -92,6 +93,7 @@ this.beanRepository = beanRepository; this.tagLibraries = new Hashtable(); this.imports = new Vector(); + this.includes = new Vector(); // Enter standard imports for(int i = 0; i < Constants.STANDARD_IMPORTS.length; i++) @@ -104,6 +106,14 @@ public List getImports() { return imports; + } + + public void addInclude(String include) { + this.includes.add(include); + } + + public List getIncludes() { + return includes; } public BeanRepository getBeanRepository() { 1.3 +3 -1 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/ParserController.java Index: ParserController.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/ParserController.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- ParserController.java 19 Apr 2002 20:35:01 -0000 1.2 +++ ParserController.java 6 May 2002 04:33:15 -0000 1.3 @@ -178,7 +178,9 @@ // for all included files where encoding is not defined. topFileEncoding = encoding; isTopFile = false; - } + } else { + compiler.getPageInfo().addInclude(absFileName); + } try { reader.close(); } catch (IOException ex) { 1.1 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/JspRuntimeContext.java Index: JspRuntimeContext.java =================================================================== /* * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/JspRuntimeContext.java,v 1.1 2002/05/06 04:33:15 glenn Exp $ * $Revision: 1.1 $ * $Date: 2002/05/06 04:33:15 $ * * ==================================================================== * * 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 [EMAIL PROTECTED] * * 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/>. * */ package org.apache.jasper.compiler; import java.io.File; import java.io.FileNotFoundException; import java.io.FilePermission; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.security.CodeSource; import java.security.Policy; import java.security.PermissionCollection; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.jsp.JspFactory; import org.apache.commons.collections.FastHashMap; import org.apache.jasper.JasperException; import org.apache.jasper.Constants; import org.apache.jasper.JspEngineContext; import org.apache.jasper.Options; import org.apache.jasper.logging.Logger; import org.apache.jasper.runtime.JspFactoryImpl; import org.apache.jasper.servlet.JspServletWrapper; /** * Class for tracking JSP compile time file dependencies when the * <%@include file="..."%> directive is used. * * A background thread periodically checks the files a JSP page * is dependent upon. If a dpendent file changes the JSP page * which included it is recompiled. * * Saves information about JSP dependincies to the file * <code>JSP_DEPENDENCY.ser</code> in the web application context * work directory. * * Only used if a web application context is a directory. * * @author Glenn L. Nielsen * @version $Revision: 1.1 $ */ public final class JspRuntimeContext implements Runnable { /** * Preload classes required at runtime by a JSP servlet so that * we don't get a defineClassInPackage security exception. */ static { JspFactoryImpl factory = new JspFactoryImpl(); if( System.getSecurityManager() != null ) { String basePackage = "org.apache.jasper."; try { factory.getClass().getClassLoader().loadClass( basePackage + "runtime.JspFactoryImpl$PrivilegedGetPageContext"); factory.getClass().getClassLoader().loadClass( basePackage + "runtime.JspFactoryImpl$PrivilegedReleasePageContext"); factory.getClass().getClassLoader().loadClass( basePackage + "runtime.JspRuntimeLibrary"); factory.getClass().getClassLoader().loadClass( basePackage + "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper"); factory.getClass().getClassLoader().loadClass( basePackage + "runtime.ServletResponseWrapperInclude"); factory.getClass().getClassLoader().loadClass( basePackage + "servlet.JspServletWrapper"); } catch (ClassNotFoundException ex) { System.out.println( "Jasper JspRuntimeContext preload of class failed: " + ex.getMessage()); } } JspFactory.setDefaultFactory(factory); } // ----------------------------------------------------------- Constructors /** * Create a JspRuntimeContext for a web application context. * * Loads in any previously generated dependencies from file. * * @param ServletContext for web application */ public JspRuntimeContext(ServletContext context, Options options) { this.context = context; this.options = options; // Get the parent class loader parentClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader(); if (parentClassLoader == null) { parentClassLoader = (URLClassLoader)this.getClass().getClassLoader(); } if (parentClassLoader != null) { Constants.message("jsp.message.parent_class_loader_is", new Object[] { parentClassLoader.toString() }, Logger.DEBUG); } else { Constants.message("jsp.message.parent_class_loader_is", new Object[] { "<none>" }, Logger.DEBUG); } initSecurity(); initClassPath(); // If this web application context is running from a // directory, start the background compilation thread String appBase = context.getRealPath("/"); if (!options.getDevelopment() && appBase != null && options.getReloading() ) { if (appBase.endsWith(File.separator) ) { appBase = appBase.substring(0,appBase.length()-1); } String directory = appBase.substring(appBase.lastIndexOf(File.separator)); threadName = threadName + "[" + directory + "]"; threadStart(); } } // ----------------------------------------------------- Instance Variables /** * This web applications ServletContext */ private ServletContext context; private Options options; private URLClassLoader parentClassLoader; private PermissionCollection permissionCollection; private CodeSource codeSource; private String classpath; /** * Maps JSP pages to their JspServletWrapper's */ private Map jsps = new FastHashMap(); /** * The background thread. */ private Thread thread = null; /** * The background thread completion semaphore. */ private boolean threadDone = false; /** * Name to register for the background thread. */ private String threadName = "JspRuntimeContext"; // ------------------------------------------------------ Protected Methods /** * Add a new JspServletWrapper. * * @param String uri of JSP * @param JspServletWrapper for JSP */ public void addWrapper(String jspUri, JspServletWrapper jsw) { jsps.remove(jspUri); jsps.put(jspUri,jsw); } /** * Get an already existing JspServletWrapper. * * @param String JSP URI * @return JspServletWrapper for JSP */ public JspServletWrapper getWrapper(String jspUri) { return (JspServletWrapper) jsps.get(jspUri); } /** * Remove a JspServletWrapper. * * @param String JSP URI of JspServletWrapper to remove */ public void removeWrapper(String jspUri) { jsps.remove(jspUri); } /** * Get the SecurityManager Policy CodeSource for this web * applicaiton context. * * @return CodeSource for JSP */ public CodeSource getCodeSource() { return codeSource; } /** * Get the parent URLClassLoader. * * @return URLClassLoader parent */ public URLClassLoader getParentClassLoader() { return parentClassLoader; } /** * Get the SecurityManager PermissionCollection for this * web application context. * * @return PermissionCollection permissions */ public PermissionCollection getPermissionCollection() { return permissionCollection; } /** * Process a "destory" event for this web application context. */ public void destroy() { threadStop(); Iterator servlets = jsps.values().iterator(); while (servlets.hasNext()) { ((JspServletWrapper) servlets.next()).destroy(); } } // -------------------------------------------------------- Private Methods /** * Method used by background thread to check the JSP dependencies * registered with this class for JSP's. */ private void checkCompile() { Iterator it = jsps.values().iterator(); while (it.hasNext()) { JspServletWrapper jsw = (JspServletWrapper)it.next(); JspEngineContext ctxt = jsw.getJspEngineContext(); // JspServletWrapper also synchronizes on this when // it detects it has to do a reload synchronized(jsw) { try { ctxt.compile(); } catch (FileNotFoundException ex) { ctxt.incrementRemoved(); } catch (Throwable t) { jsw.getServletContext().log("Background compile failed",t); } } } } /** * The classpath that is passed off to the Java compiler. */ public String getClassPath() { return classpath; } /** * Method used to initialize classpath for compiles. */ private void initClassPath() { URL [] urls = parentClassLoader.getURLs(); StringBuffer cpath = new StringBuffer(); String sep = System.getProperty("path.separator"); for(int i = 0; i < urls.length; i++) { // Tomcat 4 can use URL's other than file URL's, // a protocol other than file: will generate a // bad file system path, so only add file: // protocol URL's to the classpath. if( urls[i].getProtocol().equals("file") ) { cpath.append((String)urls[i].getFile()+sep); } } String cp = (String) context.getAttribute(Constants.SERVLET_CLASSPATH); if (cp == null || cp.equals("")) { cp = options.getClassPath(); } classpath = cpath.toString() + cp; } /** * Method used to initialize SecurityManager data. */ private void initSecurity() { // Setup the PermissionCollection for this web app context // based on the permissions configured for the root of the // web app context directory, then add a file read permission // for that directory. Policy policy = Policy.getPolicy(); if( policy != null ) { try { // Get the permissions for the web app context String contextDir = context.getRealPath("/"); if( contextDir == null ) { contextDir = options.getScratchDir().toString(); } URL url = new URL("file:" + contextDir); codeSource = new CodeSource(url,null); permissionCollection = policy.getPermissions(codeSource); // Create a file read permission for web app context directory if (contextDir.endsWith(File.separator)) { contextDir = contextDir + "-"; } else { contextDir = contextDir + File.separator + "-"; } permissionCollection.add(new FilePermission(contextDir,"read")); // Allow the JSP to access org.apache.jasper.runtime.HttpJspBase permissionCollection.add( new RuntimePermission( "accessClassInPackage.org.apache.jasper.runtime") ); if (parentClassLoader instanceof URLClassLoader) { URL [] urls = parentClassLoader.getURLs(); String jarUrl = null; String jndiUrl = null; for (int i=0; i<urls.length; i++) { if (jndiUrl == null && urls[i].toString().startsWith("jndi:") ) { jndiUrl = urls[i].toString() + "-"; } if (jarUrl == null && urls[i].toString().startsWith("jar:jndi:") ) { jarUrl = urls[i].toString(); jarUrl = jarUrl.substring(0,jarUrl.length() - 2); jarUrl = jarUrl.substring(0, jarUrl.lastIndexOf('/')) + "/-"; } } if (jarUrl != null) { permissionCollection.add( new FilePermission(jarUrl,"read")); permissionCollection.add( new FilePermission(jarUrl.substring(4),"read")); } if (jndiUrl != null) permissionCollection.add( new FilePermission(jndiUrl,"read") ); } } catch(MalformedURLException mfe) { } } } // -------------------------------------------------------- Thread Support /** * Start the background thread that will periodically check for * changes to compile time included files in a JSP. * * @exception IllegalStateException if we should not be starting * a background thread now */ protected void threadStart() { // Has the background thread already been started? if (thread != null) { return; } // Start the background thread threadDone = false; thread = new Thread(this, threadName); thread.setDaemon(true); thread.start(); } /** * Stop the background thread that is periodically checking for * changes to compile time included files in a JSP. */ protected void threadStop() { if (thread == null) { return; } threadDone = true; thread.interrupt(); try { thread.join(); } catch (InterruptedException e) { ; } thread = null; } /** * Sleep for the duration specified by the <code>checkInterval</code> * property. */ protected void threadSleep() { try { Thread.sleep(options.getCheckInterval() * 1000L); } catch (InterruptedException e) { ; } } // ------------------------------------------------------ Background Thread /** * The background thread that checks for changes to files * included by a JSP and flags that a recompile is required. */ public void run() { // Loop until the termination semaphore is set while (!threadDone) { // Wait for our check interval threadSleep(); // Check for included files which are newer than the // JSP which uses them. checkCompile(); } } } 1.4 +2 -1 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/resources/messages.properties Index: messages.properties =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/resources/messages.properties,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- messages.properties 29 Apr 2002 22:39:46 -0000 1.3 +++ messages.properties 6 May 2002 04:33:15 -0000 1.4 @@ -1,4 +1,4 @@ -# $Id: messages.properties,v 1.3 2002/04/29 22:39:46 remm Exp $ +# $Id: messages.properties,v 1.4 2002/05/06 04:33:15 glenn Exp $ # # Default localized string information # Localized this the Default Locale as is en_US @@ -117,6 +117,7 @@ jsp.warning.mappedFile=Warning: Invalid value for the initParam mappedFile. Will use the default value of \"false\" jsp.warning.sendErrToClient=Warning: Invalid value for the initParam sendErrToClient. Will use the default value of \"false\" jsp.warning.classDebugInfo=Warning: Invalid value for the initParam classdebuginfo. Will use the default value of \"false\" +jsp.warning.development=Warning: Invalid value for the initParam development. Will use the default value of \"true\" jsp.warning.reloading=Warning: Invalid value for the initParam reloading. Will use the default value of \"true\" jsp.error.badtaglib=Unable to open taglibrary {0} : {1} jsp.error.badGetReader=Cannot create a reader when the stream is not buffered 1.2 +13 -1 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/runtime/HttpJspBase.java Index: HttpJspBase.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/runtime/HttpJspBase.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- HttpJspBase.java 28 Mar 2002 18:46:19 -0000 1.1 +++ HttpJspBase.java 6 May 2002 04:33:15 -0000 1.2 @@ -62,6 +62,8 @@ import java.net.URL; import java.net.MalformedURLException; +import java.util.List; + import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*; @@ -112,7 +114,17 @@ public void jspDestroy() { } - + + /** + * Get the list of compile time included files used + * by the JSP file. + * + * Overridden by generated JSP java source files. + * + * @return List compile time includes + */ + public abstract List getIncludes(); + public abstract void _jspService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException; 1.2 +2 -2 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/servlet/JasperLoader.java Index: JasperLoader.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/servlet/JasperLoader.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- JasperLoader.java 28 Mar 2002 18:46:20 -0000 1.1 +++ JasperLoader.java 6 May 2002 04:33:15 -0000 1.2 @@ -106,7 +106,7 @@ private SecurityManager securityManager = null; private PrivilegedLoadClass privLoadClass = null; - JasperLoader(URL [] urls, String className, ClassLoader parent, + public JasperLoader(URL [] urls, String className, ClassLoader parent, PermissionCollection permissionCollection, CodeSource codeSource) { super(urls,parent); @@ -202,7 +202,7 @@ } // Only load classes for this JSP page - if( name.startsWith(Constants.JSP_PACKAGE_NAME + "." + className) ) { + if( name.startsWith(className) ) { String classFile = name.substring(Constants.JSP_PACKAGE_NAME.length()+1) + ".class"; byte [] cdata = loadClassDataFromFile(classFile); 1.11 +47 -177 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/servlet/JspServlet.java Index: JspServlet.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/servlet/JspServlet.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- JspServlet.java 1 May 2002 02:40:37 -0000 1.10 +++ JspServlet.java 6 May 2002 04:33:16 -0000 1.11 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/servlet/JspServlet.java,v 1.10 2002/05/01 02:40:37 glenn Exp $ - * $Revision: 1.10 $ - * $Date: 2002/05/01 02:40:37 $ + * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/servlet/JspServlet.java,v 1.11 2002/05/06 04:33:16 glenn Exp $ + * $Revision: 1.11 $ + * $Date: 2002/05/06 04:33:16 $ * * The Apache Software License, Version 1.1 * @@ -66,30 +66,20 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.jsp.JspFactory; -import java.io.File; import java.io.IOException; import java.io.FileNotFoundException; -import java.io.FilePermission; -import java.lang.RuntimePermission; import java.net.URL; import java.net.URLClassLoader; import java.net.MalformedURLException; -import java.security.CodeSource; -import java.security.PermissionCollection; -import java.security.Policy; import java.util.Enumeration; -import java.util.Iterator; -import java.util.Map; - -import org.apache.commons.collections.FastHashMap; import org.apache.jasper.JasperException; import org.apache.jasper.Constants; import org.apache.jasper.Options; import org.apache.jasper.EmbededServletOptions; -import org.apache.jasper.runtime.*; + +import org.apache.jasper.compiler.JspRuntimeContext; import org.apache.jasper.logging.Logger; import org.apache.jasper.logging.DefaultLogger; @@ -116,17 +106,9 @@ private Logger.Helper loghelper; private ServletContext context; - private Map jsps = new FastHashMap(); private ServletConfig config; private Options options; - private URLClassLoader parentClassLoader; - private ServletEngine engine; - private String serverInfo; - private PermissionCollection permissionCollection; - private CodeSource codeSource; - private String classpath; - - static boolean firstTime = true; + private JspRuntimeContext rctxt; public void init(ServletConfig config) throws ServletException { @@ -134,164 +116,25 @@ super.init(config); this.config = config; this.context = config.getServletContext(); - this.serverInfo = context.getServerInfo(); // Setup logging Constants.jasperLog = new DefaultLogger(this.context); Constants.jasperLog.setName("JASPER_LOG"); Constants.jasperLog.setTimestamp("false"); Constants.jasperLog.setVerbosityLevel( - config.getInitParameter("logVerbosityLevel")); - loghelper = new Logger.Helper("JASPER_LOG", "JspServlet"); + config.getInitParameter("logVerbosityLevel")); + loghelper = new Logger.Helper("JASPER_LOG", "JspServlet"); - options = new EmbededServletOptions(config, context); + options = new EmbededServletOptions(config, context); - ((FastHashMap)jsps).setFast(true); + // Initialize the JSP Runtime Context + rctxt = new JspRuntimeContext(context,options); - // Get the classpath to use for compiling - classpath = (String) context.getAttribute(Constants.SERVLET_CLASSPATH); - - if (classpath == null || classpath.equals("")) { - classpath = options.getClassPath(); - } - - // Get the parent class loader - parentClassLoader = - (URLClassLoader) Thread.currentThread().getContextClassLoader(); - if (parentClassLoader == null) { - parentClassLoader = - (URLClassLoader)this.getClass().getClassLoader(); - } - if (parentClassLoader != null) { - Constants.message("jsp.message.parent_class_loader_is", - new Object[] { - parentClassLoader.toString() - }, Logger.DEBUG); - } else { - Constants.message("jsp.message.parent_class_loader_is", - new Object[] { - "<none>" - }, Logger.DEBUG); - } - - // Setup the PermissionCollection for this web app context - // based on the permissions configured for the root of the - // web app context directory, then add a file read permission - // for that directory. - Policy policy = Policy.getPolicy(); - if( policy != null ) { - try { - // Get the permissions for the web app context - String contextDir = context.getRealPath("/"); - if( contextDir == null ) { - contextDir = options.getScratchDir().toString(); - } - URL url = new URL("file:" + contextDir); - codeSource = new CodeSource(url,null); - permissionCollection = policy.getPermissions(codeSource); - // Create a file read permission for web app context directory - if (contextDir.endsWith(File.separator)) { - contextDir = contextDir + "-"; - } else { - contextDir = contextDir + File.separator + "-"; - } - permissionCollection.add(new FilePermission(contextDir,"read")); - // Allow the JSP to access org.apache.jasper.runtime.HttpJspBase - permissionCollection.add( new RuntimePermission( - "accessClassInPackage.org.apache.jasper.runtime") ); - if (parentClassLoader instanceof URLClassLoader) { - URL [] urls = parentClassLoader.getURLs(); - String jarUrl = null; - String jndiUrl = null; - for (int i=0; i<urls.length; i++) { - if (jndiUrl == null - && urls[i].toString().startsWith("jndi:") ) { - jndiUrl = urls[i].toString() + "-"; - } - if (jarUrl == null - && urls[i].toString().startsWith("jar:jndi:") - ) { - jarUrl = urls[i].toString(); - jarUrl = jarUrl.substring(0,jarUrl.length() - 2); - jarUrl = jarUrl.substring(0, - jarUrl.lastIndexOf('/')) + "/-"; - } - } - if (jarUrl != null) { - permissionCollection.add( - new FilePermission(jarUrl,"read")); - permissionCollection.add( - new FilePermission(jarUrl.substring(4),"read")); - } - if (jndiUrl != null) - permissionCollection.add( - new FilePermission(jndiUrl,"read") ); - } - } catch(MalformedURLException mfe) { - } - } - - if (firstTime) { - firstTime = false; - if( System.getSecurityManager() != null ) { - // Make sure classes needed at runtime by a JSP servlet - // are already loaded by the class loader so that we - // don't get a defineClassInPackage security exception. - String basePackage = "org.apache.jasper."; - try { - parentClassLoader.loadClass( basePackage + - "runtime.JspFactoryImpl$PrivilegedGetPageContext"); - parentClassLoader.loadClass( basePackage + - "runtime.JspFactoryImpl$PrivilegedReleasePageContext"); - parentClassLoader.loadClass( basePackage + - "runtime.JspRuntimeLibrary"); - parentClassLoader.loadClass( basePackage + - "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper"); - parentClassLoader.loadClass( basePackage + - "runtime.ServletResponseWrapperInclude"); - this.getClass().getClassLoader().loadClass( basePackage + - "servlet.JspServletWrapper"); - } catch (ClassNotFoundException ex) { - System.out.println( - "Jasper JspServlet preload of class failed: " + - ex.getMessage()); - } - } - Constants.message("jsp.message.scratch.dir.is", - new Object[] { - options.getScratchDir().toString() - }, Logger.INFORMATION ); - Constants.message("jsp.message.dont.modify.servlets", - Logger.INFORMATION); - JspFactory.setDefaultFactory(new JspFactoryImpl()); - } - } - - private void serviceJspFile(HttpServletRequest request, - HttpServletResponse response, String jspUri, - Throwable exception, boolean precompile) - throws ServletException, IOException { - - JspServletWrapper wrapper; - synchronized (this) { - wrapper = (JspServletWrapper) jsps.get(jspUri); - if (wrapper == null) { - // First check if the requested JSP page exists, to avoid - // creating unnecessary directories and files. - if (context.getResourceAsStream(jspUri) == null) { - throw new FileNotFoundException(jspUri); - } - boolean isErrorPage = exception != null; - wrapper = new JspServletWrapper(config, options, jspUri, - isErrorPage, classpath, - parentClassLoader, - permissionCollection, - codeSource); - jsps.put(jspUri, wrapper); - } - } - - wrapper.service(request, response, precompile); + Constants.message("jsp.message.scratch.dir.is", + new Object[] { options.getScratchDir().toString() }, + Logger.INFORMATION ); + Constants.message("jsp.message.dont.modify.servlets", + Logger.INFORMATION); } @@ -347,7 +190,6 @@ } - public void service (HttpServletRequest request, HttpServletResponse response) @@ -413,10 +255,38 @@ if (Constants.jasperLog != null) Constants.jasperLog.log("JspServlet.destroy()", Logger.INFORMATION); - Iterator servlets = jsps.values().iterator(); - while (servlets.hasNext()) { - ((JspServletWrapper) servlets.next()).destroy(); + rctxt.destroy(); + } + + + // -------------------------------------------------------- Private Methods + + private void serviceJspFile(HttpServletRequest request, + HttpServletResponse response, String jspUri, + Throwable exception, boolean precompile) + throws ServletException, IOException { + + JspServletWrapper wrapper = + (JspServletWrapper) rctxt.getWrapper(jspUri); + if (wrapper == null) { + // First check if the requested JSP page exists, to avoid + // creating unnecessary directories and files. + if (context.getResourceAsStream(jspUri) == null) { + throw new FileNotFoundException(jspUri); + } + boolean isErrorPage = exception != null; + synchronized(this) { + wrapper = (JspServletWrapper) rctxt.getWrapper(jspUri); + if (wrapper == null) { + wrapper = new JspServletWrapper(config, options, jspUri, + isErrorPage, rctxt); + rctxt.addWrapper(jspUri,wrapper); + } + } } + + wrapper.service(request, response, precompile); + } } 1.3 +42 -164 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/servlet/JspServletWrapper.java Index: JspServletWrapper.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/servlet/JspServletWrapper.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- JspServletWrapper.java 1 May 2002 02:40:37 -0000 1.2 +++ JspServletWrapper.java 6 May 2002 04:33:16 -0000 1.3 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/servlet/JspServletWrapper.java,v 1.2 2002/05/01 02:40:37 glenn Exp $ - * $Revision: 1.2 $ - * $Date: 2002/05/01 02:40:37 $ + * $Header: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/servlet/JspServletWrapper.java,v 1.3 2002/05/06 04:33:16 glenn Exp $ + * $Revision: 1.3 $ + * $Date: 2002/05/06 04:33:16 $ * * The Apache Software License, Version 1.1 * @@ -69,23 +69,18 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.File; import java.io.IOException; import java.io.FileNotFoundException; import java.net.URL; import java.net.URLClassLoader; import java.net.MalformedURLException; -import java.security.CodeSource; -import java.security.PermissionCollection; import org.apache.jasper.JasperException; import org.apache.jasper.Constants; import org.apache.jasper.Options; -import org.apache.jasper.JspCompilationContext; import org.apache.jasper.JspEngineContext; -import org.apache.jasper.runtime.*; - -import org.apache.jasper.compiler.Compiler; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.runtime.HttpJspBase; import org.apache.jasper.logging.Logger; @@ -106,50 +101,38 @@ * @author Glenn Nielsen */ -class JspServletWrapper { +public class JspServletWrapper { private Servlet theServlet; private String jspUri; private Class servletClass; - private URLClassLoader loader; - private JspCompilationContext ctxt; + private JspEngineContext ctxt; private long available = 0L; private ServletConfig config; private Options options; - private Compiler compiler; - private PermissionCollection permissionCollection; - private CodeSource codeSource; - private URLClassLoader parentClassLoader; JspServletWrapper(ServletConfig config, Options options, String jspUri, - boolean isErrorPage, String classpath, - URLClassLoader parentClassLoader, - PermissionCollection permissionCollection, - CodeSource codeSource) throws JasperException { + boolean isErrorPage, JspRuntimeContext rctxt) + throws JasperException { - this.jspUri = jspUri; - this.theServlet = null; this.config = config; this.options = options; - this.parentClassLoader = parentClassLoader; - this.permissionCollection = permissionCollection; - this.codeSource = codeSource; + this.jspUri = jspUri; ctxt = new JspEngineContext - (parentClassLoader, classpath, config.getServletContext(), - jspUri, isErrorPage, options); - compiler = ctxt.createCompiler(); + (rctxt, config.getServletContext(), jspUri, + this, isErrorPage, options); } - private void load() throws JasperException, ServletException { + public JspEngineContext getJspEngineContext() { + return ctxt; + } - try { - // This is to maintain the original protocol. - destroy(); - theServlet = (Servlet) servletClass.newInstance(); - } catch (Exception ex) { - throw new JasperException(ex); - } - theServlet.init(config); + public HttpJspBase getServlet() { + return (HttpJspBase)theServlet; + } + + public ServletContext getServletContext() { + return config.getServletContext(); } public void service(HttpServletRequest request, @@ -158,6 +141,10 @@ throws ServletException, IOException, FileNotFoundException { try { + if (ctxt.isRemoved()) { + throw new FileNotFoundException(jspUri); + } + if ((available > 0L) && (available < Long.MAX_VALUE)) { response.setDateHeader("Retry-After", available); response.sendError @@ -165,8 +152,19 @@ Constants.getString("jsp.error.unavailable")); } - if (loadJSP(request, response) || theServlet == null) { - load(); + if (ctxt.isReload()) { + synchronized (this) { + + // Synchronizing on jsw enables simultaneous loading + // of different pages, but not the same page. + if (ctxt.isReload()) { + servletClass = ctxt.load(); + // This is to maintain the original protocol. + destroy(); + theServlet = (Servlet) servletClass.newInstance(); + theServlet.init(config); + } + } } // If a page is to only to be precompiled return. @@ -222,6 +220,10 @@ ex, Logger.ERROR); } } + } catch (JasperException ex) { + throw ex; + } catch (Exception ex) { + throw new JasperException(ex); } } @@ -229,130 +231,6 @@ if (theServlet != null) { theServlet.destroy(); } - } - - - /* Check if we need to reload a JSP page. - * - * Side-effect: re-compile the JSP page. - * - * @return true if JSP has been recompiled - */ - boolean loadJSP(HttpServletRequest req, HttpServletResponse res) - throws JasperException, FileNotFoundException { - - boolean outDated = false; - - if (options.getReloading() || (servletClass == null)) { - try { - synchronized (this) { - - // Synchronizing on jsw enables simultaneous - // compilations of different pages, but not the - // same page. - outDated = compiler.isOutDated(); - if (outDated) { - compiler.compile(); - } - - if ((servletClass == null) || outDated) { - URL [] urls = new URL[1]; - File outputDir = - new File(normalize(ctxt.getOutputDir())); - urls[0] = outputDir.toURL(); - loader = new JasperLoader - (urls,ctxt.getServletClassName(), - parentClassLoader, permissionCollection, - codeSource); - servletClass = loader.loadClass - (Constants.JSP_PACKAGE_NAME + "." - + ctxt.getServletClassName()); - } - - } - } catch (FileNotFoundException ex) { - compiler.removeGeneratedFiles(); - throw ex; - } catch (ClassNotFoundException cex) { - throw new JasperException( - Constants.getString("jsp.error.unable.load"),cex); - } catch (MalformedURLException mue) { - throw new JasperException( - Constants.getString("jsp.error.unable.load"),mue); - } catch (JasperException ex) { - throw ex; - } catch (Exception ex) { - throw new JasperException - (Constants.getString("jsp.error.unable.compile"), ex); - } - } - - return outDated; - } - - - /** - * Return a context-relative path, beginning with a "/", that represents - * the canonical version of the specified path after ".." and "." elements - * are resolved out. If the specified path attempts to go outside the - * boundaries of the current context (i.e. too many ".." path elements - * are present), return <code>null</code> instead. - * - * @param path Path to be normalized - */ - protected String normalize(String path) { - - if (path == null) { - return null; - } - - String normalized = path; - - // Normalize the slashes and add leading slash if necessary - if (normalized.indexOf('\\') >= 0) { - normalized = normalized.replace('\\', '/'); - } - if (!normalized.startsWith("/")) { - normalized = "/" + normalized; - } - - // Resolve occurrences of "//" in the normalized path - while (true) { - int index = normalized.indexOf("//"); - if (index < 0) { - break; - } - normalized = normalized.substring(0, index) + - normalized.substring(index + 1); - } - - // Resolve occurrences of "/./" in the normalized path - while (true) { - int index = normalized.indexOf("/./"); - if (index < 0) { - break; - } - normalized = normalized.substring(0, index) + - normalized.substring(index + 2); - } - - // Resolve occurrences of "/../" in the normalized path - while (true) { - int index = normalized.indexOf("/../"); - if (index < 0) { - break; - } - if (index == 0) { - return (null); // Trying to go outside our context - } - int index2 = normalized.lastIndexOf('/', index - 1); - normalized = normalized.substring(0, index2) + - normalized.substring(index + 3); - } - - // Return the normalized path that we have completed - return (normalized); - } }
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>