001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.core.io;
018
019import java.io.File;
020import java.io.IOException;
021import java.io.InputStream;
022import java.lang.reflect.Field;
023import java.lang.reflect.InvocationTargetException;
024import java.lang.reflect.Method;
025import java.net.URI;
026import java.net.URL;
027
028import org.springframework.util.ReflectionUtils;
029
030/**
031 * Utility for detecting and accessing JBoss VFS in the classpath.
032 *
033 * <p>As of Spring 4.0, this class supports VFS 3.x on JBoss AS 6+
034 * (package {@code org.jboss.vfs}) and is in particular compatible with
035 * JBoss AS 7 and WildFly 8+.
036 *
037 * <p>Thanks go to Marius Bogoevici for the initial patch.
038 * <b>Note:</b> This is an internal class and should not be used outside the framework.
039 *
040 * @author Costin Leau
041 * @author Juergen Hoeller
042 * @since 3.0.3
043 */
044public abstract class VfsUtils {
045
046        private static final String VFS3_PKG = "org.jboss.vfs.";
047        private static final String VFS_NAME = "VFS";
048
049        private static final Method VFS_METHOD_GET_ROOT_URL;
050        private static final Method VFS_METHOD_GET_ROOT_URI;
051
052        private static final Method VIRTUAL_FILE_METHOD_EXISTS;
053        private static final Method VIRTUAL_FILE_METHOD_GET_INPUT_STREAM;
054        private static final Method VIRTUAL_FILE_METHOD_GET_SIZE;
055        private static final Method VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED;
056        private static final Method VIRTUAL_FILE_METHOD_TO_URL;
057        private static final Method VIRTUAL_FILE_METHOD_TO_URI;
058        private static final Method VIRTUAL_FILE_METHOD_GET_NAME;
059        private static final Method VIRTUAL_FILE_METHOD_GET_PATH_NAME;
060        private static final Method VIRTUAL_FILE_METHOD_GET_PHYSICAL_FILE;
061        private static final Method VIRTUAL_FILE_METHOD_GET_CHILD;
062
063        protected static final Class<?> VIRTUAL_FILE_VISITOR_INTERFACE;
064        protected static final Method VIRTUAL_FILE_METHOD_VISIT;
065
066        private static final Field VISITOR_ATTRIBUTES_FIELD_RECURSE;
067
068        static {
069                ClassLoader loader = VfsUtils.class.getClassLoader();
070                try {
071                        Class<?> vfsClass = loader.loadClass(VFS3_PKG + VFS_NAME);
072                        VFS_METHOD_GET_ROOT_URL = ReflectionUtils.findMethod(vfsClass, "getChild", URL.class);
073                        VFS_METHOD_GET_ROOT_URI = ReflectionUtils.findMethod(vfsClass, "getChild", URI.class);
074
075                        Class<?> virtualFile = loader.loadClass(VFS3_PKG + "VirtualFile");
076                        VIRTUAL_FILE_METHOD_EXISTS = ReflectionUtils.findMethod(virtualFile, "exists");
077                        VIRTUAL_FILE_METHOD_GET_INPUT_STREAM = ReflectionUtils.findMethod(virtualFile, "openStream");
078                        VIRTUAL_FILE_METHOD_GET_SIZE = ReflectionUtils.findMethod(virtualFile, "getSize");
079                        VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED = ReflectionUtils.findMethod(virtualFile, "getLastModified");
080                        VIRTUAL_FILE_METHOD_TO_URI = ReflectionUtils.findMethod(virtualFile, "toURI");
081                        VIRTUAL_FILE_METHOD_TO_URL = ReflectionUtils.findMethod(virtualFile, "toURL");
082                        VIRTUAL_FILE_METHOD_GET_NAME = ReflectionUtils.findMethod(virtualFile, "getName");
083                        VIRTUAL_FILE_METHOD_GET_PATH_NAME = ReflectionUtils.findMethod(virtualFile, "getPathName");
084                        VIRTUAL_FILE_METHOD_GET_PHYSICAL_FILE = ReflectionUtils.findMethod(virtualFile, "getPhysicalFile");
085                        VIRTUAL_FILE_METHOD_GET_CHILD = ReflectionUtils.findMethod(virtualFile, "getChild", String.class);
086
087                        VIRTUAL_FILE_VISITOR_INTERFACE = loader.loadClass(VFS3_PKG + "VirtualFileVisitor");
088                        VIRTUAL_FILE_METHOD_VISIT = ReflectionUtils.findMethod(virtualFile, "visit", VIRTUAL_FILE_VISITOR_INTERFACE);
089
090                        Class<?> visitorAttributesClass = loader.loadClass(VFS3_PKG + "VisitorAttributes");
091                        VISITOR_ATTRIBUTES_FIELD_RECURSE = ReflectionUtils.findField(visitorAttributesClass, "RECURSE");
092                }
093                catch (Throwable ex) {
094                        throw new IllegalStateException("Could not detect JBoss VFS infrastructure", ex);
095                }
096        }
097
098        protected static Object invokeVfsMethod(Method method, Object target, Object... args) throws IOException {
099                try {
100                        return method.invoke(target, args);
101                }
102                catch (InvocationTargetException ex) {
103                        Throwable targetEx = ex.getTargetException();
104                        if (targetEx instanceof IOException) {
105                                throw (IOException) targetEx;
106                        }
107                        ReflectionUtils.handleInvocationTargetException(ex);
108                }
109                catch (Exception ex) {
110                        ReflectionUtils.handleReflectionException(ex);
111                }
112
113                throw new IllegalStateException("Invalid code path reached");
114        }
115
116        static boolean exists(Object vfsResource) {
117                try {
118                        return (Boolean) invokeVfsMethod(VIRTUAL_FILE_METHOD_EXISTS, vfsResource);
119                }
120                catch (IOException ex) {
121                        return false;
122                }
123        }
124
125        static boolean isReadable(Object vfsResource) {
126                try {
127                        return (Long) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_SIZE, vfsResource) > 0;
128                }
129                catch (IOException ex) {
130                        return false;
131                }
132        }
133
134        static long getSize(Object vfsResource) throws IOException {
135                return (Long) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_SIZE, vfsResource);
136        }
137
138        static long getLastModified(Object vfsResource) throws IOException {
139                return (Long) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED, vfsResource);
140        }
141
142        static InputStream getInputStream(Object vfsResource) throws IOException {
143                return (InputStream) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_INPUT_STREAM, vfsResource);
144        }
145
146        static URL getURL(Object vfsResource) throws IOException {
147                return (URL) invokeVfsMethod(VIRTUAL_FILE_METHOD_TO_URL, vfsResource);
148        }
149
150        static URI getURI(Object vfsResource) throws IOException {
151                return (URI) invokeVfsMethod(VIRTUAL_FILE_METHOD_TO_URI, vfsResource);
152        }
153
154        static String getName(Object vfsResource) {
155                try {
156                        return (String) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_NAME, vfsResource);
157                }
158                catch (IOException ex) {
159                        throw new IllegalStateException("Cannot get resource name", ex);
160                }
161        }
162
163        static Object getRelative(URL url) throws IOException {
164                return invokeVfsMethod(VFS_METHOD_GET_ROOT_URL, null, url);
165        }
166
167        static Object getChild(Object vfsResource, String path) throws IOException {
168                return invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_CHILD, vfsResource, path);
169        }
170
171        static File getFile(Object vfsResource) throws IOException {
172                return (File) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_PHYSICAL_FILE, vfsResource);
173        }
174
175        static Object getRoot(URI url) throws IOException {
176                return invokeVfsMethod(VFS_METHOD_GET_ROOT_URI, null, url);
177        }
178
179        // protected methods used by the support sub-package
180
181        protected static Object getRoot(URL url) throws IOException {
182                return invokeVfsMethod(VFS_METHOD_GET_ROOT_URL, null, url);
183        }
184
185        protected static Object doGetVisitorAttribute() {
186                return ReflectionUtils.getField(VISITOR_ATTRIBUTES_FIELD_RECURSE, null);
187        }
188
189        protected static String doGetPath(Object resource) {
190                return (String) ReflectionUtils.invokeMethod(VIRTUAL_FILE_METHOD_GET_PATH_NAME, resource);
191        }
192
193}