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();
+ }
}