From c1387879724146a77536e7dff9e11fefba573faa Mon Sep 17 00:00:00 2001 From: markt Date: Fri, 4 Dec 2009 10:16:27 +0000 Subject: [PATCH] Adding the plumbing to get inputstreams for class files. These will be passed BCEL for annotation scanning. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@887146 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/catalina/startup/ContextConfig.java | 195 +++++++++++++++++++-- .../catalina/startup/LocalStrings.properties | 10 ++ 2 files changed, 192 insertions(+), 13 deletions(-) diff --git a/java/org/apache/catalina/startup/ContextConfig.java b/java/org/apache/catalina/startup/ContextConfig.java index 02da045fd..31483ef75 100644 --- a/java/org/apache/catalina/startup/ContextConfig.java +++ b/java/org/apache/catalina/startup/ContextConfig.java @@ -26,7 +26,10 @@ import java.io.IOException; import java.io.InputStream; import java.net.JarURLConnection; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; +import java.net.URLConnection; +import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -60,6 +63,8 @@ import org.apache.catalina.deploy.LoginConfig; import org.apache.catalina.deploy.SecurityConstraint; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; +import org.apache.naming.resources.DirContextURLConnection; +import org.apache.naming.resources.ResourceAttributes; import org.apache.tomcat.JarScanner; import org.apache.tomcat.JarScannerCallback; import org.apache.tomcat.util.res.StringManager; @@ -1241,8 +1246,15 @@ public class ContextConfig if (!webXml.isMetadataComplete()) { // Process /WEB-INF/classes for annotations - // TODO SERVLET3 - + URL webinfClasses; + try { + webinfClasses = + context.getServletContext().getResource("/WEB-INF/classes"); + processAnnotationsUrl(webinfClasses, webXml); + } catch (MalformedURLException e) { + log.error(sm.getString("contextConfig.webinfClassesUrl"), e); + } + // Have to process JARs for fragments Map fragments = processJarsForWebFragments(); @@ -1252,7 +1264,7 @@ public class ContextConfig // Process JARs for annotations - only need to process those // fragments we are going to use - processAnnotationsInJars(orderedFragments); + processAnnotations(orderedFragments); // Merge fragment into application if (ok) { @@ -1476,6 +1488,173 @@ public class ContextConfig return callback.getFragments(); } + protected void processAnnotations(Set fragments) { + for(WebXml fragment : fragments) { + if (!fragment.isMetadataComplete()) { + URL url = fragment.getURL(); + processAnnotationsUrl(url, fragment); + } + } + } + + protected void processAnnotationsUrl(URL url, WebXml fragment) { + if (url == null) { + // Nothing to do. + return; + } else if ("jar".equals(url.getProtocol())) { + processAnnotationsJar(url, fragment); + } else if ("jndi".equals(url.getProtocol())) { + processAnnotationsJndi(url, fragment); + } else if ("file".equals(url.getProtocol())) { + try { + processAnnotationsFile(new File(url.toURI()), fragment); + } catch (URISyntaxException e) { + log.error(sm.getString("contextConfig.fileUrl", url), e); + } + } else { + log.error(sm.getString("contextConfig.unknownUrlProtocol", + url.getProtocol(), url)); + } + + } + + + protected void processAnnotationsJar(URL url, WebXml fragment) { + JarFile jarFile = null; + + try { + URLConnection urlConn = url.openConnection(); + JarURLConnection jarUrlConn; + if (!(urlConn instanceof JarURLConnection)) { + // This should never happen + sm.getString("contextConfig.jarUrl", url); + return; + } + + jarUrlConn = (JarURLConnection) urlConn; + jarUrlConn.setUseCaches(false); + jarFile = jarUrlConn.getJarFile(); + + Enumeration jarEntries = jarFile.entries(); + while (jarEntries.hasMoreElements()) { + JarEntry jarEntry = jarEntries.nextElement(); + String entryName = jarEntry.getName(); + if (entryName.endsWith(".class")) { + InputStream is = null; + try { + is = jarFile.getInputStream(jarEntry); + processAnnotationsStream(is, fragment); + } catch (IOException e) { + log.error(sm.getString("contextConfig.inputStreamJar", + entryName, url),e); + } finally { + if (is != null) { + try { + is.close(); + } catch (Throwable t) { + // ignore + } + } + } + } + } + } catch (IOException e) { + log.error(sm.getString("contextConfig.jarFile", url), e); + } finally { + if (jarFile != null) { + try { + jarFile.close(); + } catch (Throwable t) { + // ignore + } + } + } + } + + + protected void processAnnotationsJndi(URL url, WebXml fragment) { + try { + URLConnection urlConn = url.openConnection(); + DirContextURLConnection dcUrlConn; + if (!(urlConn instanceof DirContextURLConnection)) { + // This should never happen + sm.getString("contextConfig.jndiUrl", url); + return; + } + + dcUrlConn = (DirContextURLConnection) urlConn; + dcUrlConn.setUseCaches(false); + + String ct = dcUrlConn.getContentType(); + if (ResourceAttributes.COLLECTION_TYPE.equals(ct)) { + // Collection + Enumeration dirs = dcUrlConn.list(); + while (dirs.hasMoreElements()) { + String dir = dirs.nextElement(); + URL dirUrl = new URL(url.toString() + '/' + dir); + processAnnotationsJndi(dirUrl, fragment); + } + + } else { + // Single file + if (url.getPath().endsWith(".class")) { + InputStream is = null; + try { + is = dcUrlConn.getInputStream(); + processAnnotationsStream(is, fragment); + } catch (IOException e) { + log.error(sm.getString("contextConfig.inputStreamJndi", + url),e); + } finally { + if (is != null) { + try { + is.close(); + } catch (Throwable t) { + // ignore + } + } + } + } + } + } catch (IOException e) { + log.error(sm.getString("contextConfig.jarFile", url), e); + } + } + + + protected void processAnnotationsFile(File file, WebXml fragment) { + + if (file.isDirectory()) { + String[] dirs = file.list(); + for (String dir : dirs) { + processAnnotationsFile(new File(file,dir), fragment); + } + } else if (file.canRead() && file.getName().endsWith(".class")) { + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + processAnnotationsStream(fis, fragment); + } catch (IOException e) { + log.error(sm.getString("contextConfig.inputStreamFile", + file.getAbsolutePath()),e); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (Throwable t) { + // ignore + } + } + } + } + } + + + protected void processAnnotationsStream(InputStream is, WebXml fragment) { + // TODO SERVLET 3 + } + + private class FragmentJarScannerCallback implements JarScannerCallback { private static final String FRAGMENT_LOCATION = @@ -1567,16 +1746,6 @@ public class ContextConfig } - protected void processAnnotationsInJars(Set fragments) { - for(WebXml fragment : fragments) { - if (!fragment.isMetadataComplete()) { - // Scan jar for annotations, add to fragment - // TODO SERVLET3 - } - } - } - - protected static class ContextErrorHandler implements ErrorHandler { diff --git a/java/org/apache/catalina/startup/LocalStrings.properties b/java/org/apache/catalina/startup/LocalStrings.properties index caafda1aa..0b27b181b 100644 --- a/java/org/apache/catalina/startup/LocalStrings.properties +++ b/java/org/apache/catalina/startup/LocalStrings.properties @@ -33,8 +33,16 @@ contextConfig.defaultError=Error processed default web.xml named {0} at {1} contextConfig.defaultMissing=No global web.xml found contextConfig.defaultPosition=Occurred at line {0} column {1} contextConfig.destroy=ContextConfig: Destroying +contextConfig.fileUrl=Unable to create a File object from the URL [{0}] contextConfig.fixDocBase=Exception fixing docBase for context [{0}] contextConfig.init=ContextConfig: Initializing +contextConfig.inputStreamFile=Unable to process file [{0}] for annotations +contextConfig.inputStreamJar=Unable to process Jar entry [{0}] from Jar [{1}] for annotations +contextConfig.inputStreamJndi=Unable to process resource element [{0}] for annotations +contextConfig.jarFile=Unable to process Jar [{0}] for annotations +contextConfig.jarUrl=The connection created for URL [{0}] was not a JarUrlConnection +contextConfig.jar=Unable to process resource [{0}] for annotations +contextConfig.jndiUrl=The connection created for URL [{0}] was not a DirContextURLConnection contextConfig.missingRealm=No Realm has been configured to authenticate against contextConfig.role.auth=WARNING: Security role name {0} used in an without being defined in a contextConfig.role.link=WARNING: Security role name {0} used in a without being defined in a @@ -42,6 +50,8 @@ contextConfig.role.runas=WARNING: Security role name {0} used in a with contextConfig.start=ContextConfig: Processing START contextConfig.stop=ContextConfig: Processing STOP contextConfig.unavailable=Marking this application unavailable due to previous error(s) +contextConfig.unknownUrlProtocol=The URL protocol [{0}] was not recognised during annotation processing. URL [{1}] was ignored. +contextConfig.webinfClassesUrl=Unable to determine URL for WEB-INF/classes contextConfig.xmlSettings=Context [{0}] will parse web.xml and web-fragment.xml files with validation:{1} and namespaceAware:{2} embedded.alreadyStarted=Embedded service has already been started embedded.noEngines=No engines have been defined yet -- 2.11.0