Index: java/org/apache/jasper/JspCompilationContext.java =================================================================== --- java/org/apache/jasper/JspCompilationContext.java (revision 1125437) +++ java/org/apache/jasper/JspCompilationContext.java (working copy) @@ -295,7 +295,7 @@ // May not be in a JAR in some IDE environments result = context.getResource(canonicalURI(res)); } - } else if (res.startsWith("jar:file:")) { + } else if (res.startsWith("jar:jndi:")) { // This is a tag file packaged in a jar that is being checked // for a dependency result = new URL(res); @@ -385,14 +385,14 @@ return jspUri; } - public long getJspLastModified() { + public Long getLastModified(String resource) { long result = -1; URLConnection uc = null; try { - URL jspUrl = getResource(getJspFile()); + URL jspUrl = getResource(resource); if (jspUrl == null) { incrementRemoved(); - return result; + return Long.valueOf(result); } uc = jspUrl.openConnection(); if (uc instanceof JarURLConnection) { @@ -419,7 +419,7 @@ } } } - return result; + return Long.valueOf(result); } public boolean isTagFile() { Index: java/org/apache/jasper/compiler/Compiler.java =================================================================== --- java/org/apache/jasper/compiler/Compiler.java (revision 1125437) +++ java/org/apache/jasper/compiler/Compiler.java (working copy) @@ -27,7 +27,8 @@ import java.net.URL; import java.net.URLConnection; import java.util.Iterator; -import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import org.apache.jasper.JasperException; import org.apache.jasper.JspCompilationContext; @@ -370,6 +371,9 @@ try { String[] smap = generateJava(); + File javaFile = new File(ctxt.getServletJavaFileName()); + Long jspLastModified = ctxt.getLastModified(ctxt.getJspFile()); + javaFile.setLastModified(jspLastModified.longValue()); if (compileClass) { generateClass(smap); // Fix for bugzilla 41606 @@ -377,8 +381,12 @@ String targetFileName = ctxt.getClassFileName(); if (targetFileName != null) { File targetFile = new File(targetFileName); - if (targetFile.exists() && jsw != null) { - jsw.setServletClassLastModifiedTime(targetFile.lastModified()); + if (targetFile.exists()) { + targetFile.setLastModified(jspLastModified.longValue()); + if (jsw != null) { + jsw.setServletClassLastModifiedTime( + jspLastModified.longValue()); + } } } } @@ -440,8 +448,8 @@ jsw.setLastModificationTest(System.currentTimeMillis()); } - long jspRealLastModified = ctxt.getJspLastModified(); - if (jspRealLastModified < 0) { + Long jspRealLastModified = ctxt.getLastModified(ctxt.getJspFile()); + if (jspRealLastModified.longValue() < 0) { // Something went wrong - assume modification return true; } @@ -463,7 +471,7 @@ if (checkClass && jsw != null) { jsw.setServletClassLastModifiedTime(targetLastModified); } - if (targetLastModified < jspRealLastModified) { + if (targetLastModified != jspRealLastModified.longValue()) { if (log.isDebugEnabled()) { log.debug("Compiler: outdated: " + targetFile + " " + targetLastModified); @@ -477,16 +485,16 @@ return false; } - List depends = jsw.getDependants(); + Map depends = jsw.getDependants(); if (depends == null) { return false; } - Iterator it = depends.iterator(); + Iterator> it = depends.entrySet().iterator(); while (it.hasNext()) { - String include = it.next(); + Entry include = it.next(); try { - URL includeUrl = ctxt.getResource(include); + URL includeUrl = ctxt.getResource(include.getKey()); if (includeUrl == null) { return true; } @@ -501,7 +509,7 @@ } iuc.getInputStream().close(); - if (includeLastModified > targetLastModified) { + if (includeLastModified != include.getValue().longValue()) { return true; } } catch (Exception e) { Index: java/org/apache/jasper/compiler/Generator.java =================================================================== --- java/org/apache/jasper/compiler/Generator.java (revision 1125437) +++ java/org/apache/jasper/compiler/Generator.java (working copy) @@ -34,6 +34,8 @@ import java.util.Hashtable; import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.TimeZone; import java.util.Vector; @@ -525,20 +527,23 @@ out.println(); // Static data for getDependants() - out.printil("private static java.util.List _jspx_dependants;"); + out.printil("private static java.util.Map _jspx_dependants;"); out.println(); - List dependants = pageInfo.getDependants(); - Iterator iter = dependants.iterator(); + Map dependants = pageInfo.getDependants(); + Iterator> iter = dependants.entrySet().iterator(); if (!dependants.isEmpty()) { out.printil("static {"); out.pushIndent(); - out.printin("_jspx_dependants = new java.util.ArrayList("); + out.printin("_jspx_dependants = new java.util.HashMap("); out.print("" + dependants.size()); out.println(");"); while (iter.hasNext()) { - out.printin("_jspx_dependants.add(\""); - out.print(iter.next()); - out.println("\");"); + Entry entry = iter.next(); + out.printin("_jspx_dependants.put(\""); + out.print(entry.getKey()); + out.print("\", Long.valueOf("); + out.print(entry.getValue().toString()); + out.println("L));"); } out.popIndent(); out.printil("}"); @@ -576,7 +581,7 @@ */ private void genPreambleMethods() { // Method used to get compile time file dependencies - out.printil("public java.util.List getDependants() {"); + out.printil("public java.util.Map getDependants() {"); out.pushIndent(); out.printil("return _jspx_dependants;"); out.popIndent(); @@ -3494,6 +3499,9 @@ out.println(" * Version: " + ctxt.getServletContext().getServerInfo()); out.println(" * Generated at: " + timestampFormat.format(new Date()) + " UTC"); + out.println(" * Note: The last modified time of this file was set to"); + out.println(" * the last modified time of the source file after"); + out.println(" * generation to assit with modification tracking."); out.println(" */"); } Index: java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java =================================================================== --- java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java (revision 1125437) +++ java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java (working copy) @@ -121,7 +121,7 @@ // Add implicit TLD to dependency list if (pi != null) { - pi.addDependant(path); + pi.addDependant(path, ctxt.getLastModified(path)); } ParserUtils pu = new ParserUtils(); Index: java/org/apache/jasper/compiler/PageInfo.java =================================================================== --- java/org/apache/jasper/compiler/PageInfo.java (revision 1125437) +++ java/org/apache/jasper/compiler/PageInfo.java (working copy) @@ -21,6 +21,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.Vector; @@ -39,7 +40,7 @@ class PageInfo { private Vector imports; - private Vector dependants; + private Map dependants; private BeanRepository beanRepository; private Set varInfoNames; @@ -108,7 +109,7 @@ this.xmlPrefixMapper = new HashMap>(); this.nonCustomTagPrefixMap = new HashMap(); this.imports = new Vector(); - this.dependants = new Vector(); + this.dependants = new HashMap(); this.includePrelude = new Vector(); this.includeCoda = new Vector(); this.pluginDcls = new Vector(); @@ -146,12 +147,12 @@ return jspFile; } - public void addDependant(String d) { - if (!dependants.contains(d) && !jspFile.equals(d)) - dependants.add(d); + public void addDependant(String d, Long lastModified) { + if (!dependants.containsKey(d) && !jspFile.equals(d)) + dependants.put(d, lastModified); } - public List getDependants() { + public Map getDependants() { return dependants; } Index: java/org/apache/jasper/compiler/ParserController.java =================================================================== --- java/org/apache/jasper/compiler/ParserController.java (revision 1125437) +++ java/org/apache/jasper/compiler/ParserController.java (working copy) @@ -192,10 +192,13 @@ if (parent != null) { // Included resource, add to dependent list if (jarFile == null) { - compiler.getPageInfo().addDependant(absFileName); + compiler.getPageInfo().addDependant(absFileName, + ctxt.getLastModified(absFileName)); } else { + String entry = absFileName.substring(1); compiler.getPageInfo().addDependant( - jarResource.getEntry(absFileName.substring(1)).toString()); + jarResource.getEntry(entry).toString(), + Long.valueOf(jarFile.getEntry(entry).getTime())); } } Index: java/org/apache/jasper/compiler/TagFileProcessor.java =================================================================== --- java/org/apache/jasper/compiler/TagFileProcessor.java (revision 1125437) +++ java/org/apache/jasper/compiler/TagFileProcessor.java (working copy) @@ -21,6 +21,7 @@ import java.io.IOException; import java.util.HashMap; import java.util.Iterator; +import java.util.Map.Entry; import java.util.Vector; import javax.el.MethodExpression; @@ -586,10 +587,12 @@ try { Object tagIns = tagClazz.newInstance(); if (tagIns instanceof JspSourceDependent) { - Iterator iter = ((JspSourceDependent) tagIns) - .getDependants().iterator(); + Iterator> iter = ((JspSourceDependent) + tagIns).getDependants().entrySet().iterator(); while (iter.hasNext()) { - parentPageInfo.addDependant(iter.next()); + Entry entry = iter.next(); + parentPageInfo.addDependant(entry.getKey(), + entry.getValue()); } } } catch (Exception e) { @@ -628,16 +631,26 @@ tagFileInfo.getTagInfo().getTagLibrary().getURI()); JarResource jarResource = location.getJarResource(); if (jarResource != null) { - // Add TLD - pageInfo.addDependant(jarResource.getEntry(location.getName()).toString()); - // Add Tag - pageInfo.addDependant(jarResource.getEntry(tagFilePath.substring(1)).toString()); + try { + // Add TLD + pageInfo.addDependant(jarResource.getEntry(location.getName()).toString(), + Long.valueOf(jarResource.getJarFile().getEntry(location.getName()).getTime())); + // Add Tag + pageInfo.addDependant(jarResource.getEntry(tagFilePath.substring(1)).toString(), + Long.valueOf(jarResource.getJarFile().getEntry(tagFilePath.substring(1)).getTime())); + } catch (IOException ioe) { + throw new JasperException(ioe); + } } else { - pageInfo.addDependant(tagFilePath); + pageInfo.addDependant(tagFilePath, + compiler.getCompilationContext().getLastModified( + tagFilePath)); } } else { - pageInfo.addDependant(tagFilePath); + pageInfo.addDependant(tagFilePath, + compiler.getCompilationContext().getLastModified( + tagFilePath)); } Class c = loadTagFile(compiler, tagFilePath, n.getTagInfo(), pageInfo); Index: java/org/apache/jasper/compiler/TagLibraryInfoImpl.java =================================================================== --- java/org/apache/jasper/compiler/TagLibraryInfoImpl.java (revision 1125437) +++ java/org/apache/jasper/compiler/TagLibraryInfoImpl.java (working copy) @@ -170,7 +170,8 @@ // Add TLD to dependency list PageInfo pageInfo = ctxt.createCompiler().getPageInfo(); if (pageInfo != null) { - pageInfo.addDependant(tldName); + pageInfo.addDependant(tldName, + ctxt.getLastModified(tldName)); } } else { // Tag library is packaged in JAR file Index: java/org/apache/jasper/runtime/JspSourceDependent.java =================================================================== --- java/org/apache/jasper/runtime/JspSourceDependent.java (revision 1125437) +++ java/org/apache/jasper/runtime/JspSourceDependent.java (working copy) @@ -17,7 +17,7 @@ package org.apache.jasper.runtime; -import java.util.List; +import java.util.Map; /** * Interface for tracking the source files dependencies, for the purpose @@ -31,9 +31,9 @@ public interface JspSourceDependent { /** - * Returns a list of files names that the current page has a source - * dependency on. + * Returns a map of file names and last modified time where the current page + * has a source dependency on the file. */ - public List getDependants(); + public Map getDependants(); } Index: java/org/apache/jasper/servlet/JspServletWrapper.java =================================================================== --- java/org/apache/jasper/servlet/JspServletWrapper.java (revision 1125437) +++ java/org/apache/jasper/servlet/JspServletWrapper.java (working copy) @@ -266,7 +266,7 @@ /** * Get a list of files that the current page has source dependency on. */ - public java.util.List getDependants() { + public java.util.Map getDependants() { try { Object target; if (isTagFile) { Index: webapps/docs/changelog.xml =================================================================== --- webapps/docs/changelog.xml (revision 1125437) +++ webapps/docs/changelog.xml (working copy) @@ -64,6 +64,14 @@ + + 33453: Recompile JSPs if last modified time of the source or + any of its dependencies changes either forwards or backwards. Note that + this introduces an incompatible change to the code generated for JSPs + and the work directory must be emptied before starting a Tomcat instance + that has been upgraded from 7.0.14 or earlier to 7.0.15 or later. + (markt) + 51220: Add a system property to enable tag pooling with JSPs that use a custom base class. Based on a patch by Dan Mikusa. (markt)