What does use tomcat now? Can't we align instead of forking? BTW about dependeny of tomee-juli it should be optional not provided since it can be not used in several cases (tomee-embedded can exclude it typically)
Romain Manni-Bucau Twitter: @rmannibucau Blog: http://rmannibucau.wordpress.com/ LinkedIn: http://fr.linkedin.com/in/rmannibucau Github: https://github.com/rmannibucau ---------- Forwarded message ---------- From: <[email protected]> Date: 2014-05-23 13:25 GMT+02:00 Subject: svn commit: r1597062 - in /tomee/tomee/trunk/tomee: tomee-juli/ tomee-juli/pom.xml tomee-loader/src/main/java/org/apache/tomee/loader/TomEEJarScanner.java To: [email protected] Author: andygumbrecht Date: Fri May 23 11:25:51 2014 New Revision: 1597062 URL: http://svn.apache.org/r1597062 Log: Tomcat removed Matcher code, not good for a public API tomee-juli is required for tomee-loader, so should be provided. Modified: tomee/tomee/trunk/tomee/tomee-juli/ (props changed) tomee/tomee/trunk/tomee/tomee-juli/pom.xml tomee/tomee/trunk/tomee/tomee-loader/src/main/java/org/apache/tomee/loader/TomEEJarScanner.java Propchange: tomee/tomee/trunk/tomee/tomee-juli/ ------------------------------------------------------------------------------ --- svn:ignore (added) +++ svn:ignore Fri May 23 11:25:51 2014 @@ -0,0 +1,3 @@ +*.iml +target +dependency-reduced-pom.xml Modified: tomee/tomee/trunk/tomee/tomee-juli/pom.xml URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/tomee/tomee-juli/pom.xml?rev=1597062&r1=1597061&r2=1597062&view=diff ============================================================================== --- tomee/tomee/trunk/tomee/tomee-juli/pom.xml (original) +++ tomee/tomee/trunk/tomee/tomee-juli/pom.xml Fri May 23 11:25:51 2014 @@ -34,7 +34,7 @@ <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-juli</artifactId> <version>${tomcat.version}</version> - <optional>true</optional> + <scope>provided</scope> </dependency> <dependency> <groupId>log4j</groupId> @@ -53,7 +53,6 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> - <version>2.3</version> <executions> <execution> <id>tomee-juli</id> Modified: tomee/tomee/trunk/tomee/tomee-loader/src/main/java/org/apache/tomee/loader/TomEEJarScanner.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/tomee/tomee-loader/src/main/java/org/apache/tomee/loader/TomEEJarScanner.java?rev=1597062&r1=1597061&r2=1597062&view=diff ============================================================================== --- tomee/tomee/trunk/tomee/tomee-loader/src/main/java/org/apache/tomee/loader/TomEEJarScanner.java (original) +++ tomee/tomee/trunk/tomee/tomee-loader/src/main/java/org/apache/tomee/loader/TomEEJarScanner.java Fri May 23 11:25:51 2014 @@ -34,7 +34,6 @@ import org.apache.openejb.util.URLs; import org.apache.openejb.util.reflection.Reflections; import org.apache.tomcat.JarScannerCallback; import org.apache.tomcat.util.descriptor.XmlErrorHandler; -import org.apache.tomcat.util.file.Matcher; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.util.scan.Constants; import org.apache.tomcat.util.scan.StandardJarScanner; @@ -55,14 +54,22 @@ import java.net.URLConnection; import java.util.ArrayList; import java.util.HashSet; import java.util.Hashtable; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; +@SuppressWarnings("unchecked") public class TomEEJarScanner extends StandardJarScanner { private static final Log log = LogFactory.getLog(StandardJarScanner.class); + public static final String DEEP_TREE_MATCH = "**"; + private static final boolean ON_NETWARE = isNetware(); + private static final boolean ON_DOS = isDos(); + private static final String OS_NAME = System.getProperty("os.name ").toLowerCase(Locale.ENGLISH); + private static final String PATH_SEP = System.getProperty("path.separator"); + protected static final Set<String[]> DEFAULT_JARS_TO_SKIP; /** @@ -99,7 +106,7 @@ public class TomEEJarScanner extends Sta final Set<String[]> ignoredJarsTokens = new HashSet<String[]>(); for (final String pattern : defaultJarsToSkip) { - ignoredJarsTokens.add(Matcher.tokenizePathAsArray(pattern)); + ignoredJarsTokens.add(tokenizePathAsArray(pattern)); } DEFAULT_JARS_TO_SKIP = ignoredJarsTokens; @@ -109,40 +116,41 @@ public class TomEEJarScanner extends Sta tldConfigScanStream = TldConfig.class.getDeclaredMethod("tldScanStream", InputStream.class); tldConfigScanStream.setAccessible(true); tldConfig = loader.loadClass("org.apache.catalina.startup.TldConfig$TldJarScannerCallback") - .getDeclaredFields()[0]; // there is a unique field and this way it is portable - //.getDeclaredField("this$0"); + .getDeclaredFields()[0]; // there is a unique field and this way it is portable + //.getDeclaredField("this$0"); tldConfig.setAccessible(true); final Class<?> tldLocationsCache = loader.loadClass("org.apache.jasper.compiler.TldLocationsCache"); tldLocationScanStream = tldLocationsCache.getDeclaredMethod("tldScanStream", String.class, String.class, InputStream.class); tldLocationScanStream.setAccessible(true); tldLocationCache = loader.loadClass("org.apache.jasper.compiler.TldLocationsCache$TldJarScannerCallback") - .getDeclaredFields()[0]; + .getDeclaredFields()[0]; tldLocationCache.setAccessible(true); // init server cache SERVER_URLS = TldScanner.scan(TomEEJarScanner.class.getClassLoader()); final Context fakeWebApp = (Context) Proxy.newProxyInstance(loader, new Class<?>[]{Context.class}, - new InvocationHandler() { - @Override - public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { - if ("getTldNamespaceAware".equals(method.getName())) { - return Globals.STRICT_SERVLET_COMPLIANCE; - } else if ("getTldValidation".equals(method.getName())) { - return Globals.STRICT_SERVLET_COMPLIANCE; - } else if ("getXmlValidation".equals(method.getName())) { - return Globals.STRICT_SERVLET_COMPLIANCE; - } else if ("getXmlBlockExternal".equals(method.getName())) { - return Globals.IS_SECURITY_ENABLED; - } - return null; + new InvocationHandler() { + @Override + public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { + if ("getTldNamespaceAware".equals(method.getName())) { + return Globals.STRICT_SERVLET_COMPLIANCE; + } else if ("getTldValidation".equals(method.getName())) { + return Globals.STRICT_SERVLET_COMPLIANCE; + } else if ("getXmlValidation".equals(method.getName())) { + return Globals.STRICT_SERVLET_COMPLIANCE; + } else if ("getXmlBlockExternal".equals(method.getName())) { + return Globals.IS_SECURITY_ENABLED; } - }); + return null; + } + } + ); final TldConfig config = new TldConfig(); config.lifecycleEvent(new LifecycleEvent(fakeWebApp, Lifecycle.AFTER_INIT_EVENT, null)); - final Object fakeSc = Proxy.newProxyInstance(loader, new Class<?>[]{ ServletContext.class }, new InvocationHandler() { + final Object fakeSc = Proxy.newProxyInstance(loader, new Class<?>[]{ServletContext.class}, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return null; @@ -156,9 +164,7 @@ public class TomEEJarScanner extends Sta public void run() { for (URL current : SERVER_URLS) { tldConfig(config, current); - if (tldLocationsCache != null) { - tldLocationCache(locationsCacheInstance, current); - } + tldLocationCache(locationsCacheInstance, current); } } }; @@ -171,7 +177,7 @@ public class TomEEJarScanner extends Sta TAG_LIB_URIS = (Set<String>) Reflections.get(config, "taglibUris"); LISTENERS = (ArrayList<String>) Reflections.get(config, "listeners"); - MAPPINGS= (Hashtable<String, Object>) Reflections.get(locationsCacheInstance, "mappings"); + MAPPINGS = (Hashtable<String, Object>) Reflections.get(locationsCacheInstance, "mappings"); } catch (Exception e) { throw new OpenEJBRuntimeException(e); } @@ -241,15 +247,17 @@ public class TomEEJarScanner extends Sta } catch (OpenEJBException oe) { // no-op } - } else { log.debug("This callback " + callback + " is not known and perf optim will not be available"); } + } else { + log.debug("This callback " + callback + " is not known and perf optim will not be available"); + } // Scan WEB-INF/lib final Set<String> dirList = context.getResourcePaths(Constants.WEB_INF_LIB); if (dirList != null) { for (final String path : dirList) { if (path.endsWith(Constants.JAR_EXT) && - !Matcher.matchPath(DEFAULT_JARS_TO_SKIP, - path.substring(path.lastIndexOf('/') + 1))) { + !matchPath(DEFAULT_JARS_TO_SKIP, + path.substring(path.lastIndexOf('/') + 1))) { // Need to scan this JAR URL url = null; try { @@ -291,7 +299,7 @@ public class TomEEJarScanner extends Sta // Skip JARs known not to be interesting and JARs // in WEB-INF/lib we have already scanned - if (jarName != null && !(Matcher.matchPath(DEFAULT_JARS_TO_SKIP, jarName) || url.toString().contains(Constants.WEB_INF_LIB + jarName))) { + if (jarName != null && !(matchPath(DEFAULT_JARS_TO_SKIP, jarName) || url.toString().contains(Constants.WEB_INF_LIB + jarName))) { if (log.isDebugEnabled()) { log.debug(sm.getString("jarScan.classloaderJarScan", url)); @@ -300,7 +308,7 @@ public class TomEEJarScanner extends Sta this.process(callback, url); } catch (IOException ioe) { log.warn(sm.getString( - "jarScan.classloaderFail", url), ioe); + "jarScan.classloaderFail", url), ioe); } } else { if (log.isTraceEnabled()) { @@ -454,4 +462,391 @@ public class TomEEJarScanner extends Sta return name; } + + public static boolean matchPath(Set<String[]> patternSet, String str) { + for (String[] patternTokens : patternSet) { + if (matchPath(patternTokens, tokenizePathAsArray(str), true)) { + return true; + } + } + return false; + } + + public static boolean matchPath(String[] tokenizedPattern, String[] strDirs, + boolean isCaseSensitive) { + int patIdxStart = 0; + int patIdxEnd = tokenizedPattern.length - 1; + int strIdxStart = 0; + int strIdxEnd = strDirs.length - 1; + + // up to first '**' + while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { + String patDir = tokenizedPattern[patIdxStart]; + if (patDir.equals(DEEP_TREE_MATCH)) { + break; + } + if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) { + return false; + } + patIdxStart++; + strIdxStart++; + } + if (strIdxStart > strIdxEnd) { + // String is exhausted + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { + return false; + } + } + return true; + } else { + if (patIdxStart > patIdxEnd) { + // String not exhausted, but pattern is. Failure. + return false; + } + } + + // up to last '**' + while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { + String patDir = tokenizedPattern[patIdxEnd]; + if (patDir.equals(DEEP_TREE_MATCH)) { + break; + } + if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) { + return false; + } + patIdxEnd--; + strIdxEnd--; + } + if (strIdxStart > strIdxEnd) { + // String is exhausted + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { + return false; + } + } + return true; + } + + while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { + int patIdxTmp = -1; + for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { + if (tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { + patIdxTmp = i; + break; + } + } + if (patIdxTmp == patIdxStart + 1) { + // '**/**' situation, so skip one + patIdxStart++; + continue; + } + // Find the pattern between padIdxStart & padIdxTmp in str between + // strIdxStart & strIdxEnd + int patLength = (patIdxTmp - patIdxStart - 1); + int strLength = (strIdxEnd - strIdxStart + 1); + int foundIdx = -1; + strLoop: + for (int i = 0; i <= strLength - patLength; i++) { + for (int j = 0; j < patLength; j++) { + String subPat = tokenizedPattern[patIdxStart + j + 1]; + String subStr = strDirs[strIdxStart + i + j]; + if (!match(subPat, subStr, isCaseSensitive)) { + continue strLoop; + } + } + + foundIdx = strIdxStart + i; + break; + } + + if (foundIdx == -1) { + return false; + } + + patIdxStart = patIdxTmp; + strIdxStart = foundIdx + patLength; + } + + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { + return false; + } + } + + return true; + } + + public static boolean match(String pattern, String str, + boolean caseSensitive) { + char[] patArr = pattern.toCharArray(); + char[] strArr = str.toCharArray(); + int patIdxStart = 0; + int patIdxEnd = patArr.length - 1; + int strIdxStart = 0; + int strIdxEnd = strArr.length - 1; + char ch; + + boolean containsStar = false; + for (char aPatArr : patArr) { + if (aPatArr == '*') { + containsStar = true; + break; + } + } + + if (!containsStar) { + // No '*'s, so we make a shortcut + if (patIdxEnd != strIdxEnd) { + return false; // Pattern and string do not have the same size + } + for (int i = 0; i <= patIdxEnd; i++) { + ch = patArr[i]; + if (ch != '?') { + if (different(caseSensitive, ch, strArr[i])) { + return false; // Character mismatch + } + } + } + return true; // String matches against pattern + } + + if (patIdxEnd == 0) { + return true; // Pattern contains only '*', which matches anything + } + + // Process characters before first star + while (true) { + ch = patArr[patIdxStart]; + if (ch == '*' || strIdxStart > strIdxEnd) { + break; + } + if (ch != '?') { + if (different(caseSensitive, ch, strArr[strIdxStart])) { + return false; // Character mismatch + } + } + patIdxStart++; + strIdxStart++; + } + if (strIdxStart > strIdxEnd) { + // All characters in the string are used. Check if only '*'s are + // left in the pattern. If so, we succeeded. Otherwise failure. + return allStars(patArr, patIdxStart, patIdxEnd); + } + + // Process characters after last star + while (true) { + ch = patArr[patIdxEnd]; + if (ch == '*' || strIdxStart > strIdxEnd) { + break; + } + if (ch != '?') { + if (different(caseSensitive, ch, strArr[strIdxEnd])) { + return false; // Character mismatch + } + } + patIdxEnd--; + strIdxEnd--; + } + if (strIdxStart > strIdxEnd) { + // All characters in the string are used. Check if only '*'s are + // left in the pattern. If so, we succeeded. Otherwise failure. + return allStars(patArr, patIdxStart, patIdxEnd); + } + + // process pattern between stars. padIdxStart and patIdxEnd point + // always to a '*'. + while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { + int patIdxTmp = -1; + for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { + if (patArr[i] == '*') { + patIdxTmp = i; + break; + } + } + if (patIdxTmp == patIdxStart + 1) { + // Two stars next to each other, skip the first one. + patIdxStart++; + continue; + } + // Find the pattern between padIdxStart & padIdxTmp in str between + // strIdxStart & strIdxEnd + int patLength = (patIdxTmp - patIdxStart - 1); + int strLength = (strIdxEnd - strIdxStart + 1); + int foundIdx = -1; + strLoop: + for (int i = 0; i <= strLength - patLength; i++) { + for (int j = 0; j < patLength; j++) { + ch = patArr[patIdxStart + j + 1]; + if (ch != '?') { + if (different(caseSensitive, ch, + strArr[strIdxStart + i + j])) { + continue strLoop; + } + } + } + + foundIdx = strIdxStart + i; + break; + } + + if (foundIdx == -1) { + return false; + } + + patIdxStart = patIdxTmp; + strIdxStart = foundIdx + patLength; + } + + // All characters in the string are used. Check if only '*'s are left + // in the pattern. If so, we succeeded. Otherwise failure. + return allStars(patArr, patIdxStart, patIdxEnd); + } + + private static boolean allStars(char[] chars, int start, int end) { + for (int i = start; i <= end; ++i) { + if (chars[i] != '*') { + return false; + } + } + return true; + } + + private static boolean different( + boolean caseSensitive, char ch, char other) { + return caseSensitive + ? ch != other + : Character.toUpperCase(ch) != Character.toUpperCase(other); + } + + public static String[] tokenizePathAsArray(String path) { + if (log.isTraceEnabled()) { + log.trace(sm.getString("matcher.tokenize", path)); + } + String root = null; + if (isAbsolutePath(path)) { + String[] s = dissect(path); + root = s[0]; + path = s[1]; + } + char sep = File.separatorChar; + int start = 0; + int len = path.length(); + int count = 0; + for (int pos = 0; pos < len; pos++) { + if (path.charAt(pos) == sep) { + if (pos != start) { + count++; + } + start = pos + 1; + } + } + if (len != start) { + count++; + } + String[] l = new String[count + ((root == null) ? 0 : 1)]; + + if (root != null) { + l[0] = root; + count = 1; + } else { + count = 0; + } + start = 0; + for (int pos = 0; pos < len; pos++) { + if (path.charAt(pos) == sep) { + if (pos != start) { + String tok = path.substring(start, pos); + l[count++] = tok; + } + start = pos + 1; + } + } + if (len != start) { + String tok = path.substring(start); + l[count/*++*/] = tok; + } + return l; + } + + private static String[] dissect(String path) { + char sep = File.separatorChar; + path = path.replace('/', sep).replace('\\', sep); + + String root; + int colon = path.indexOf(':'); + if (colon > 0 && (ON_DOS || ON_NETWARE)) { + + int next = colon + 1; + root = path.substring(0, next); + char[] ca = path.toCharArray(); + root += sep; + //remove the initial separator; the root has it. + next = (ca[next] == sep) ? next + 1 : next; + + StringBuilder sbPath = new StringBuilder(); + // Eliminate consecutive slashes after the drive spec: + for (int i = next; i < ca.length; i++) { + if (ca[i] != sep || ca[i - 1] != sep) { + sbPath.append(ca[i]); + } + } + path = sbPath.toString(); + } else if (path.length() > 1 && path.charAt(1) == sep) { + // UNC drive + int nextsep = path.indexOf(sep, 2); + nextsep = path.indexOf(sep, nextsep + 1); + root = (nextsep > 2) ? path.substring(0, nextsep + 1) : path; + path = path.substring(root.length()); + } else { + root = File.separator; + path = path.substring(1); + } + return new String[]{root, path}; + } + + private static boolean isAbsolutePath(String filename) { + int len = filename.length(); + if (len == 0) { + return false; + } + char sep = File.separatorChar; + filename = filename.replace('/', sep).replace('\\', sep); + char c = filename.charAt(0); + if (!(ON_DOS || ON_NETWARE)) { + return (c == sep); + } + if (c == sep) { + // CheckStyle:MagicNumber OFF + if (!(ON_DOS && len > 4 && filename.charAt(1) == sep)) { + return false; + } + // CheckStyle:MagicNumber ON + int nextsep = filename.indexOf(sep, 2); + return nextsep > 2 && nextsep + 1 < len; + } + int colon = filename.indexOf(':'); + return (Character.isLetter(c) && colon == 1 + && filename.length() > 2 && filename.charAt(2) == sep) + || (ON_NETWARE && colon > 0); + } + + /** + * Determines if our OS is Netware. + * + * @return true if we run on Netware + */ + private static boolean isNetware() { + return OS_NAME.contains("netware"); + } + + /** + * Determines if our OS is DOS. + * + * @return true if we run on DOS + */ + private static boolean isDos() { + return PATH_SEP.equals(";") && !isNetware(); + } }
