Author: markt
Date: Tue Nov 20 16:54:28 2018
New Revision: 1847028
URL: http://svn.apache.org/viewvc?rev=1847028&view=rev
Log:
Complete the fix for https://bz.apache.org/bugzilla/show_bug.cgi?id=53737
Extend JspC to include support for resource JARs
Modified:
tomcat/trunk/java/org/apache/jasper/JspC.java
tomcat/trunk/java/org/apache/jasper/servlet/JspCServletContext.java
tomcat/trunk/test/org/apache/jasper/servlet/TestJspCServletContext.java
tomcat/trunk/webapps/docs/changelog.xml
Modified: tomcat/trunk/java/org/apache/jasper/JspC.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/JspC.java?rev=1847028&r1=1847027&r2=1847028&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/jasper/JspC.java (original)
+++ tomcat/trunk/java/org/apache/jasper/JspC.java Tue Nov 20 16:54:28 2018
@@ -37,7 +37,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.concurrent.Callable;
@@ -1398,41 +1397,48 @@ public class JspC extends Task implement
* Locate all jsp files in the webapp. Used if no explicit
* jsps are specified.
* @param base Base path
+ *
+ * @deprecated This will be removed in Tomcat 10. Use {@link #scanFiles()}
*/
- public void scanFiles( File base ) {
- Stack<String> dirs = new Stack<>();
- dirs.push(base.toString());
+ @Deprecated
+ public void scanFiles(File base) {
+ scanFiles();
+ }
+
+ /**
+ * Locate all jsp files in the webapp. Used if no explicit jsps are
+ * specified. Scan is performed via the ServletContext and will include any
+ * JSPs located in resource JARs.
+ */
+ public void scanFiles() {
// Make sure default extensions are always included
if ((getExtensions() == null) || (getExtensions().size() < 2)) {
addExtension("jsp");
addExtension("jspx");
}
- while (!dirs.isEmpty()) {
- String s = dirs.pop();
- File f = new File(s);
- if (f.exists() && f.isDirectory()) {
- String[] files = f.list();
- String ext;
- for (int i = 0; (files != null) && i < files.length; i++) {
- File f2 = new File(s, files[i]);
- if (f2.isDirectory()) {
- dirs.push(f2.getPath());
- } else {
- String path = f2.getPath();
- String uri = path.substring(uriRoot.length());
- ext = files[i].substring(files[i].lastIndexOf('.') +1);
- if (getExtensions().contains(ext) ||
- jspConfig.isJspPage(uri)) {
- pages.add(path);
- }
- }
+ scanFilesInternal("/");
+ }
+
+
+ private void scanFilesInternal(String input) {
+ Set<String> paths = context.getResourcePaths(input);
+ for (String path : paths) {
+ if (path.endsWith("/")) {
+ scanFilesInternal(input.substring(0, input.length() -1) +
path);
+ } else if (jspConfig.isJspPage(input + path)) {
+ pages.add(path);
+ } else {
+ String ext = path.substring(path.lastIndexOf('.') + 1);
+ if (extensions.contains(ext)) {
+ pages.add(input + path.substring(1));
}
}
}
}
+
/**
* Executes the compilation.
*/
@@ -1474,20 +1480,15 @@ public class JspC extends Task implement
// No explicit pages, we'll process all .jsp in the webapp
if (pages.size() == 0) {
- scanFiles(uriRootF);
- }
-
- initWebXml();
-
- int errorCount = 0;
- long start = System.currentTimeMillis();
-
- ExecutorService threadPool =
Executors.newFixedThreadPool(threadCount);
- ExecutorCompletionService<Void> service = new
ExecutorCompletionService<>(threadPool);
- try {
- int pageCount = pages.size();
+ scanFiles();
+ } else {
+ // Ensure pages are all relative to the uriRoot.
+ // Those that are not will trigger an error later. The error
+ // could be detected earlier but isn't to support the use case
+ // when failFast is not used.
+ for (int i = 0; i < pages.size(); i++) {
+ String nextjsp = pages.get(i);
- for (String nextjsp : pages) {
File fjsp = new File(nextjsp);
if (!fjsp.isAbsolute()) {
fjsp = new File(uriRootF, nextjsp);
@@ -1506,6 +1507,20 @@ public class JspC extends Task implement
if (nextjsp.startsWith("." + File.separatorChar)) {
nextjsp = nextjsp.substring(2);
}
+ pages.set(i, nextjsp);
+ }
+ }
+
+ initWebXml();
+
+ int errorCount = 0;
+ long start = System.currentTimeMillis();
+
+ ExecutorService threadPool =
Executors.newFixedThreadPool(threadCount);
+ ExecutorCompletionService<Void> service = new
ExecutorCompletionService<>(threadPool);
+ try {
+ int pageCount = pages.size();
+ for (String nextjsp : pages) {
service.submit(new ProcessFile(nextjsp));
}
JasperException reportableError = null;
Modified: tomcat/trunk/java/org/apache/jasper/servlet/JspCServletContext.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/servlet/JspCServletContext.java?rev=1847028&r1=1847027&r2=1847028&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/jasper/servlet/JspCServletContext.java
(original)
+++ tomcat/trunk/java/org/apache/jasper/servlet/JspCServletContext.java Tue Nov
20 16:54:28 2018
@@ -22,12 +22,16 @@ import java.io.InputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
@@ -49,10 +53,12 @@ import org.apache.jasper.Constants;
import org.apache.jasper.JasperException;
import org.apache.jasper.compiler.Localizer;
import org.apache.jasper.runtime.ExceptionUtils;
+import org.apache.tomcat.Jar;
import org.apache.tomcat.JarScanType;
import org.apache.tomcat.util.descriptor.web.FragmentJarScannerCallback;
import org.apache.tomcat.util.descriptor.web.WebXml;
import org.apache.tomcat.util.descriptor.web.WebXmlParser;
+import org.apache.tomcat.util.scan.JarFactory;
import org.apache.tomcat.util.scan.StandardJarScanFilter;
import org.apache.tomcat.util.scan.StandardJarScanner;
@@ -100,8 +106,12 @@ public class JspCServletContext implemen
private WebXml webXml;
+ private List<URL> resourceJARs;
+
+
private JspConfigDescriptor jspConfigDescriptor;
+
/**
* Web application class loader.
*/
@@ -167,11 +177,45 @@ public class JspCServletContext implemen
Map<String, WebXml> fragments = scanForFragments(webXmlParser);
Set<WebXml> orderedFragments = WebXml.orderWebFragments(webXml,
fragments, this);
+ // Find resource JARs
+ this.resourceJARs = scanForResourceJARs(orderedFragments,
fragments.values());
+
// JspC is not affected by annotations so skip that processing,
proceed to merge
webXml.merge(orderedFragments);
return webXml;
}
+
+ private List<URL> scanForResourceJARs(Set<WebXml> orderedFragments,
Collection<WebXml> fragments)
+ throws JasperException {
+ List<URL> resourceJars = new ArrayList<>();
+ // Build list of potential resource JARs. Use same ordering as
ContextConfig
+ Set<WebXml> resourceFragments = new LinkedHashSet<>();
+ for (WebXml fragment : orderedFragments) {
+ resourceFragments.add(fragment);
+ }
+ for (WebXml fragment : fragments) {
+ if (!resourceFragments.contains(fragment)) {
+ resourceFragments.add(fragment);
+ }
+ }
+
+ for (WebXml resourceFragment : resourceFragments) {
+ try (Jar jar = JarFactory.newInstance(resourceFragment.getURL())) {
+ if (jar.exists("META-INF/resources/")) {
+ // This is a resource JAR
+ resourceJars.add(resourceFragment.getURL());
+ }
+ jar.close();
+ } catch (IOException ioe) {
+ throw new JasperException(ioe);
+ }
+ }
+
+ return resourceJars;
+ }
+
+
private Map<String, WebXml> scanForFragments(WebXmlParser webXmlParser)
throws JasperException {
StandardJarScanner scanner = new StandardJarScanner();
// TODO - enabling this means initializing the classloader first in
JspC
@@ -337,15 +381,34 @@ public class JspCServletContext implemen
@Override
public URL getResource(String path) throws MalformedURLException {
- if (!path.startsWith("/"))
- throw new MalformedURLException("Path '" + path +
- "' does not start with '/'");
- URL url = new URL(myResourceBaseURL, path.substring(1));
+ if (!path.startsWith("/")) {
+ throw new MalformedURLException("Path '" + path + "' does not
start with '/'");
+ }
+
+ // Strip leading '/'
+ path = path.substring(1);
+
+ URL url = new URL(myResourceBaseURL, path);
try (InputStream is = url.openStream()) {
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
url = null;
}
+
+ // During initialisation, getResource() is called before resourceJARs
is
+ // initialised
+ if (url == null && resourceJARs != null) {
+ String jarPath = "META-INF/resources/" + path;
+ for (URL jarUrl : resourceJARs) {
+ try (Jar jar = JarFactory.newInstance(jarUrl)) {
+ if (jar.exists(jarPath)) {
+ return new URL(jar.getURL(jarPath));
+ }
+ } catch (IOException ioe) {
+ // Ignore
+ }
+ }
+ }
return url;
}
@@ -377,27 +440,57 @@ public class JspCServletContext implemen
public Set<String> getResourcePaths(String path) {
Set<String> thePaths = new HashSet<>();
- if (!path.endsWith("/"))
+ if (!path.endsWith("/")) {
path += "/";
+ }
String basePath = getRealPath(path);
- if (basePath == null)
- return thePaths;
- File theBaseDir = new File(basePath);
- if (!theBaseDir.exists() || !theBaseDir.isDirectory())
- return thePaths;
- String theFiles[] = theBaseDir.list();
- if (theFiles == null) {
- return thePaths;
- }
- for (int i = 0; i < theFiles.length; i++) {
- File testFile = new File(basePath + File.separator + theFiles[i]);
- if (testFile.isFile())
- thePaths.add(path + theFiles[i]);
- else if (testFile.isDirectory())
- thePaths.add(path + theFiles[i] + "/");
+ if (basePath != null) {
+ File theBaseDir = new File(basePath);
+ if (theBaseDir.isDirectory()) {
+ String theFiles[] = theBaseDir.list();
+ if (theFiles != null) {
+ for (int i = 0; i < theFiles.length; i++) {
+ File testFile = new File(basePath + File.separator +
theFiles[i]);
+ if (testFile.isFile()) {
+ thePaths.add(path + theFiles[i]);
+ } else if (testFile.isDirectory()) {
+ thePaths.add(path + theFiles[i] + "/");
+ }
+ }
+ }
+ }
}
- return thePaths;
+ // During initialisation, getResourcePaths() is called before
+ // resourceJARs is initialised
+ if (resourceJARs != null) {
+ String jarPath = "META-INF/resources" + path;
+ for (URL jarUrl : resourceJARs) {
+ try (Jar jar = JarFactory.newInstance(jarUrl)) {
+ jar.nextEntry();
+ for (String entryName = jar.getEntryName();
+ entryName != null;
+ jar.nextEntry(), entryName = jar.getEntryName()) {
+ if (entryName.startsWith(jarPath) &&
+ entryName.length() > jarPath.length()) {
+ // Let the Set implementation handle duplicates
+ int sep = entryName.indexOf("/", jarPath.length());
+ if (sep < 0) {
+ // This is a file
+
thePaths.add(entryName.substring(jarPath.length() - 1));
+ } else {
+ // This is a directory
+
thePaths.add(entryName.substring(jarPath.length() - 1, sep + 1));
+ }
+ }
+ }
+ } catch (IOException e) {
+ log(e.getMessage(), e);
+ }
+ }
+ }
+
+ return thePaths;
}
Modified:
tomcat/trunk/test/org/apache/jasper/servlet/TestJspCServletContext.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/jasper/servlet/TestJspCServletContext.java?rev=1847028&r1=1847027&r2=1847028&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/jasper/servlet/TestJspCServletContext.java
(original)
+++ tomcat/trunk/test/org/apache/jasper/servlet/TestJspCServletContext.java Tue
Nov 20 16:54:28 2018
@@ -19,6 +19,7 @@ package org.apache.jasper.servlet;
import java.io.File;
import java.util.Collection;
import java.util.Iterator;
+import java.util.Set;
import javax.servlet.descriptor.JspConfigDescriptor;
import javax.servlet.descriptor.JspPropertyGroupDescriptor;
@@ -131,4 +132,25 @@ public class TestJspCServletContext {
Assert.assertEquals(4, context.getEffectiveMajorVersion());
Assert.assertEquals(0, context.getEffectiveMinorVersion());
}
+
+
+ @Test
+ public void testResourceJARs() throws Exception {
+ File appDir = new File("test/webapp-fragments");
+ JspCServletContext context = new JspCServletContext(
+ null, appDir.toURI().toURL(), null, false, false);
+
+ Set<String> paths = context.getResourcePaths("/");
+ Assert.assertEquals(paths.size(), 10);
+ Assert.assertTrue(paths.contains("/WEB-INF/"));
+ Assert.assertTrue(paths.contains("/folder/"));
+ Assert.assertTrue(paths.contains("/'singlequote.jsp"));
+ Assert.assertTrue(paths.contains("/'singlequote2.jsp"));
+ Assert.assertTrue(paths.contains("/bug51396.jsp"));
+ Assert.assertTrue(paths.contains("/jndi.jsp"));
+ Assert.assertTrue(paths.contains("/resourceA.jsp"));
+ Assert.assertTrue(paths.contains("/resourceB.jsp"));
+ Assert.assertTrue(paths.contains("/resourceF.jsp"));
+ Assert.assertTrue(paths.contains("/warDirContext.jsp"));
+ }
}
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1847028&r1=1847027&r2=1847028&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Tue Nov 20 16:54:28 2018
@@ -136,6 +136,10 @@
Update the Eclipse Compiler for Java to 4.9. Additional patch by Lukasz
Jader. (markt)
</update>
+ <add>
+ <bug>53737</bug>: Extend JspC, the precompilation tool, to include
+ support for resource JARs. (markt)
+ </add>
</changelog>
</subsection>
<subsection name="Web applications">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]