View Javadoc
1   /**
2    *    Copyright 2009-2015 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.apache.ibatis.io;
17  
18  import java.io.IOException;
19  import java.lang.reflect.InvocationTargetException;
20  import java.lang.reflect.Method;
21  import java.net.URL;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collections;
25  import java.util.List;
26  
27  import org.apache.ibatis.logging.Log;
28  import org.apache.ibatis.logging.LogFactory;
29  
30  /**
31   * Provides a very simple API for accessing resources within an application server.
32   * 
33   * @author Ben Gunter
34   */
35  public abstract class VFS {
36    private static final Log log = LogFactory.getLog(ResolverUtil.class);
37  
38    /** The built-in implementations. */
39    public static final Class<?>[] IMPLEMENTATIONS = { JBoss6VFS.class, DefaultVFS.class };
40  
41    /** The list to which implementations are added by {@link #addImplClass(Class)}. */
42    public static final List<Class<? extends VFS>> USER_IMPLEMENTATIONS = new ArrayList<Class<? extends VFS>>();
43  
44    /** Singleton instance. */
45    private static VFS instance;
46  
47    /**
48     * Get the singleton {@link VFS} instance. If no {@link VFS} implementation can be found for the
49     * current environment, then this method returns null.
50     */
51    @SuppressWarnings("unchecked")
52    public static VFS getInstance() {
53      if (instance != null) {
54        return instance;
55      }
56  
57      // Try the user implementations first, then the built-ins
58      List<Class<? extends VFS>> impls = new ArrayList<Class<? extends VFS>>();
59      impls.addAll(USER_IMPLEMENTATIONS);
60      impls.addAll(Arrays.asList((Class<? extends VFS>[]) IMPLEMENTATIONS));
61  
62      // Try each implementation class until a valid one is found
63      VFS vfs = null;
64      for (int i = 0; vfs == null || !vfs.isValid(); i++) {
65        Class<? extends VFS> impl = impls.get(i);
66        try {
67          vfs = impl.newInstance();
68          if (vfs == null || !vfs.isValid()) {
69            if (log.isDebugEnabled()) {
70              log.debug("VFS implementation " + impl.getName() +
71                " is not valid in this environment.");
72            }
73          }
74        } catch (InstantiationException e) {
75          log.error("Failed to instantiate " + impl, e);
76          return null;
77        } catch (IllegalAccessException e) {
78          log.error("Failed to instantiate " + impl, e);
79          return null;
80        }
81      }
82  
83      if (log.isDebugEnabled()) {
84        log.debug("Using VFS adapter " + vfs.getClass().getName());
85      }
86      VFS.instance = vfs;
87      return VFS.instance;
88    }
89  
90    /**
91     * Adds the specified class to the list of {@link VFS} implementations. Classes added in this
92     * manner are tried in the order they are added and before any of the built-in implementations.
93     * 
94     * @param clazz The {@link VFS} implementation class to add.
95     */
96    public static void addImplClass(Class<? extends VFS> clazz) {
97      if (clazz != null) {
98        USER_IMPLEMENTATIONS.add(clazz);
99      }
100   }
101 
102   /** Get a class by name. If the class is not found then return null. */
103   protected static Class<?> getClass(String className) {
104     try {
105       return Thread.currentThread().getContextClassLoader().loadClass(className);
106 //      return ReflectUtil.findClass(className);
107     } catch (ClassNotFoundException e) {
108       if (log.isDebugEnabled()) {
109         log.debug("Class not found: " + className);
110       }
111       return null;
112     }
113   }
114 
115   /**
116    * Get a method by name and parameter types. If the method is not found then return null.
117    * 
118    * @param clazz The class to which the method belongs.
119    * @param methodName The name of the method.
120    * @param parameterTypes The types of the parameters accepted by the method.
121    */
122   protected static Method getMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
123     if (clazz == null) {
124       return null;
125     }
126     try {
127       return clazz.getMethod(methodName, parameterTypes);
128     } catch (SecurityException e) {
129       log.error("Security exception looking for method " + clazz.getName() + "." + methodName + ".  Cause: " + e);
130       return null;
131     } catch (NoSuchMethodException e) {
132       log.error("Method not found " + clazz.getName() + "." + methodName + "." + methodName + ".  Cause: " + e);
133       return null;
134     }
135   }
136 
137   /**
138    * Invoke a method on an object and return whatever it returns.
139    * 
140    * @param method The method to invoke.
141    * @param object The instance or class (for static methods) on which to invoke the method.
142    * @param parameters The parameters to pass to the method.
143    * @return Whatever the method returns.
144    * @throws IOException If I/O errors occur
145    * @throws StripesRuntimeException If anything else goes wrong
146    */
147   @SuppressWarnings("unchecked")
148   protected static <T> T invoke(Method method, Object object, Object... parameters)
149       throws IOException, RuntimeException {
150     try {
151       return (T) method.invoke(object, parameters);
152     } catch (IllegalArgumentException e) {
153       throw new RuntimeException(e);
154     } catch (IllegalAccessException e) {
155       throw new RuntimeException(e);
156     } catch (InvocationTargetException e) {
157       if (e.getTargetException() instanceof IOException) {
158         throw (IOException) e.getTargetException();
159       } else {
160         throw new RuntimeException(e);
161       }
162     }
163   }
164 
165   /**
166    * Get a list of {@link URL}s from the context classloader for all the resources found at the
167    * specified path.
168    * 
169    * @param path The resource path.
170    * @return A list of {@link URL}s, as returned by {@link ClassLoader#getResources(String)}.
171    * @throws IOException If I/O errors occur
172    */
173   protected static List<URL> getResources(String path) throws IOException {
174     return Collections.list(Thread.currentThread().getContextClassLoader().getResources(path));
175   }
176 
177   /** Return true if the {@link VFS} implementation is valid for the current environment. */
178   public abstract boolean isValid();
179 
180   /**
181    * Recursively list the full resource path of all the resources that are children of the
182    * resource identified by a URL.
183    * 
184    * @param url The URL that identifies the resource to list.
185    * @param forPath The path to the resource that is identified by the URL. Generally, this is the
186    *            value passed to {@link #getResources(String)} to get the resource URL.
187    * @return A list containing the names of the child resources.
188    * @throws IOException If I/O errors occur
189    */
190   protected abstract List<String> list(URL url, String forPath) throws IOException;
191 
192   /**
193    * Recursively list the full resource path of all the resources that are children of all the
194    * resources found at the specified path.
195    * 
196    * @param path The path of the resource(s) to list.
197    * @return A list containing the names of the child resources.
198    * @throws IOException If I/O errors occur
199    */
200   public List<String> list(String path) throws IOException {
201     List<String> names = new ArrayList<String>();
202     for (URL url : getResources(path)) {
203       names.addAll(list(url, path));
204     }
205     return names;
206   }
207 }