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.myfaces.shared_orchestra.util;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  
24  import javax.faces.FacesException;
25  import javax.servlet.jsp.el.ELException;
26  import java.io.InputStream;
27  import java.io.IOException;
28  import java.lang.reflect.Array;
29  import java.util.*;
30  
31  
32  /**
33   * @author Manfred Geiler (latest modification by $Author: lu4242 $)
34   * @author Anton Koinov
35   * @version $Revision: 925490 $ $Date: 2010-03-19 19:00:09 -0500 (Fri, 19 Mar 2010) $
36   */
37  public final class ClassUtils
38  {
39      //~ Static fields/initializers -----------------------------------------------------------------
40  
41      private static final Log log                  = LogFactory.getLog(ClassUtils.class);
42      //private static final Logger COERCION_LOGGER   = new Logger(System.out);
43  
44      public static final Class BOOLEAN_ARRAY_CLASS = boolean[].class;
45      public static final Class BYTE_ARRAY_CLASS    = byte[].class;
46      public static final Class CHAR_ARRAY_CLASS    = char[].class;
47      public static final Class SHORT_ARRAY_CLASS   = short[].class;
48      public static final Class INT_ARRAY_CLASS     = int[].class;
49      public static final Class LONG_ARRAY_CLASS    = long[].class;
50      public static final Class FLOAT_ARRAY_CLASS   = float[].class;
51      public static final Class DOUBLE_ARRAY_CLASS  = double[].class;
52      public static final Class OBJECT_ARRAY_CLASS  = Object[].class;
53      public static final Class BOOLEAN_OBJECT_ARRAY_CLASS = Boolean[].class;
54      public static final Class BYTE_OBJECT_ARRAY_CLASS = Byte[].class;
55      public static final Class CHARACTER_OBJECT_ARRAY_CLASS = Character[].class;
56      public static final Class SHORT_OBJECT_ARRAY_CLASS = Short[].class;
57      public static final Class INTEGER_OBJECT_ARRAY_CLASS = Integer[].class;
58      public static final Class LONG_OBJECT_ARRAY_CLASS = Long[].class;
59      public static final Class FLOAT_OBJECT_ARRAY_CLASS = Float[].class;
60      public static final Class DOUBLE_OBJECT_ARRAY_CLASS = Double[].class;
61      public static final Class STRING_OBJECT_ARRAY_CLASS = String[].class;
62  
63      public static final Map COMMON_TYPES = new HashMap(64);
64      static
65      {
66          COMMON_TYPES.put("byte", Byte.TYPE);
67          COMMON_TYPES.put("char", Character.TYPE);
68          COMMON_TYPES.put("double", Double.TYPE);
69          COMMON_TYPES.put("float", Float.TYPE);
70          COMMON_TYPES.put("int", Integer.TYPE);
71          COMMON_TYPES.put("long", Long.TYPE);
72          COMMON_TYPES.put("short", Short.TYPE);
73          COMMON_TYPES.put("boolean", Boolean.TYPE);
74          COMMON_TYPES.put("void", Void.TYPE);
75          COMMON_TYPES.put("java.lang.Object", Object.class);
76          COMMON_TYPES.put("java.lang.Boolean", Boolean.class);
77          COMMON_TYPES.put("java.lang.Byte", Byte.class);
78          COMMON_TYPES.put("java.lang.Character", Character.class);
79          COMMON_TYPES.put("java.lang.Short", Short.class);
80          COMMON_TYPES.put("java.lang.Integer", Integer.class);
81          COMMON_TYPES.put("java.lang.Long", Long.class);
82          COMMON_TYPES.put("java.lang.Float", Float.class);
83          COMMON_TYPES.put("java.lang.Double", Double.class);
84          COMMON_TYPES.put("java.lang.String", String.class);
85  
86          COMMON_TYPES.put("byte[]", BYTE_ARRAY_CLASS);
87          COMMON_TYPES.put("char[]", CHAR_ARRAY_CLASS);
88          COMMON_TYPES.put("double[]", DOUBLE_ARRAY_CLASS);
89          COMMON_TYPES.put("float[]", FLOAT_ARRAY_CLASS);
90          COMMON_TYPES.put("int[]", INT_ARRAY_CLASS);
91          COMMON_TYPES.put("long[]", LONG_ARRAY_CLASS);
92          COMMON_TYPES.put("short[]", SHORT_ARRAY_CLASS);
93          COMMON_TYPES.put("boolean[]", BOOLEAN_ARRAY_CLASS);
94          COMMON_TYPES.put("java.lang.Object[]", OBJECT_ARRAY_CLASS);
95          COMMON_TYPES.put("java.lang.Boolean[]", BOOLEAN_OBJECT_ARRAY_CLASS);
96          COMMON_TYPES.put("java.lang.Byte[]", BYTE_OBJECT_ARRAY_CLASS);
97          COMMON_TYPES.put("java.lang.Character[]", CHARACTER_OBJECT_ARRAY_CLASS);
98          COMMON_TYPES.put("java.lang.Short[]", SHORT_OBJECT_ARRAY_CLASS);
99          COMMON_TYPES.put("java.lang.Integer[]", INTEGER_OBJECT_ARRAY_CLASS);
100         COMMON_TYPES.put("java.lang.Long[]", LONG_OBJECT_ARRAY_CLASS);
101         COMMON_TYPES.put("java.lang.Float[]", FLOAT_OBJECT_ARRAY_CLASS);
102         COMMON_TYPES.put("java.lang.Double[]", DOUBLE_OBJECT_ARRAY_CLASS);
103         COMMON_TYPES.put("java.lang.String[]", STRING_OBJECT_ARRAY_CLASS);
104         // array of void is not a valid type
105     }
106 
107     /** utility class, do not instantiate */
108     private ClassUtils()
109     {
110         // utility class, disable instantiation
111     }
112 
113     //~ Methods ------------------------------------------------------------------------------------
114 
115     /**
116      * Tries a Class.loadClass with the context class loader of the current thread first and
117      * automatically falls back to the ClassUtils class loader (i.e. the loader of the
118      * myfaces.jar lib) if necessary.
119      *
120      * @param type fully qualified name of a non-primitive non-array class
121      * @return the corresponding Class
122      * @throws NullPointerException if type is null
123      * @throws ClassNotFoundException
124      */
125     public static Class classForName(String type)
126         throws ClassNotFoundException
127     {
128         if (type == null) throw new NullPointerException("type");
129         try
130         {
131             // Try WebApp ClassLoader first
132             return Class.forName(type,
133                                  false, // do not initialize for faster startup
134                                  Thread.currentThread().getContextClassLoader());
135         }
136         catch (ClassNotFoundException ignore)
137         {
138             // fallback: Try ClassLoader for ClassUtils (i.e. the myfaces.jar lib)
139             return Class.forName(type,
140                                  false, // do not initialize for faster startup
141                                  ClassUtils.class.getClassLoader());
142         }
143     }
144 
145 
146     /**
147      * Same as {@link #classForName(String)}, but throws a RuntimeException
148      * (FacesException) instead of a ClassNotFoundException.
149      *
150      * @return the corresponding Class
151      * @throws NullPointerException if type is null
152      * @throws FacesException if class not found
153      */
154     public static Class simpleClassForName(String type)
155     {
156         try
157         {
158             return classForName(type);
159         }
160         catch (ClassNotFoundException e)
161         {
162             log.error("Class " + type + " not found", e);
163             throw new FacesException(e);
164         }
165     }
166 
167 
168     /**
169      * Similar as {@link #classForName(String)}, but also supports primitive types
170      * and arrays as specified for the JavaType element in the JavaServer Faces Config DTD.
171      *
172      * @param type fully qualified class name or name of a primitive type, both optionally
173      *             followed by "[]" to indicate an array type
174      * @return the corresponding Class
175      * @throws NullPointerException if type is null
176      * @throws ClassNotFoundException
177      */
178     public static Class javaTypeToClass(String type)
179         throws ClassNotFoundException
180     {
181         if (type == null) throw new NullPointerException("type");
182 
183         // try common types and arrays of common types first
184         Class clazz = (Class) COMMON_TYPES.get(type);
185         if (clazz != null)
186         {
187             return clazz;
188         }
189 
190         int len = type.length();
191         if (len > 2 && type.charAt(len - 1) == ']' && type.charAt(len - 2) == '[')
192         {
193             String componentType = type.substring(0, len - 2);
194             Class componentTypeClass = classForName(componentType);
195             return Array.newInstance(componentTypeClass, 0).getClass();
196         }
197         else
198         {
199             return classForName(type);
200         }
201     }
202 
203 
204     /**
205      * Same as {@link #javaTypeToClass(String)}, but throws a RuntimeException
206      * (FacesException) instead of a ClassNotFoundException.
207      *
208      * @return the corresponding Class
209      * @throws NullPointerException if type is null
210      * @throws FacesException if class not found
211      */
212     public static Class simpleJavaTypeToClass(String type)
213     {
214         try
215         {
216             return javaTypeToClass(type);
217         }
218         catch (ClassNotFoundException e)
219         {
220             log.error("Class " + type + " not found", e);
221             throw new FacesException(e);
222         }
223     }
224 
225     public static InputStream getResourceAsStream(String resource)
226     {
227         InputStream stream = Thread.currentThread().getContextClassLoader()
228                                 .getResourceAsStream(resource);
229         if (stream == null)
230         {
231             // fallback
232             stream = ClassUtils.class.getClassLoader().getResourceAsStream(resource);
233         }
234         return stream;
235     }
236 
237     /**
238      * @param resource       Name of resource(s) to find in classpath
239      * @param defaultObject  The default object to use to determine the class loader (if none associated with current thread.)
240      * @return Iterator over URL Objects
241      */
242     public static Iterator getResources(String resource, Object defaultObject)
243     {
244         try
245         {
246             Enumeration resources = getCurrentLoader(defaultObject).getResources(resource);
247             List lst = new ArrayList();
248             while (resources.hasMoreElements())
249             {
250                 lst.add(resources.nextElement());
251             }
252             return lst.iterator();
253         }
254         catch (IOException e)
255         {
256             log.error(e.getMessage(), e);
257             throw new FacesException(e);
258         }
259     }
260 
261 
262     public static Object newInstance(String type)
263         throws FacesException
264     {
265         if (type == null) return null;
266         return newInstance(simpleClassForName(type));
267     }
268 
269     public static Object newInstance(String type, Class expectedType) throws FacesException
270     {
271         return newInstance(type, expectedType == null ? null : new Class[] {expectedType});
272     }
273 
274     public static Object newInstance(String type, Class[] expectedTypes)
275     {
276         if (type == null)
277             return null;        
278         
279         Class clazzForName = simpleClassForName(type);
280         
281         if(expectedTypes != null)
282         {
283             for (int i = 0, size = expectedTypes.length; i < size; i++)
284             {
285                 if (!expectedTypes[i].isAssignableFrom(clazzForName))
286                 {
287                     throw new FacesException("'" + type + "' does not implement expected type '" + expectedTypes[i]
288                             + "'");
289                 }
290             }
291         }
292         
293         return newInstance(clazzForName);
294     }
295 
296     public static Object newInstance(Class clazz)
297         throws FacesException
298     {
299         try
300         {
301             return clazz.newInstance();
302         }
303         catch(NoClassDefFoundError e)
304         {
305             log.error("Class : "+clazz.getName()+" not found.",e);
306             throw new FacesException(e);
307         }
308         catch (InstantiationException e)
309         {
310             log.error(e.getMessage(), e);
311             throw new FacesException(e);
312         }
313         catch (IllegalAccessException e)
314         {
315             log.error(e.getMessage(), e);
316             throw new FacesException(e);
317         }
318     }
319 
320     public static Object convertToType(Object value, Class desiredClass)
321     {
322         if (value == null) return null;
323 
324         try
325         {
326             // Use coersion implemented by JSP EL for consistency with EL
327             // expressions. Additionally, it caches some of the coersions.
328             //return Coercions.coerce(value, desiredClass, COERCION_LOGGER);
329             //return coerce(value, desiredClass);
330             return _Coercions.coerce(value, desiredClass);
331         }
332         catch (ELException e)
333         {
334             String message = "Cannot coerce " + value.getClass().getName()
335                              + " to " + desiredClass.getName();
336             log.error(message, e);
337             throw new FacesException(message, e);
338         }
339     }
340     
341     /**
342      * Gets the ClassLoader associated with the current thread.  Returns the class loader associated with
343      * the specified default object if no context loader is associated with the current thread.
344      *
345      * @param defaultObject The default object to use to determine the class loader (if none associated with current thread.)
346      * @return ClassLoader
347      */
348     protected static ClassLoader getCurrentLoader(Object defaultObject)
349     {
350         ClassLoader loader = Thread.currentThread().getContextClassLoader();
351         if(loader == null)
352         {
353             loader = defaultObject.getClass().getClassLoader();
354         }
355         return loader;
356     }
357 }