001: /*
002: * Copyright 2004 The Apache Software Foundation.
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: * http://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: package javax.faces.component;
017:
018: import org.apache.commons.logging.Log;
019: import org.apache.commons.logging.LogFactory;
020:
021: import javax.faces.FacesException;
022: import javax.faces.context.FacesContext;
023: import javax.el.ExpressionFactory;
024: import java.io.InputStream;
025: import java.io.IOException;
026: import java.lang.reflect.Array;
027: import java.util.*;
028:
029: /**
030: * @author Manfred Geiler (latest modification by $Author: mbr $)
031: * @author Anton Koinov
032: * @version $Revision: 518532 $ $Date: 2007-03-15 10:13:01 +0100 (Do, 15 Mrz 2007) $
033: */
034: final class _ClassUtils {
035: //~ Static fields/initializers -----------------------------------------------------------------
036:
037: private static final Log log = LogFactory.getLog(_ClassUtils.class);
038:
039: public static final Class BOOLEAN_ARRAY_CLASS = boolean[].class;
040: public static final Class BYTE_ARRAY_CLASS = byte[].class;
041: public static final Class CHAR_ARRAY_CLASS = char[].class;
042: public static final Class SHORT_ARRAY_CLASS = short[].class;
043: public static final Class INT_ARRAY_CLASS = int[].class;
044: public static final Class LONG_ARRAY_CLASS = long[].class;
045: public static final Class FLOAT_ARRAY_CLASS = float[].class;
046: public static final Class DOUBLE_ARRAY_CLASS = double[].class;
047: public static final Class OBJECT_ARRAY_CLASS = Object[].class;
048: public static final Class BOOLEAN_OBJECT_ARRAY_CLASS = Boolean[].class;
049: public static final Class BYTE_OBJECT_ARRAY_CLASS = Byte[].class;
050: public static final Class CHARACTER_OBJECT_ARRAY_CLASS = Character[].class;
051: public static final Class SHORT_OBJECT_ARRAY_CLASS = Short[].class;
052: public static final Class INTEGER_OBJECT_ARRAY_CLASS = Integer[].class;
053: public static final Class LONG_OBJECT_ARRAY_CLASS = Long[].class;
054: public static final Class FLOAT_OBJECT_ARRAY_CLASS = Float[].class;
055: public static final Class DOUBLE_OBJECT_ARRAY_CLASS = Double[].class;
056: public static final Class STRING_OBJECT_ARRAY_CLASS = String[].class;
057:
058: public static final Map COMMON_TYPES = new HashMap(64);
059: static {
060: COMMON_TYPES.put("byte", Byte.TYPE);
061: COMMON_TYPES.put("char", Character.TYPE);
062: COMMON_TYPES.put("double", Double.TYPE);
063: COMMON_TYPES.put("float", Float.TYPE);
064: COMMON_TYPES.put("int", Integer.TYPE);
065: COMMON_TYPES.put("long", Long.TYPE);
066: COMMON_TYPES.put("short", Short.TYPE);
067: COMMON_TYPES.put("boolean", Boolean.TYPE);
068: COMMON_TYPES.put("void", Void.TYPE);
069: COMMON_TYPES.put("java.lang.Object", Object.class);
070: COMMON_TYPES.put("java.lang.Boolean", Boolean.class);
071: COMMON_TYPES.put("java.lang.Byte", Byte.class);
072: COMMON_TYPES.put("java.lang.Character", Character.class);
073: COMMON_TYPES.put("java.lang.Short", Short.class);
074: COMMON_TYPES.put("java.lang.Integer", Integer.class);
075: COMMON_TYPES.put("java.lang.Long", Long.class);
076: COMMON_TYPES.put("java.lang.Float", Float.class);
077: COMMON_TYPES.put("java.lang.Double", Double.class);
078: COMMON_TYPES.put("java.lang.String", String.class);
079:
080: COMMON_TYPES.put("byte[]", BYTE_ARRAY_CLASS);
081: COMMON_TYPES.put("char[]", CHAR_ARRAY_CLASS);
082: COMMON_TYPES.put("double[]", DOUBLE_ARRAY_CLASS);
083: COMMON_TYPES.put("float[]", FLOAT_ARRAY_CLASS);
084: COMMON_TYPES.put("int[]", INT_ARRAY_CLASS);
085: COMMON_TYPES.put("long[]", LONG_ARRAY_CLASS);
086: COMMON_TYPES.put("short[]", SHORT_ARRAY_CLASS);
087: COMMON_TYPES.put("boolean[]", BOOLEAN_ARRAY_CLASS);
088: COMMON_TYPES.put("java.lang.Object[]", OBJECT_ARRAY_CLASS);
089: COMMON_TYPES.put("java.lang.Boolean[]",
090: BOOLEAN_OBJECT_ARRAY_CLASS);
091: COMMON_TYPES.put("java.lang.Byte[]", BYTE_OBJECT_ARRAY_CLASS);
092: COMMON_TYPES.put("java.lang.Character[]",
093: CHARACTER_OBJECT_ARRAY_CLASS);
094: COMMON_TYPES.put("java.lang.Short[]", SHORT_OBJECT_ARRAY_CLASS);
095: COMMON_TYPES.put("java.lang.Integer[]",
096: INTEGER_OBJECT_ARRAY_CLASS);
097: COMMON_TYPES.put("java.lang.Long[]", LONG_OBJECT_ARRAY_CLASS);
098: COMMON_TYPES.put("java.lang.Float[]", FLOAT_OBJECT_ARRAY_CLASS);
099: COMMON_TYPES.put("java.lang.Double[]",
100: DOUBLE_OBJECT_ARRAY_CLASS);
101: COMMON_TYPES.put("java.lang.String[]",
102: STRING_OBJECT_ARRAY_CLASS);
103: // array of void is not a valid type
104: }
105:
106: /** utility class, do not instantiate */
107: private _ClassUtils() {
108: // utility class, disable instantiation
109: }
110:
111: //~ Methods ------------------------------------------------------------------------------------
112:
113: /**
114: * Tries a Class.loadClass with the context class loader of the current thread first and
115: * automatically falls back to the ClassUtils class loader (i.e. the loader of the
116: * myfaces.jar lib) if necessary.
117: *
118: * @param type fully qualified name of a non-primitive non-array class
119: * @return the corresponding Class
120: * @throws NullPointerException if type is null
121: * @throws ClassNotFoundException
122: */
123: public static Class classForName(String type)
124: throws ClassNotFoundException {
125: if (type == null)
126: throw new NullPointerException("type");
127: try {
128: // Try WebApp ClassLoader first
129: return Class.forName(type, false, // do not initialize for faster startup
130: Thread.currentThread().getContextClassLoader());
131: } catch (ClassNotFoundException ignore) {
132: // fallback: Try ClassLoader for ClassUtils (i.e. the myfaces.jar lib)
133: return Class.forName(type, false, // do not initialize for faster startup
134: _ClassUtils.class.getClassLoader());
135: }
136: }
137:
138: /**
139: * Same as {@link #classForName(String)}, but throws a RuntimeException
140: * (FacesException) instead of a ClassNotFoundException.
141: *
142: * @return the corresponding Class
143: * @throws NullPointerException if type is null
144: * @throws FacesException if class not found
145: */
146: public static Class simpleClassForName(String type) {
147: try {
148: return classForName(type);
149: } catch (ClassNotFoundException e) {
150: log.error("Class " + type + " not found", e);
151: throw new FacesException(e);
152: }
153: }
154:
155: /**
156: * Similar as {@link #classForName(String)}, but also supports primitive types
157: * and arrays as specified for the JavaType element in the JavaServer Faces Config DTD.
158: *
159: * @param type fully qualified class name or name of a primitive type, both optionally
160: * followed by "[]" to indicate an array type
161: * @return the corresponding Class
162: * @throws NullPointerException if type is null
163: * @throws ClassNotFoundException
164: */
165: public static Class javaTypeToClass(String type)
166: throws ClassNotFoundException {
167: if (type == null)
168: throw new NullPointerException("type");
169:
170: // try common types and arrays of common types first
171: Class clazz = (Class) COMMON_TYPES.get(type);
172: if (clazz != null) {
173: return clazz;
174: }
175:
176: int len = type.length();
177: if (len > 2 && type.charAt(len - 1) == ']'
178: && type.charAt(len - 2) == '[') {
179: String componentType = type.substring(0, len - 2);
180: Class componentTypeClass = classForName(componentType);
181: return Array.newInstance(componentTypeClass, 0).getClass();
182: }
183:
184: return classForName(type);
185:
186: }
187:
188: /**
189: * Same as {@link #javaTypeToClass(String)}, but throws a RuntimeException
190: * (FacesException) instead of a ClassNotFoundException.
191: *
192: * @return the corresponding Class
193: * @throws NullPointerException if type is null
194: * @throws FacesException if class not found
195: */
196: public static Class simpleJavaTypeToClass(String type) {
197: try {
198: return javaTypeToClass(type);
199: } catch (ClassNotFoundException e) {
200: log.error("Class " + type + " not found", e);
201: throw new FacesException(e);
202: }
203: }
204:
205: public static InputStream getResourceAsStream(String resource) {
206: InputStream stream = Thread.currentThread()
207: .getContextClassLoader().getResourceAsStream(resource);
208: if (stream == null) {
209: // fallback
210: stream = _ClassUtils.class.getClassLoader()
211: .getResourceAsStream(resource);
212: }
213: return stream;
214: }
215:
216: /**
217: * @param resource Name of resource(s) to find in classpath
218: * @param defaultObject The default object to use to determine the class loader (if none associated with current thread.)
219: * @return Iterator over URL Objects
220: */
221: public static Iterator getResources(String resource,
222: Object defaultObject) {
223: try {
224: Enumeration resources = getCurrentLoader(defaultObject)
225: .getResources(resource);
226: List lst = new ArrayList();
227: while (resources.hasMoreElements()) {
228: lst.add(resources.nextElement());
229: }
230: return lst.iterator();
231: } catch (IOException e) {
232: log.error(e.getMessage(), e);
233: throw new FacesException(e);
234: }
235: }
236:
237: public static Object newInstance(String type) throws FacesException {
238: if (type == null)
239: return null;
240: return newInstance(simpleClassForName(type));
241: }
242:
243: public static Object newInstance(String type, Class expectedType)
244: throws FacesException {
245: return newInstance(type, expectedType == null ? null
246: : new Class[] { expectedType });
247: }
248:
249: public static Object newInstance(String type, Class[] expectedTypes) {
250: if (type == null)
251: return null;
252:
253: Class clazzForName = simpleClassForName(type);
254:
255: if (expectedTypes != null) {
256: for (int i = 0, size = expectedTypes.length; i < size; i++) {
257: if (!expectedTypes[i].isAssignableFrom(clazzForName)) {
258: throw new FacesException("'" + type
259: + "' does not implement expected type '"
260: + expectedTypes[i] + "'");
261: }
262: }
263: }
264:
265: return newInstance(clazzForName);
266: }
267:
268: public static Object newInstance(Class clazz) throws FacesException {
269: try {
270: return clazz.newInstance();
271: } catch (NoClassDefFoundError e) {
272: log.error("Class : " + clazz.getName() + " not found.", e);
273: throw new FacesException(e);
274: } catch (InstantiationException e) {
275: log.error(e.getMessage(), e);
276: throw new FacesException(e);
277: } catch (IllegalAccessException e) {
278: log.error(e.getMessage(), e);
279: throw new FacesException(e);
280: }
281: }
282:
283: public static Object convertToType(Object value, Class desiredClass) {
284: if (value == null)
285: return null;
286:
287: try {
288: ExpressionFactory expFactory = FacesContext
289: .getCurrentInstance().getApplication()
290: .getExpressionFactory();
291: return expFactory.coerceToType(value, desiredClass);
292: } catch (Exception e) {
293: String message = "Cannot coerce "
294: + value.getClass().getName() + " to "
295: + desiredClass.getName();
296: log.error(message, e);
297: throw new FacesException(message, e);
298: }
299: }
300:
301: /**
302: * Gets the ClassLoader associated with the current thread. Returns the class loader associated with
303: * the specified default object if no context loader is associated with the current thread.
304: *
305: * @param defaultObject The default object to use to determine the class loader (if none associated with current thread.)
306: * @return ClassLoader
307: */
308: protected static ClassLoader getCurrentLoader(Object defaultObject) {
309: ClassLoader loader = Thread.currentThread()
310: .getContextClassLoader();
311: if (loader == null) {
312: loader = defaultObject.getClass().getClassLoader();
313: }
314: return loader;
315: }
316: }
|