View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.shiro.util;
20  
21  import org.slf4j.Logger;
22  import org.slf4j.LoggerFactory;
23  
24  import java.io.InputStream;
25  import java.lang.reflect.Constructor;
26  
27  
28  /**
29   * Utility method library used to conveniently interact with <code>Class</code>es, such as acquiring them from the
30   * application <code>ClassLoader</code>s and instantiating Objects from them.
31   *
32   * @since 0.1
33   */
34  public class ClassUtils {
35  
36      //TODO - complete JavaDoc
37  
38      /**
39       * Private internal log instance.
40       */
41      private static final Logger log = LoggerFactory.getLogger(ClassUtils.class);
42  
43      /**
44       * @since 1.0
45       */
46      private static final ClassLoaderAccessor THREAD_CL_ACCESSOR = new ExceptionIgnoringAccessor() {
47          @Override
48          protected ClassLoader doGetClassLoader() throws Throwable {
49              return Thread.currentThread().getContextClassLoader();
50          }
51      };
52  
53      /**
54       * @since 1.0
55       */
56      private static final ClassLoaderAccessor CLASS_CL_ACCESSOR = new ExceptionIgnoringAccessor() {
57          @Override
58          protected ClassLoader doGetClassLoader() throws Throwable {
59              return ClassUtils.class.getClassLoader();
60          }
61      };
62  
63      /**
64       * @since 1.0
65       */
66      private static final ClassLoaderAccessor SYSTEM_CL_ACCESSOR = new ExceptionIgnoringAccessor() {
67          @Override
68          protected ClassLoader doGetClassLoader() throws Throwable {
69              return ClassLoader.getSystemClassLoader();
70          }
71      };
72  
73      /**
74       * Returns the specified resource by checking the current thread's
75       * {@link Thread#getContextClassLoader() context class loader}, then the
76       * current ClassLoader (<code>ClassUtils.class.getClassLoader()</code>), then the system/application
77       * ClassLoader (<code>ClassLoader.getSystemClassLoader()</code>, in that order, using
78       * {@link ClassLoader#getResourceAsStream(String) getResourceAsStream(name)}.
79       *
80       * @param name the name of the resource to acquire from the classloader(s).
81       * @return the InputStream of the resource found, or <code>null</code> if the resource cannot be found from any
82       *         of the three mentioned ClassLoaders.
83       * @since 0.9
84       */
85      public static InputStream getResourceAsStream(String name) {
86  
87          InputStream is = THREAD_CL_ACCESSOR.getResourceStream(name);
88  
89          if (is == null) {
90              if (log.isTraceEnabled()) {
91                  log.trace("Resource [" + name + "] was not found via the thread context ClassLoader.  Trying the " +
92                          "current ClassLoader...");
93              }
94              is = CLASS_CL_ACCESSOR.getResourceStream(name);
95          }
96  
97          if (is == null) {
98              if (log.isTraceEnabled()) {
99                  log.trace("Resource [" + name + "] was not found via the current class loader.  Trying the " +
100                         "system/application ClassLoader...");
101             }
102             is = SYSTEM_CL_ACCESSOR.getResourceStream(name);
103         }
104 
105         if (is == null && log.isTraceEnabled()) {
106             log.trace("Resource [" + name + "] was not found via the thread context, current, or " +
107                     "system/application ClassLoaders.  All heuristics have been exhausted.  Returning null.");
108         }
109 
110         return is;
111     }
112 
113     /**
114      * Attempts to load the specified class name from the current thread's
115      * {@link Thread#getContextClassLoader() context class loader}, then the
116      * current ClassLoader (<code>ClassUtils.class.getClassLoader()</code>), then the system/application
117      * ClassLoader (<code>ClassLoader.getSystemClassLoader()</code>, in that order.  If any of them cannot locate
118      * the specified class, an <code>UnknownClassException</code> is thrown (our RuntimeException equivalent of
119      * the JRE's <code>ClassNotFoundException</code>.
120      *
121      * @param fqcn the fully qualified class name to load
122      * @return the located class
123      * @throws UnknownClassException if the class cannot be found.
124      */
125     public static Class forName(String fqcn) throws UnknownClassException {
126 
127         Class clazz = THREAD_CL_ACCESSOR.loadClass(fqcn);
128 
129         if (clazz == null) {
130             if (log.isTraceEnabled()) {
131                 log.trace("Unable to load class named [" + fqcn +
132                         "] from the thread context ClassLoader.  Trying the current ClassLoader...");
133             }
134             clazz = CLASS_CL_ACCESSOR.loadClass(fqcn);
135         }
136 
137         if (clazz == null) {
138             if (log.isTraceEnabled()) {
139                 log.trace("Unable to load class named [" + fqcn + "] from the current ClassLoader.  " +
140                         "Trying the system/application ClassLoader...");
141             }
142             clazz = SYSTEM_CL_ACCESSOR.loadClass(fqcn);
143         }
144 
145         if (clazz == null) {
146             String msg = "Unable to load class named [" + fqcn + "] from the thread context, current, or " +
147                     "system/application ClassLoaders.  All heuristics have been exhausted.  Class could not be found.";
148             throw new UnknownClassException(msg);
149         }
150 
151         return clazz;
152     }
153 
154     public static boolean isAvailable(String fullyQualifiedClassName) {
155         try {
156             forName(fullyQualifiedClassName);
157             return true;
158         } catch (UnknownClassException e) {
159             return false;
160         }
161     }
162 
163     public static Object newInstance(String fqcn) {
164         return newInstance(forName(fqcn));
165     }
166 
167     public static Object newInstance(String fqcn, Object... args) {
168         return newInstance(forName(fqcn), args);
169     }
170 
171     public static Object newInstance(Class clazz) {
172         if (clazz == null) {
173             String msg = "Class method parameter cannot be null.";
174             throw new IllegalArgumentException(msg);
175         }
176         try {
177             return clazz.newInstance();
178         } catch (Exception e) {
179             throw new InstantiationException("Unable to instantiate class [" + clazz.getName() + "]", e);
180         }
181     }
182 
183     public static Object newInstance(Class clazz, Object... args) {
184         Class[] argTypes = new Class[args.length];
185         for (int i = 0; i < args.length; i++) {
186             argTypes[i] = args[i].getClass();
187         }
188         Constructor ctor = getConstructor(clazz, argTypes);
189         return instantiate(ctor, args);
190     }
191 
192     public static Constructor getConstructor(Class clazz, Class... argTypes) {
193         try {
194             return clazz.getConstructor(argTypes);
195         } catch (NoSuchMethodException e) {
196             throw new IllegalStateException(e);
197         }
198 
199     }
200 
201     public static Object instantiate(Constructor ctor, Object... args) {
202         try {
203             return ctor.newInstance(args);
204         } catch (Exception e) {
205             String msg = "Unable to instantiate Permission instance with constructor [" + ctor + "]";
206             throw new InstantiationException(msg, e);
207         }
208     }
209 
210     /**
211      * @since 1.0
212      */
213     private static interface ClassLoaderAccessor {
214         Class loadClass(String fqcn);
215         InputStream getResourceStream(String name);
216     }
217 
218     /**
219      * @since 1.0
220      */
221     private static abstract class ExceptionIgnoringAccessor implements ClassLoaderAccessor {
222 
223         public Class loadClass(String fqcn) {
224             Class clazz = null;
225             ClassLoader cl = getClassLoader();
226             if (cl != null) {
227                 try {
228                     clazz = cl.loadClass(fqcn);
229                 } catch (ClassNotFoundException e) {
230                     if (log.isTraceEnabled()) {
231                         log.trace("Unable to load clazz named [" + fqcn + "] from class loader [" + cl + "]");
232                     }
233                 }
234             }
235             return clazz;
236         }
237 
238         public InputStream getResourceStream(String name) {
239             InputStream is = null;
240             ClassLoader cl = getClassLoader();
241             if (cl != null) {
242                 is = cl.getResourceAsStream(name);
243             }
244             return is;
245         }
246 
247         protected final ClassLoader getClassLoader() {
248             try {
249                 return doGetClassLoader();
250             } catch (Throwable t) {
251                 if (log.isDebugEnabled()) {
252                     log.debug("Unable to acquire ClassLoader.", t);
253                 }
254             }
255             return null;
256         }
257 
258         protected abstract ClassLoader doGetClassLoader() throws Throwable;
259     }
260 }