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