提交 dc05ef65 编写于 作者: J Juergen Hoeller

revised JBoss VFS support

上级 e56aa91b
/*
* 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;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import org.jboss.virtual.VFS;
import org.springframework.util.ResourceUtils;
/**
* Abstract base class for resources which resolve URLs into File references,
* such as {@link UrlResource} or {@link ClassPathResource}.
*
* <p>Detects the "file" protocol as well as the JBoss "vfs" protocol in URLs,
* resolving file system references accordingly.
*
* @author Juergen Hoeller
* @since 3.0
*/
public abstract class AbstractFileResolvingResource extends AbstractResource {
/**
* This implementation returns a File reference for the underlying class path
* resource, provided that it refers to a file in the file system.
* @see org.springframework.util.ResourceUtils#getFile(java.net.URL, String)
*/
@Override
public File getFile() throws IOException {
URL url = getURL();
if (url.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
return VfsResourceDelegate.getResource(url).getFile();
}
return ResourceUtils.getFile(url, getDescription());
}
/**
* This implementation determines the underlying File
* (or jar file, in case of a resource in a jar/zip).
*/
@Override
protected File getFileForLastModifiedCheck() throws IOException {
URL url = getURL();
if (ResourceUtils.isJarURL(url)) {
URL actualUrl = ResourceUtils.extractJarFileURL(url);
if (actualUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
return VfsResourceDelegate.getResource(actualUrl).getFile();
}
return ResourceUtils.getFile(actualUrl, "Jar URL");
}
else {
return getFile();
}
}
/**
* This implementation returns a File reference for the underlying class path
* resource, provided that it refers to a file in the file system.
* @see org.springframework.util.ResourceUtils#getFile(java.net.URI, String)
*/
protected File getFile(URI uri) throws IOException {
if (uri.getScheme().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
return VfsResourceDelegate.getResource(uri).getFile();
}
return ResourceUtils.getFile(uri, getDescription());
}
/**
* Inner delegate class, avoiding a hard JBoss VFS API dependency at runtime.
*/
private static class VfsResourceDelegate {
public static Resource getResource(URL url) throws IOException {
return new VfsResource(VFS.getRoot(url));
}
public static Resource getResource(URI uri) throws IOException {
return new VfsResource(VFS.getRoot(uri));
}
}
}
......@@ -16,7 +16,6 @@
package org.springframework.core.io;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
......@@ -25,9 +24,7 @@ import java.net.URL;
import org.springframework.util.Assert;
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.
......@@ -42,7 +39,7 @@ import org.springframework.core.io.support.ResourceHandlingUtils;
* @see java.lang.ClassLoader#getResourceAsStream(String)
* @see java.lang.Class#getResourceAsStream(String)
*/
public class ClassPathResource extends AbstractResource {
public class ClassPathResource extends AbstractFileResolvingResource {
private final String path;
......@@ -50,6 +47,7 @@ public class ClassPathResource extends AbstractResource {
private Class clazz;
/**
* Create a new ClassPathResource for ClassLoader usage.
* A leading slash will be removed, as the ClassLoader
......@@ -167,32 +165,6 @@ public class ClassPathResource extends AbstractResource {
return url;
}
/**
* This implementation returns a File reference for the underlying class path
* resource, provided that it refers to a file in the file system.
* @see org.springframework.util.ResourceUtils#getFile(java.net.URL, String)
*/
@Override
public File getFile() throws IOException {
return ResourceHandlingUtils.getFile(getURL(), getDescription());
}
/**
* This implementation determines the underlying File
* (or jar file, in case of a resource in a jar/zip).
*/
@Override
protected File getFileForLastModifiedCheck() throws IOException {
URL url = getURL();
if (ResourceUtils.isJarURL(url)) {
URL actualUrl = ResourceUtils.extractJarFileURL(url);
return ResourceHandlingUtils.getFile(actualUrl);
}
else {
return ResourceHandlingUtils.getFile(url, getDescription());
}
}
/**
* This implementation creates a ClassPathResource, applying the given path
* relative to the path of the underlying resource of this descriptor.
......
......@@ -26,9 +26,7 @@ import java.net.URL;
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 <code>java.net.URL</code> locators.
......@@ -39,7 +37,7 @@ import org.springframework.core.io.support.ResourceHandlingUtils;
* @since 28.12.2003
* @see java.net.URL
*/
public class UrlResource extends AbstractResource {
public class UrlResource extends AbstractFileResolvingResource {
/**
* Original URL, used for actual access.
......@@ -164,25 +162,10 @@ public class UrlResource extends AbstractResource {
@Override
public File getFile() throws IOException {
if (this.uri != null) {
return ResourceHandlingUtils.getFile(this.uri, getDescription());
return super.getFile(this.uri);
}
else {
return ResourceHandlingUtils.getFile(this.url, getDescription());
}
}
/**
* This implementation determines the underlying File
* (or jar file, in case of a resource in a jar/zip).
*/
@Override
protected File getFileForLastModifiedCheck() throws IOException {
if (ResourceUtils.isJarURL(this.url)) {
URL actualUrl = ResourceUtils.extractJarFileURL(this.url);
return ResourceHandlingUtils.getFile(actualUrl);
}
else {
return getFile();
return super.getFile();
}
}
......
......@@ -14,105 +14,93 @@
* limitations under the License.
*/
package org.springframework.core.io.support.jboss;
package org.springframework.core.io;
import java.io.IOException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URISyntaxException;
import java.net.URI;
import java.net.URL;
import org.jboss.virtual.VirtualFile;
import org.jboss.virtual.VFSUtils;
import org.jboss.virtual.VFS;
import org.jboss.virtual.VFSUtils;
import org.jboss.virtual.VirtualFile;
import org.springframework.core.io.Resource;
import org.springframework.core.io.AbstractResource;
import org.springframework.core.NestedIOException;
import org.springframework.util.Assert;
/**
* VFS based Resource.
* VFS based {@link Resource} implementation.
*
* @author Ales Justin
* @author Juergen Hoeller
* @since 3.0
* @see org.jboss.virtual.VirtualFile
*/
class VfsResource extends AbstractResource {
public class VfsResource extends AbstractResource {
private final VirtualFile file;
private VirtualFile file;
public VfsResource(VirtualFile file) {
Assert.notNull(file, "The file cannot be null.");
Assert.notNull(file, "VirtualFile must not be null");
this.file = file;
}
public boolean exists() {
try {
return file.exists();
return this.file.exists();
}
catch (IOException e) {
throw new RuntimeException(e);
catch (IOException ex) {
return false;
}
}
public boolean isOpen() {
return false;
}
public boolean isReadable() {
try {
return file.getSize() > 0;
return (this.file.getSize() > 0);
}
catch (IOException e) {
throw new RuntimeException(e);
return false;
}
}
public long lastModified() {
try {
return file.getLastModified();
}
catch (IOException e) {
throw new RuntimeException(e);
}
public long lastModified() throws IOException {
return this.file.getLastModified();
}
public InputStream getInputStream() throws IOException {
return this.file.openStream();
}
public URL getURL() throws IOException {
try {
return file.toURL();
return this.file.toURL();
}
catch (URISyntaxException e) {
IOException ioe = new IOException(e.getMessage());
ioe.initCause(e);
throw ioe;
catch (Exception ex) {
throw new NestedIOException("Failed to obtain URL for file " + this.file, ex);
}
}
public URI getURI() throws IOException {
try {
return file.toURI();
return this.file.toURI();
}
catch (URISyntaxException e) {
IOException ioe = new IOException(e.getMessage());
ioe.initCause(e);
throw ioe;
catch (Exception ex) {
throw new NestedIOException("Failed to obtain URI for " + this.file, ex);
}
}
public File getFile() throws IOException {
if (VFSUtils.isNestedFile(file)) {
throw new IOException("This resource is a nested resource: " + file);
if (VFSUtils.isNestedFile(this.file)) {
throw new IOException("File resolution not supported for nested resource: " + this.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;
catch (Exception ex) {
throw new NestedIOException("Failed to obtain File reference for " + this.file, ex);
}
}
......@@ -121,33 +109,22 @@ class VfsResource extends AbstractResource {
}
public String getFilename() {
return file.getName();
return this.file.getName();
}
public String getDescription() {
return file.toString();
return this.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;
}
return (obj == this || (obj instanceof VfsResource && this.file.equals(((VfsResource) obj).file)));
}
@Override
public int hashCode() {
return this.file.hashCode();
}
}
......@@ -32,12 +32,17 @@ import java.util.jar.JarFile;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.virtual.VFS;
import org.jboss.virtual.VirtualFile;
import org.jboss.virtual.VirtualFileVisitor;
import org.jboss.virtual.VisitorAttributes;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.UrlResource;
import org.springframework.core.io.VfsResource;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.PathMatcher;
......@@ -335,11 +340,12 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
Resource[] rootDirResources = getResources(rootDirPath);
Set<Resource> result = new LinkedHashSet<Resource>(16);
for (Resource rootDirResource : rootDirResources) {
if (ResourceHandlingUtils.useResourceHandlingDelegate(rootDirResource.getURL())) {
result.addAll(ResourceHandlingUtils.findMatchingResourcesByDelegate(rootDirResource, subPattern, getPathMatcher()));
} else if (isJarResource(rootDirResource)) {
if (isJarResource(rootDirResource)) {
result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern));
}
else if (rootDirResource.getURL().getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher()));
}
else {
result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
}
......@@ -625,4 +631,64 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
}
}
/**
* Inner delegate class, avoiding a hard JBoss VFS API dependency at runtime.
*/
private static class VfsResourceMatchingDelegate {
public static Set<Resource> 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();
}
}
/**
* VFS visitor for path matching purposes.
*/
private static class PatternVirtualFileVisitor implements VirtualFileVisitor {
private final String subPattern;
private final PathMatcher pathMatcher;
private final String rootPath;
private final Set<Resource> resources = new LinkedHashSet<Resource>();
public 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 (this.pathMatcher.match(this.subPattern, vf.getPathName().substring(this.rootPath.length()))) {
this.resources.add(new VfsResource(vf));
}
}
public Set<Resource> getResources() {
return this.resources;
}
public int size() {
return this.resources.size();
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("sub-pattern: ").append(this.subPattern);
sb.append(", resources: ").append(this.resources);
return sb.toString();
}
}
}
/*
* 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<Resource> findMatchingResources(Resource rootResource, String subPattern, PathMatcher pathMatcher) throws
IOException;
Resource loadResource(URL url) throws IOException;
Resource loadResource(URI uri) throws IOException;
}
/*
* 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<Resource> findMatchingResourcesByDelegate(Resource resource, String pattern, PathMatcher matcher) throws
IOException {
return resourceHandlingDelegate.findMatchingResources(resource, pattern, matcher);
}
}
\ No newline at end of file
/*
* 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<Resource> 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<Resource> resources = new LinkedHashSet<Resource>();
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<Resource> 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();
}
}
}
/*
* Copyright 2002-2008 the original author or authors.
* 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.
......@@ -68,6 +68,9 @@ public abstract class ResourceUtils {
/** URL protocol for an entry from a JBoss jar file: "vfszip" */
public static final String URL_PROTOCOL_VFSZIP = "vfszip";
/** URL protocol for a JBoss VFS resource: "vfs" */
public static final String URL_PROTOCOL_VFS = "vfs";
/** URL protocol for an entry from a WebSphere jar file: "wsjar" */
public static final String URL_PROTOCOL_WSJAR = "wsjar";
......@@ -257,7 +260,7 @@ public abstract class ResourceUtils {
return (URL_PROTOCOL_JAR.equals(protocol) ||
URL_PROTOCOL_ZIP.equals(protocol) ||
URL_PROTOCOL_WSJAR.equals(protocol) ||
(URL_PROTOCOL_CODE_SOURCE.equals(protocol) && url.getPath().indexOf(JAR_URL_SEPARATOR) != -1));
(URL_PROTOCOL_CODE_SOURCE.equals(protocol) && url.getPath().contains(JAR_URL_SEPARATOR)));
}
/**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册