You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tamaya.apache.org by an...@apache.org on 2015/01/16 15:06:38 UTC
incubator-tamaya git commit: TAMAYA-43: Added support for JBoss VFS.
Repository: incubator-tamaya
Updated Branches:
refs/heads/master 987c5a1d9 -> af21ac43e
TAMAYA-43: Added support for JBoss VFS.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/af21ac43
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/af21ac43
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/af21ac43
Branch: refs/heads/master
Commit: af21ac43e7c00aeabc5a2ba617c5ca8737b1a290
Parents: 987c5a1
Author: anatole <an...@apache.org>
Authored: Fri Jan 16 15:06:13 2015 +0100
Committer: anatole <an...@apache.org>
Committed: Fri Jan 16 15:06:30 2015 +0100
----------------------------------------------------------------------
.../resource/internal/ClasspathCollector.java | 115 ++++++++-
.../tamaya/resource/internal/VfsSupport.java | 252 +++++++++++++++++++
2 files changed, 365 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/af21ac43/modules/resources/src/main/java/org/apache/tamaya/resource/internal/ClasspathCollector.java
----------------------------------------------------------------------
diff --git a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/ClasspathCollector.java b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/ClasspathCollector.java
index 8688ce8..c47bd10 100644
--- a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/ClasspathCollector.java
+++ b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/ClasspathCollector.java
@@ -20,6 +20,8 @@ package org.apache.tamaya.resource.internal;
import java.io.File;
import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
@@ -28,6 +30,7 @@ import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
+import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.jar.JarEntry;
@@ -121,6 +124,8 @@ public class ClasspathCollector {
try {
if (isJarFile(resource)) {
result.addAll(doFindPathMatchingJarResources(resource, locator.getSubPath()));
+ } else if (resource.getProtocol().startsWith(PROTOCOL_VFSZIP)) {
+ result.addAll(findMatchingVfsResources(resource, locator.getSubPath()));
} else {
result.addAll(FileCollector.traverseAndSelectFromChildren(getFile(resource),
locator.getSubPathTokens(), 0));
@@ -194,7 +199,7 @@ public class ClasspathCollector {
String entryPath = entry.getName();
if (entryPath.startsWith(rootEntryPath)) {
String relativePath = entryPath.substring(rootEntryPath.length());
- if(relativePath.contains("/") && isFileExpression){
+ if (relativePath.contains("/") && isFileExpression) {
continue;
}
if (relativePath.matches(subPattern)) {
@@ -245,7 +250,7 @@ public class ClasspathCollector {
PROTOCOL_ZIP.equals(protocol) ||
PROTOCOL_VFSZIP.equals(protocol) ||
PROTOCOL_WSJAR.equals(protocol) ||
- (PROTOCOL_CODE_SOURCE.equals(protocol) && url.getPath().indexOf(JAR_URL_SEPARATOR) != -1));
+ (PROTOCOL_CODE_SOURCE.equals(protocol) && url.getPath().contains(JAR_URL_SEPARATOR)));
}
/**
@@ -268,4 +273,110 @@ public class ClasspathCollector {
}
}
+ /**
+ * Method that collects resources from a JBoss classloading system using Vfs.
+ * @param rootResource the root resource for evaluating its children.
+ * @param locationPattern the sub pattern that all children must mach, so they are selected.
+ * @return the resources found, never null.
+ * @throws IOException
+ */
+ private static Collection<URL> findMatchingVfsResources(
+ URL rootResource, String locationPattern) throws IOException {
+ Object root = VfsSupport.getRoot(rootResource);
+ PatternVfsVisitor visitor =
+ new PatternVfsVisitor(VfsSupport.getPath(root), locationPattern);
+ VfsSupport.visit(root, visitor);
+ return visitor.getResources();
+ }
+
+ /**
+ * Simple dynamic visitor implementation used for evaluating paths from a JBoss Vfs system.
+ */
+ private static class PatternVfsVisitor implements InvocationHandler {
+ /**
+ * The regex pattern to match agains all child resources of the root path against.
+ */
+ private final String subPattern;
+ /**
+ * The resource path before yny placeholders/whitespaces are occurring.
+ */
+ private final String rootPath;
+ /**
+ * THe resources found so far.
+ */
+ private final List<URL> resources = new LinkedList<>();
+
+ /**
+ * Creates a new visitor for cfs resources.
+ *
+ * @param rootPath the root path, until any patterns are occurring.
+ * @param subPattern the sub pattern for looking for.
+ */
+ public PatternVfsVisitor(String rootPath, String subPattern) {
+ this.subPattern = subPattern;
+ this.rootPath = (rootPath.length() == 0 || rootPath.endsWith("/") ? rootPath : rootPath + "/");
+ }
+
+ /**
+ * Method called by visitor proxy.
+ *
+ * @param proxy the proxy instance.
+ * @param method the method called.
+ * @param args any arguments.
+ * @return the result.
+ * @throws Throwable in case something goes wrong.
+ */
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ String methodName = method.getName();
+ if (Object.class.equals(method.getDeclaringClass())) {
+ if (methodName.equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0]);
+ } else if (methodName.equals("hashCode")) {
+ return System.identityHashCode(proxy);
+ }
+ } else if ("getAttributes".equals(methodName)) {
+ return VfsSupport.getVisitorAttributes();
+ } else if ("visit".equals(methodName)) {
+ visit(args[0]);
+ return null;
+ } else if ("toString".equals(methodName)) {
+ return toString();
+ }
+
+ throw new IllegalStateException("Unexpected method invocation: " + method);
+ }
+
+ /**
+ * Visitor method.
+ *
+ * @param vfsResource the vfsResource object.
+ */
+ public void visit(Object vfsResource) {
+ String subPath = VfsSupport.getPath(vfsResource).substring(this.rootPath.length());
+ if (subPath.matches(this.subPattern)) {
+ try {
+ this.resources.add(VfsSupport.getURL(vfsResource));
+ } catch (Exception e) {
+ LOG.log(Level.WARNING, "Failed to convert vfs resource to URL: " + vfsResource, e);
+ }
+ }
+ }
+
+ /**
+ * Access the resources found from Vfs during last visit.
+ *
+ * @return the resources found, not null.
+ */
+ public Collection<URL> getResources() {
+ return this.resources;
+ }
+
+ @Override
+ public String toString() {
+ return "sub-pattern: " + this.subPattern + ", resources: " + this.resources;
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/af21ac43/modules/resources/src/main/java/org/apache/tamaya/resource/internal/VfsSupport.java
----------------------------------------------------------------------
diff --git a/modules/resources/src/main/java/org/apache/tamaya/resource/internal/VfsSupport.java b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/VfsSupport.java
new file mode 100644
index 0000000..22b4f52
--- /dev/null
+++ b/modules/resources/src/main/java/org/apache/tamaya/resource/internal/VfsSupport.java
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.resource.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Internal support class dealing with JBoss VFS in the classpath.
+ * <p>
+ * This code is compatible with JBoss AS 6+ and JBoss AS 7 and
+ * WildFly 8.
+ */
+class VfsSupport {
+
+ private static final String VFS3_PKG = "org.jboss.vfs.";
+ private static final String VFS_PROTOCOL = "VFS";
+
+ private static Method methodGetRootUrl = null;
+ private static Method methodToUrl;
+ private static Method methodGetPathName;
+ private static Class<?> fileVisitorInterface;
+ private static Method methodVisit;
+ private static Field visitorAttributesField = null;
+ private static Method methodGetPhysicalFile = null;
+
+ /**
+ * Private constructor.
+ */
+ private VfsSupport(){}
+
+ /**
+ * Initialize glue reflection code for communicating with VFS systems.
+ */
+ static {
+ ClassLoader loader = VfsSupport.class.getClassLoader();
+ try {
+ Class<?> vfsClass = loader.loadClass(VFS3_PKG + VFS_PROTOCOL);
+ methodGetRootUrl = findMethod(vfsClass, "getChild", URL.class);
+ Class<?> virtualFile = loader.loadClass(VFS3_PKG + "VirtualFile");
+ methodToUrl = findMethod(virtualFile, "toURL");
+ methodGetPathName = findMethod(virtualFile, "getPathName");
+ methodGetPhysicalFile = findMethod(virtualFile, "getPhysicalFile");
+ fileVisitorInterface = loader.loadClass(VFS3_PKG + "VirtualFileVisitor");
+ methodVisit = findMethod(virtualFile, "visit", fileVisitorInterface);
+ Class<?> visitorAttributesClass = loader.loadClass(VFS3_PKG + "VisitorAttributes");
+ visitorAttributesField = findField(visitorAttributesClass, "RECURSE");
+ } catch (ClassNotFoundException ex) {
+ throw new IllegalStateException("JBoss VFS not available.", ex);
+ }
+ }
+
+ /**
+ * Visit a VFS resource with the given visitor, modeled as dynamic {@link java.lang.reflect.InvocationHandler}.
+ *
+ * @param resource the resource
+ * @param visitor the visitor.
+ * @throws IOException
+ */
+ static void visit(Object resource, InvocationHandler visitor) throws IOException {
+ Object visitorProxy = Proxy.newProxyInstance(
+ fileVisitorInterface.getClassLoader(),
+ new Class<?>[]{fileVisitorInterface}, visitor);
+ invokeVfsMethod(methodVisit, resource, visitorProxy);
+ }
+
+ /**
+ * Helper method to invoke an operation on VFS.
+ *
+ * @param method the method to invoke
+ * @param target the target instance
+ * @param args any arguments
+ * @return the result
+ * @throws IOException if something fails.
+ */
+ private static Object invokeVfsMethod(Method method, Object target, Object... args) throws IOException {
+ try {
+ return method.invoke(target, args);
+ } catch (Exception ex) {
+ throw new IOException("Failed to evaluated method: " + method, ex);
+ }
+
+ }
+
+ /**
+ * Transform a VFS resource into an URL.
+ *
+ * @param vfsResource the cfw resource, not null
+ * @return the corresponding URL
+ * @throws IOException
+ */
+ static URL getURL(Object vfsResource) throws IOException {
+ return (URL) invokeVfsMethod(methodToUrl, vfsResource);
+ }
+
+ /**
+ * Get a to root VFS resource for the given URL.
+ *
+ * @param url the url
+ * @return the corresponding VFS resource.
+ * @throws IOException
+ */
+ static Object getRelative(URL url) throws IOException {
+ return invokeVfsMethod(methodGetRootUrl, null, url);
+ }
+
+ /**
+ * Transform the given VFS resource of a file.
+ *
+ * @param vfsResource the VFS resource
+ * @return the file.
+ * @throws IOException
+ */
+ static File getFile(Object vfsResource) throws IOException {
+ return (File) invokeVfsMethod(methodGetPhysicalFile, vfsResource);
+ }
+
+ /**
+ * Convert the given URL to the correspinoding root URL.
+ *
+ * @param url the url
+ * @return the root resource.
+ * @throws IOException
+ */
+ static Object getRoot(URL url) throws IOException {
+ return invokeVfsMethod(methodGetRootUrl, null, url);
+ }
+
+ /**
+ * Access the attributes from the current visitor context.
+ *
+ * @return the attributes.
+ */
+ static Object getVisitorAttributes() {
+ return readField(visitorAttributesField, null);
+ }
+
+ /**
+ * Access the corresponding path to the given VFS resource.
+ *
+ * @param resource the VFS resource
+ * @return the corresponding path.
+ */
+ static String getPath(Object resource) {
+ try {
+ return (String) methodGetPathName.invoke(resource);
+ } catch (Exception e) {
+ throw new IllegalStateException("Failed to get path name - " + resource, e);
+ }
+ }
+
+
+ /**
+ * Attempt to find a {@link Method} on the supplied class with the supplied name
+ * and parameter types. Searches all superclasses up to {@code Object}.
+ * <p>Returns {@code null} if no {@link Method} can be found.
+ *
+ * @param clazz the class to introspect
+ * @param name the name of the method
+ * @param paramTypes the parameter types of the method
+ * (may be {@code null} to indicate any signature)
+ * @return the Method object, or {@code null} if none found
+ */
+ private static Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
+ Objects.requireNonNull(clazz, "Class must not be null");
+ Objects.requireNonNull(name, "Method name must not be null");
+ Class<?> searchType = clazz;
+ while (searchType != null) {
+ Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods());
+ for (Method method : methods) {
+ if (name.equals(method.getName()) &&
+ (paramTypes == null || Arrays.equals(paramTypes, method.getParameterTypes()))) {
+ return method;
+ }
+ }
+ searchType = searchType.getSuperclass();
+ }
+ return null;
+ }
+
+
+ /**
+ * Get the field represented by the supplied {@link Field field object} on the
+ * specified {@link Object target object}. In accordance with {@link Field#get(Object)}
+ * semantics, the returned value is automatically wrapped if the underlying field
+ * has a primitive type.
+ * <p>Thrown exceptions are rethrown as {@link IllegalStateException}.
+ *
+ * @param field the field to get
+ * @param target the target object from which to get the field
+ * @return the field's current value
+ */
+ private static Object readField(Field field, Object target) {
+ try {
+ if (!field.isAccessible()) {
+ field.setAccessible(true);
+ }
+ return field.get(target);
+ } catch (Exception e) {
+ throw new IllegalStateException(
+ "Failed to read field: " + field.toGenericString(), e);
+ }
+ }
+
+ /**
+ * Attempt to find a {@link Field field} on the supplied {@link Class} with the
+ * supplied {@code name}. Searches all superclasses up to {@link Object}.
+ *
+ * @param clazz the class to introspect
+ * @param name the name of the field
+ * @return the corresponding Field object, or {@code null} if not found
+ */
+ private static Field findField(Class<?> clazz, String name) {
+ Objects.requireNonNull(clazz, "Class must not be null");
+ Objects.requireNonNull(name, "Name must not be null.");
+ Class<?> searchType = clazz;
+ while (!Object.class.equals(searchType) && searchType != null) {
+ Field[] fields = searchType.getDeclaredFields();
+ for (Field field : fields) {
+ if (name.equals(field.getName())) {
+ return field;
+ }
+ }
+ searchType = searchType.getSuperclass();
+ }
+ return null;
+ }
+
+}