diff --git a/org.springframework.core/core.iml b/org.springframework.core/core.iml index 552e3ec093..0fd49c0c31 100644 --- a/org.springframework.core/core.iml +++ b/org.springframework.core/core.iml @@ -1,202 +1,211 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.core/ivy.xml b/org.springframework.core/ivy.xml index ebe3803be4..321a81b977 100644 --- a/org.springframework.core/ivy.xml +++ b/org.springframework.core/ivy.xml @@ -37,6 +37,7 @@ + diff --git a/org.springframework.core/pom.xml b/org.springframework.core/pom.xml index 776dbc1c29..836666ae9c 100644 --- a/org.springframework.core/pom.xml +++ b/org.springframework.core/pom.xml @@ -43,6 +43,12 @@ 1.6.2 true + + org.jboss.vfs + com.springsource.org.jboss.virtual + 2.1.0.GA + true + javax.servlet servlet-api diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/ClassPathResource.java b/org.springframework.core/src/main/java/org/springframework/core/io/ClassPathResource.java index c63afc0feb..9fffc28f58 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/io/ClassPathResource.java +++ b/org.springframework.core/src/main/java/org/springframework/core/io/ClassPathResource.java @@ -27,6 +27,7 @@ import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.ResourceUtils; import org.springframework.util.StringUtils; +import org.springframework.core.io.support.ResourceHandlingUtils; /** * {@link Resource} implementation for class path resources. @@ -49,7 +50,6 @@ public class ClassPathResource extends AbstractResource { private Class clazz; - /** * Create a new ClassPathResource for ClassLoader usage. * A leading slash will be removed, as the ClassLoader @@ -174,7 +174,7 @@ public class ClassPathResource extends AbstractResource { */ @Override public File getFile() throws IOException { - return ResourceUtils.getFile(getURL(), getDescription()); + return ResourceHandlingUtils.getFile(getURL(), getDescription()); } /** @@ -186,10 +186,10 @@ public class ClassPathResource extends AbstractResource { URL url = getURL(); if (ResourceUtils.isJarURL(url)) { URL actualUrl = ResourceUtils.extractJarFileURL(url); - return ResourceUtils.getFile(actualUrl); + return ResourceHandlingUtils.getFile(actualUrl); } else { - return ResourceUtils.getFile(url, getDescription()); + return ResourceHandlingUtils.getFile(url, getDescription()); } } diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/UrlResource.java b/org.springframework.core/src/main/java/org/springframework/core/io/UrlResource.java index 912b9091c3..2e02b20e59 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/io/UrlResource.java +++ b/org.springframework.core/src/main/java/org/springframework/core/io/UrlResource.java @@ -28,6 +28,7 @@ import java.net.URLConnection; import org.springframework.util.Assert; import org.springframework.util.ResourceUtils; import org.springframework.util.StringUtils; +import org.springframework.core.io.support.ResourceHandlingUtils; /** * {@link Resource} implementation for java.net.URL locators. @@ -163,10 +164,10 @@ public class UrlResource extends AbstractResource { @Override public File getFile() throws IOException { if (this.uri != null) { - return ResourceUtils.getFile(this.uri, getDescription()); + return ResourceHandlingUtils.getFile(this.uri, getDescription()); } else { - return ResourceUtils.getFile(this.url, getDescription()); + return ResourceHandlingUtils.getFile(this.url, getDescription()); } } @@ -178,7 +179,7 @@ public class UrlResource extends AbstractResource { protected File getFileForLastModifiedCheck() throws IOException { if (ResourceUtils.isJarURL(this.url)) { URL actualUrl = ResourceUtils.extractJarFileURL(this.url); - return ResourceUtils.getFile(actualUrl); + return ResourceHandlingUtils.getFile(actualUrl); } else { return getFile(); diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java b/org.springframework.core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java index 9c8b001e96..d53233a1e1 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java +++ b/org.springframework.core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java @@ -154,6 +154,7 @@ import org.springframework.util.StringUtils; * * @author Juergen Hoeller * @author Colin Sampaleanu + * @author Marius Bogoevici * @since 1.0.2 * @see #CLASSPATH_ALL_URL_PREFIX * @see org.springframework.util.AntPathMatcher @@ -334,8 +335,9 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol Resource[] rootDirResources = getResources(rootDirPath); Set result = new LinkedHashSet(16); for (Resource rootDirResource : rootDirResources) { - rootDirResource = resolveRootDirResource(rootDirResource); - if (isJarResource(rootDirResource)) { + if (ResourceHandlingUtils.useResourceHandlingDelegate(rootDirResource.getURL())) { + result.addAll(ResourceHandlingUtils.findMatchingResourcesByDelegate(rootDirResource, subPattern, getPathMatcher())); + } else if (isJarResource(rootDirResource)) { result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern)); } else { diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/support/ResourceHandlingDelegate.java b/org.springframework.core/src/main/java/org/springframework/core/io/support/ResourceHandlingDelegate.java new file mode 100644 index 0000000000..2599c6989c --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/io/support/ResourceHandlingDelegate.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed 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.springframework.core.io.support; + +import java.io.IOException; +import java.net.URL; +import java.net.URI; +import java.util.Set; + +import org.springframework.core.io.Resource; +import org.springframework.util.PathMatcher; + +/** + * Abstraction for a path matching strategy, for customizing the way in which a resource can be + * scanned for finding underlying resources that match a given pattern. + * Used for implementing application-server specific resource scanning strategies (e.g. for JBoss AS) + * + * @author Marius Bogoevici + * + */ +public interface ResourceHandlingDelegate { + + boolean canHandleResource(URL url); + + boolean canHandleResource(URI uri); + + Set findMatchingResources(Resource rootResource, String subPattern, PathMatcher pathMatcher) throws + IOException; + + Resource loadResource(URL url) throws IOException; + + Resource loadResource(URI uri) throws IOException; + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/support/ResourceHandlingUtils.java b/org.springframework.core/src/main/java/org/springframework/core/io/support/ResourceHandlingUtils.java new file mode 100644 index 0000000000..a6a615d1d4 --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/io/support/ResourceHandlingUtils.java @@ -0,0 +1,107 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed 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.springframework.core.io.support; + +import java.net.URL; +import java.net.URI; +import java.util.Set; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.io.File; + +import org.springframework.util.ReflectionUtils; +import org.springframework.util.PathMatcher; +import org.springframework.util.ResourceUtils; +import org.springframework.util.Assert; +import org.springframework.core.io.support.jboss.VfsResourceHandlingDelegate; +import org.springframework.core.io.Resource; + +/** + * Utility class for determining whether a given URL is a resource + * location that should receive special treatmen, such as looking up a + * resource in JBoss VFS. + * + * @author Thomas Risberg + * @author Marius Bogoevici + * @since 3.0 + */ +public abstract class ResourceHandlingUtils { + + private static ResourceHandlingDelegate resourceHandlingDelegate; + + static { + try { + Class jBossVersionClass = PathMatchingResourcePatternResolver.class.getClassLoader().loadClass("org.jboss.Version"); + Object versionObject = ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(jBossVersionClass, "getInstance"), null); + Integer majorVersion = (Integer) ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(jBossVersionClass, "getMajor"), versionObject); + // For JBoss AS versions 5 and higher + if (majorVersion >= 5) { + resourceHandlingDelegate = new VfsResourceHandlingDelegate(); + } + } + catch (Throwable ex) { + // do nothing + } + } + + public static File getFile(URL resourceUrl) throws FileNotFoundException { + return getFile(resourceUrl, "URL"); + } + + public static File getFile(URL resourceUrl, String description) throws FileNotFoundException { + Assert.notNull(resourceUrl, "Resource URL must not be null"); + if (useResourceHandlingDelegate(resourceUrl)) { + try { + return resourceHandlingDelegate.loadResource(resourceUrl).getFile(); + } + catch (IOException e) { + throw new FileNotFoundException(description + " cannot be resolved as a file resource"); + } + } + return ResourceUtils.getFile(resourceUrl, description); + } + + public static File getFile(URI resourceUri) throws FileNotFoundException { + return getFile(resourceUri, "URI"); + } + + public static File getFile(URI resourceUri, String description) throws FileNotFoundException { + Assert.notNull(resourceUri, "Resource URI must not be null"); + if (useResourceHandlingDelegate(resourceUri)) { + try { + return resourceHandlingDelegate.loadResource(resourceUri).getFile(); + } + catch (IOException e) { + throw new FileNotFoundException(description + " cannot be resolved as a file resource"); + } + } + return ResourceUtils.getFile(resourceUri, description); + } + + public static boolean useResourceHandlingDelegate(URL url) { + return resourceHandlingDelegate != null && resourceHandlingDelegate.canHandleResource(url); + } + + public static boolean useResourceHandlingDelegate(URI uri) { + return resourceHandlingDelegate != null && resourceHandlingDelegate.canHandleResource(uri); + } + + public static Set findMatchingResourcesByDelegate(Resource resource, String pattern, PathMatcher matcher) throws + IOException { + return resourceHandlingDelegate.findMatchingResources(resource, pattern, matcher); + } +} \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/support/jboss/VfsResource.java b/org.springframework.core/src/main/java/org/springframework/core/io/support/jboss/VfsResource.java new file mode 100644 index 0000000000..2aef4f4e10 --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/io/support/jboss/VfsResource.java @@ -0,0 +1,153 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed 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.springframework.core.io.support.jboss; + +import java.io.IOException; +import java.io.File; +import java.io.InputStream; +import java.net.URL; +import java.net.URISyntaxException; +import java.net.URI; + +import org.jboss.virtual.VirtualFile; +import org.jboss.virtual.VFSUtils; + +import org.springframework.core.io.Resource; +import org.springframework.core.io.AbstractResource; +import org.springframework.util.Assert; + +/** + * VFS based Resource. + * + * @author Ales Justin + */ +class VfsResource extends AbstractResource { + + private VirtualFile file; + + public VfsResource(VirtualFile file) { + Assert.notNull(file, "The file cannot be null."); + this.file = file; + } + + public boolean exists() { + try { + return file.exists(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + public boolean isOpen() { + return false; + } + + public boolean isReadable() { + try { + return file.getSize() > 0; + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + public long lastModified() { + try { + return file.getLastModified(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + public URL getURL() throws IOException { + try { + return file.toURL(); + } + catch (URISyntaxException e) { + IOException ioe = new IOException(e.getMessage()); + ioe.initCause(e); + throw ioe; + } + } + + public URI getURI() throws IOException { + try { + return file.toURI(); + } + catch (URISyntaxException e) { + IOException ioe = new IOException(e.getMessage()); + ioe.initCause(e); + throw ioe; + } + } + + public File getFile() throws IOException { + if (VFSUtils.isNestedFile(file)) { + throw new IOException("This resource is a nested resource: " + file); + } + + try { + return new File(VFSUtils.getCompatibleURI(file)); + } + catch (IOException e) { + throw e; + } + catch (Exception e) { + IOException ioe = new IOException(e.getMessage()); + ioe.initCause(e); + throw ioe; + } + } + + @SuppressWarnings("deprecation") + public Resource createRelative(String relativePath) throws IOException { + return new VfsResource(file.findChild(relativePath)); + } + + public String getFilename() { + return file.getName(); + } + + public String getDescription() { + return file.toString(); + } + + public InputStream getInputStream() throws IOException { + return file.openStream(); + } + + public String toString() { + return getDescription(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof VfsResource) { + return file.equals(((VfsResource)obj).file); + } + else { + return false; + } + } + + @Override + public int hashCode() { + return this.file.hashCode(); + } +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/support/jboss/VfsResourceHandlingDelegate.java b/org.springframework.core/src/main/java/org/springframework/core/io/support/jboss/VfsResourceHandlingDelegate.java new file mode 100644 index 0000000000..8b04c73fd6 --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/io/support/jboss/VfsResourceHandlingDelegate.java @@ -0,0 +1,117 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed 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.springframework.core.io.support.jboss; + +import java.io.IOException; +import java.io.File; +import java.util.Set; +import java.util.LinkedHashSet; +import java.net.URL; +import java.net.URI; + +import org.jboss.virtual.VFS; +import org.jboss.virtual.VirtualFile; +import org.jboss.virtual.VirtualFileVisitor; +import org.jboss.virtual.VisitorAttributes; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.ResourceHandlingDelegate; +import org.springframework.util.PathMatcher; + +/** + * {@link org.springframework.core.io.support.ResourceHandlingDelegate} implementation + * for JBoss' Virtual File System. + * + * @author Marius Bogoevici + * @author Ales Justin + * + * Note: Thanks to David Ward from Alfresco for indicating a fix for path matching. + */ +public class VfsResourceHandlingDelegate implements ResourceHandlingDelegate { + + public boolean canHandleResource(URL url) { + return url.getProtocol().startsWith("vfs"); + } + + public boolean canHandleResource(URI uri) { + return uri.getScheme().startsWith("vfs"); + } + + + public Set findMatchingResources(Resource rootResource, String locationPattern, PathMatcher pathMatcher) throws IOException { + VirtualFile root = VFS.getRoot(rootResource.getURL()); + PatternVirtualFileVisitor visitor = new PatternVirtualFileVisitor(root.getPathName(), locationPattern, pathMatcher); + root.visit(visitor); + return visitor.getResources(); + } + + public Resource loadResource(URL url) throws IOException{ + return new VfsResource(VFS.getRoot(url)); + } + + public Resource loadResource(URI uri) throws IOException { + return new VfsResource(VFS.getRoot(uri)); + } + + + protected static class PatternVirtualFileVisitor implements VirtualFileVisitor + { + private final String subPattern; + private final Set resources = new LinkedHashSet(); + private final PathMatcher pathMatcher; + private final String rootPath; + + private PatternVirtualFileVisitor(String rootPath, String subPattern, PathMatcher pathMatcher) + { + this.subPattern = subPattern; + this.pathMatcher = pathMatcher; + this.rootPath = rootPath.length() == 0 || rootPath.endsWith("/") ? rootPath : rootPath + "/"; + } + + public VisitorAttributes getAttributes() + { + return VisitorAttributes.RECURSE; + } + + public void visit(VirtualFile vf) + { + if (pathMatcher.match(subPattern, vf.getPathName().substring(rootPath.length()))) + resources.add(new VfsResource(vf)); + } + + public Set getResources() + { + return resources; + } + + public int size() + { + return resources.size(); + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + buffer.append("sub-pattern: ").append(subPattern); + buffer.append(", resources: ").append(resources); + return buffer.toString(); + } + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/util/ResourceUtils.java b/org.springframework.core/src/main/java/org/springframework/util/ResourceUtils.java index bf52694bb7..5d71d08c38 100644 --- a/org.springframework.core/src/main/java/org/springframework/util/ResourceUtils.java +++ b/org.springframework.core/src/main/java/org/springframework/util/ResourceUtils.java @@ -256,7 +256,6 @@ public abstract class ResourceUtils { String protocol = url.getProtocol(); return (URL_PROTOCOL_JAR.equals(protocol) || URL_PROTOCOL_ZIP.equals(protocol) || - URL_PROTOCOL_VFSZIP.equals(protocol) || URL_PROTOCOL_WSJAR.equals(protocol) || (URL_PROTOCOL_CODE_SOURCE.equals(protocol) && url.getPath().indexOf(JAR_URL_SEPARATOR) != -1)); } diff --git a/org.springframework.core/template.mf b/org.springframework.core/template.mf index d426e0c5a7..f1a5d532f4 100644 --- a/org.springframework.core/template.mf +++ b/org.springframework.core/template.mf @@ -10,6 +10,7 @@ Import-Template: org.springframework.asm.*;version="[3.0.0, 3.0.1)";resolution:=optional, org.apache.log4j.*;version="[1.2.15, 2.0.0)";resolution:=optional, org.aspectj.*;version="[1.5.4, 2.0.0)";resolution:=optional, + org.jboss.virtual.*;version="[2.1.0.GA,2.1.0.GA]";resolution:=optional, org.xml.sax.*;version="0";resolution:=optional, org.w3c.dom.*;version="0";resolution:=optional Ignored-Existing-Headers: