KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > directwebremoting > util > LocalUtil


1 /*
2  * Copyright 2005 Joe Walker
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.directwebremoting.util;
17
18 import java.io.IOException JavaDoc;
19 import java.io.InputStream JavaDoc;
20 import java.io.RandomAccessFile JavaDoc;
21 import java.lang.reflect.Field JavaDoc;
22 import java.lang.reflect.InvocationTargetException JavaDoc;
23 import java.lang.reflect.Method JavaDoc;
24 import java.net.URLDecoder JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Arrays JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Locale JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.Set JavaDoc;
33
34 import javax.servlet.ServletConfig JavaDoc;
35 import javax.servlet.ServletContext JavaDoc;
36 import javax.servlet.http.HttpServletRequest JavaDoc;
37 import javax.servlet.http.HttpServletResponse JavaDoc;
38 import javax.servlet.http.HttpSession JavaDoc;
39 import javax.xml.transform.TransformerFactoryConfigurationError JavaDoc;
40
41 /**
42  * Various utilities, mostly to make up for JDK 1.4 functionallity that is not
43  * in JDK 1.3
44  * @author Joe Walker [joe at getahead dot ltd dot uk]
45  */

46 public final class LocalUtil
47 {
48     /**
49      * splitInbound() returns the type info in this parameter
50      */

51     public static final int INBOUND_INDEX_TYPE = 0;
52
53     /**
54      * splitInbound() returns the value info in this parameter
55      */

56     public static final int INBOUND_INDEX_VALUE = 1;
57
58     /**
59      * Prevent instansiation
60      */

61     private LocalUtil()
62     {
63     }
64
65     /**
66      * Replacement for String#replaceAll(String, String) in JDK 1.4+
67      * @param text source text
68      * @param repl the stuff to get rid of
69      * @param with the stuff to replace it with
70      * @return replaced text or null if any args are null
71      */

72     public static String JavaDoc replace(String JavaDoc text, String JavaDoc repl, String JavaDoc with)
73     {
74         if (text == null || repl == null || with == null || repl.length() == 0)
75         {
76             return text;
77         }
78
79         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(text.length());
80         int searchFrom = 0;
81         while (true)
82         {
83             int foundAt = text.indexOf(repl, searchFrom);
84             if (foundAt == -1)
85             {
86                 break;
87             }
88
89             buf.append(text.substring(searchFrom, foundAt)).append(with);
90             searchFrom = foundAt + repl.length();
91         }
92         buf.append(text.substring(searchFrom));
93
94         return buf.toString();
95     }
96
97     /**
98      * Determines if the specified string is permissible as a Java identifier.
99      * Returns true if the string is non-null, non-zero length with a Java
100      * identifier start as the first character and Java identifier parts in all
101      * remaining characters.
102      * @param test the string to be tested.
103      * @return true if the string is a Java identifier, false otherwise.
104      * @see java.lang.Character#isJavaIdentifierPart(char)
105      * @see java.lang.Character#isJavaIdentifierStart(char)
106      */

107     public static boolean isJavaIdentifier(String JavaDoc test)
108     {
109         if (test == null || test.length() == 0)
110         {
111             return false;
112         }
113
114         if (!Character.isJavaIdentifierStart(test.charAt(0)))
115         {
116             return false;
117         }
118
119         for (int i = 1; i < test.length(); i++)
120         {
121             if (!Character.isJavaIdentifierPart(test.charAt(i)))
122             {
123                 return false;
124             }
125         }
126
127         return true;
128     }
129
130     /**
131      * True if c1 is java.lang.Boolean and c2 is boolean, etc.
132      * @param c1 the first class to test
133      * @param c2 the second class to test
134      * @return true if the classes are equivalent
135      */

136     public static boolean isEquivalent(Class JavaDoc c1, Class JavaDoc c2)
137     {
138         if (c1 == Boolean JavaDoc.class || c1 == Boolean.TYPE)
139         {
140             return c2 == Boolean JavaDoc.class || c2 == Boolean.TYPE;
141         }
142         else if (c1 == Byte JavaDoc.class || c1 == Byte.TYPE)
143         {
144             return c2 == Byte JavaDoc.class || c2 == Byte.TYPE;
145         }
146         else if (c1 == Character JavaDoc.class || c1 == Character.TYPE)
147         {
148             return c2 == Character JavaDoc.class || c2 == Character.TYPE;
149         }
150         else if (c1 == Short JavaDoc.class || c1 == Short.TYPE)
151         {
152             return c2 == Short JavaDoc.class || c2 == Short.TYPE;
153         }
154         else if (c1 == Integer JavaDoc.class || c1 == Integer.TYPE)
155         {
156             return c2 == Integer JavaDoc.class || c2 == Integer.TYPE;
157         }
158         else if (c1 == Long JavaDoc.class || c1 == Long.TYPE)
159         {
160             return c2 == Long JavaDoc.class || c2 == Long.TYPE;
161         }
162         else if (c1 == Float JavaDoc.class || c1 == Float.TYPE)
163         {
164             return c2 == Float JavaDoc.class || c2 == Float.TYPE;
165         }
166         else if (c1 == Double JavaDoc.class || c1 == Double.TYPE)
167         {
168             return c2 == Double JavaDoc.class || c2 == Double.TYPE;
169         }
170         else if (c1 == Void JavaDoc.class || c1 == Void.TYPE)
171         {
172             return c2 == Void JavaDoc.class || c2 == Void.TYPE;
173         }
174
175         return false;
176     }
177
178     /**
179      * @param type The class to de-primitivize
180      * @return The non-privitive version of the class
181      */

182     public static Class JavaDoc getNonPrimitiveType(Class JavaDoc type)
183     {
184         if (!type.isPrimitive())
185         {
186             return type;
187         }
188         else if (type == Boolean.TYPE)
189         {
190             return Boolean JavaDoc.class;
191         }
192         else if (type == Byte.TYPE)
193         {
194             return Byte JavaDoc.class;
195         }
196         else if (type == Character.TYPE)
197         {
198             return Character JavaDoc.class;
199         }
200         else if (type == Short.TYPE)
201         {
202             return Short JavaDoc.class;
203         }
204         else if (type == Integer.TYPE)
205         {
206             return Integer JavaDoc.class;
207         }
208         else if (type == Long.TYPE)
209         {
210             return Long JavaDoc.class;
211         }
212         else if (type == Float.TYPE)
213         {
214             return Float JavaDoc.class;
215         }
216         else if (type == Double.TYPE)
217         {
218             return Double JavaDoc.class;
219         }
220         else if (type == Void.TYPE)
221         {
222             return Void JavaDoc.class;
223         }
224
225         return null;
226     }
227
228     /**
229      * Add headers to prevent browers and proxies from caching this reply.
230      * @param resp The response to add headers to
231      */

232     public static void addNoCacheHeaders(HttpServletResponse JavaDoc resp)
233     {
234         // Set standard HTTP/1.1 no-cache headers.
235
resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
236
237         // Set IE extended HTTP/1.1 no-cache headers (use addHeader).
238
resp.addHeader("Cache-Control", "post-check=0, pre-check=0");
239
240         // Set standard HTTP/1.0 no-cache header.
241
resp.setHeader("Pragma", "no-cache");
242
243         // Set to expire far in the past. Prevents caching at the proxy server
244
resp.setHeader("Expires", "Sat, 6 May 1995 12:00:00 GMT");
245     }
246
247     /**
248      * Is this class one that we auto fill, so the user can ignore?
249      * @param paramType The type to test
250      * @return true if the type is a Servlet type
251      */

252     public static boolean isServletClass(Class JavaDoc paramType)
253     {
254         return paramType == HttpServletRequest JavaDoc.class ||
255                paramType == HttpServletResponse JavaDoc.class ||
256                paramType == ServletConfig JavaDoc.class ||
257                paramType == ServletContext JavaDoc.class ||
258                paramType == HttpSession JavaDoc.class;
259     }
260
261     /**
262      * URL decode a value. This method gets around the lack of a
263      * decode(String, String) method in JDK 1.3.
264      * @param value The string to decode
265      * @return The decoded string
266      */

267     public static String JavaDoc decode(String JavaDoc value)
268     {
269         if (!testedDecoder)
270         {
271             try
272             {
273                 decode14 = URLDecoder JavaDoc.class.getMethod("decode", new Class JavaDoc[] { String JavaDoc.class, String JavaDoc.class });
274             }
275             catch (Exception JavaDoc ex)
276             {
277                 if (!warn13)
278                 {
279                     log.warn("URLDecoder.decode(String, String) is not available. Falling back to 1.3 variant.");
280                     warn13 = true;
281                 }
282             }
283
284             testedDecoder = true;
285         }
286
287         if (decode14 != null)
288         {
289             try
290             {
291                 return (String JavaDoc) decode14.invoke(null, new Object JavaDoc[] { value, "UTF-8" });
292             }
293             catch (Exception JavaDoc ex)
294             {
295                 log.warn("Failed to use JDK 1.4 decoder", ex);
296             }
297         }
298
299         return URLDecoder.decode(value);
300     }
301
302     /**
303      * Set use reflection to set the setters on the object called by the keys
304      * in the params map with the corresponding values
305      * @param object The object to setup
306      * @param params The settings to use
307      * @param ignore List of keys to not warn about if they are not properties
308      * Note only the warning is skipped, we still try the setter
309      */

310     public static void setParams(Object JavaDoc object, Map JavaDoc params, List JavaDoc ignore)
311     {
312         for (Iterator JavaDoc it = params.entrySet().iterator(); it.hasNext();)
313         {
314             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
315             String JavaDoc key = (String JavaDoc) entry.getKey();
316             Object JavaDoc value = entry.getValue();
317
318             try
319             {
320                 setProperty(object, key, value);
321             }
322             catch (NoSuchMethodException JavaDoc ex)
323             {
324                 if (ignore != null && !ignore.contains(key))
325                 {
326                     log.warn("No property '" + key + "' on " + object.getClass().getName());
327                 }
328             }
329             catch (InvocationTargetException JavaDoc ex)
330             {
331                 log.warn("Error setting " + key + "=" + value + " on " + object.getClass().getName(), ex.getTargetException());
332             }
333             catch (Exception JavaDoc ex)
334             {
335                 log.warn("Error setting " + key + "=" + value + " on " + object.getClass().getName(), ex);
336             }
337         }
338     }
339
340     /**
341      * Set a property on an object using reflection
342      * @param object The object to call the setter on
343      * @param key The name of the property to set.
344      * @param value The new value to use for the property
345      * @throws NoSuchMethodException Passed on from reflection code
346      * @throws SecurityException Passed on from reflection code
347      * @throws IllegalAccessException Passed on from reflection code
348      * @throws IllegalArgumentException Passed on from reflection code
349      * @throws InvocationTargetException Passed on from reflection code
350      */

351     public static void setProperty(Object JavaDoc object, String JavaDoc key, Object JavaDoc value) throws NoSuchMethodException JavaDoc, SecurityException JavaDoc, IllegalAccessException JavaDoc, IllegalArgumentException JavaDoc, InvocationTargetException JavaDoc
352     {
353         Class JavaDoc real = object.getClass();
354
355         String JavaDoc setterName = "set" + key.substring(0, 1).toUpperCase(Locale.ENGLISH) + key.substring(1);
356
357         try
358         {
359             // Can we work with whatever type we were given?
360
Method JavaDoc method = real.getMethod(setterName, new Class JavaDoc[] { value.getClass() });
361             method.invoke(object, new Object JavaDoc[] { value });
362             return;
363         }
364         catch (NoSuchMethodException JavaDoc ex)
365         {
366             // If it is a string then next we try to coerce it to the right type
367
// otherwise we give up.
368
if (!(value instanceof String JavaDoc))
369             {
370                 throw ex;
371             }
372         }
373
374         Method JavaDoc[] methods = real.getMethods();
375         for (int i = 0; i < methods.length; i++)
376         {
377             Method JavaDoc setter = methods[i];
378
379             if (setter.getName().equals(setterName) && setter.getParameterTypes().length == 1)
380             {
381                 Class JavaDoc propertyType = setter.getParameterTypes()[0];
382                 try
383                 {
384                     Object JavaDoc param = LocalUtil.simpleConvert((String JavaDoc) value, propertyType);
385                     setter.invoke(object, new Object JavaDoc[] { param });
386                     return;
387                 }
388                 catch (IllegalArgumentException JavaDoc ex)
389                 {
390                     // The conversion failed - it was speculative anyway so we
391
// don't worry now
392
}
393             }
394         }
395
396         throw new NoSuchMethodException JavaDoc("Failed to find a property called: " + key + " on " + object.getClass().getName());
397     }
398
399     /**
400      * Can the type be used in a call to {@link #simpleConvert(String, Class)}?
401      * @param paramType The type to test
402      * @return true if the type is acceptable to simpleConvert()
403      */

404     public static boolean isTypeSimplyConvertable(Class JavaDoc paramType)
405     {
406         return paramType == String JavaDoc.class ||
407             paramType == Integer JavaDoc.class ||
408             paramType == Integer.TYPE ||
409             paramType == Short JavaDoc.class ||
410             paramType == Short.TYPE ||
411             paramType == Byte JavaDoc.class ||
412             paramType == Byte.TYPE ||
413             paramType == Long JavaDoc.class ||
414             paramType == Long.TYPE ||
415             paramType == Float JavaDoc.class ||
416             paramType == Float.TYPE ||
417             paramType == Double JavaDoc.class ||
418             paramType == Double.TYPE ||
419             paramType == Character JavaDoc.class ||
420             paramType == Character.TYPE ||
421             paramType == Boolean JavaDoc.class ||
422             paramType == Boolean.TYPE;
423     }
424
425     /**
426      * A very simple conversion function for all the IoC style setup and
427      * reflection that we are doing.
428      * @param value The value to convert
429      * @param paramType The type to convert to. Currently ony primitive types and
430      * String are supported.
431      * @return The converted object.
432      */

433     public static Object JavaDoc simpleConvert(String JavaDoc value, Class JavaDoc paramType)
434     {
435         if (paramType == String JavaDoc.class)
436         {
437             return value;
438         }
439
440         if (paramType == Character JavaDoc.class || paramType == Character.TYPE)
441         {
442             if (value.length() == 1)
443             {
444                 return new Character JavaDoc(value.charAt(0));
445             }
446             else
447             {
448                 throw new IllegalArgumentException JavaDoc("Can't more than one character in string - can't convert to char: '" + value + "'");
449             }
450         }
451
452         String JavaDoc trimValue = value.trim();
453
454         if (paramType == Boolean JavaDoc.class)
455         {
456             if (trimValue.length() == 0)
457             {
458                 return null;
459             }
460
461             return Boolean.valueOf(trimValue);
462         }
463
464         if (paramType == Boolean.TYPE)
465         {
466             return Boolean.valueOf(trimValue);
467         }
468
469         if (paramType == Integer JavaDoc.class)
470         {
471             if (trimValue.length() == 0)
472             {
473                 return null;
474             }
475
476             return Integer.valueOf(trimValue);
477         }
478
479         if (paramType == Integer.TYPE)
480         {
481             if (trimValue.length() == 0)
482             {
483                 return new Integer JavaDoc(0);
484             }
485
486             return Integer.valueOf(trimValue);
487         }
488
489         if (paramType == Short JavaDoc.class)
490         {
491             if (trimValue.length() == 0)
492             {
493                 return null;
494             }
495
496             return Short.valueOf(trimValue);
497         }
498
499         if (paramType == Short.TYPE)
500         {
501             if (trimValue.length() == 0)
502             {
503                 return new Short JavaDoc((short) 0);
504             }
505
506             return Short.valueOf(trimValue);
507         }
508
509         if (paramType == Byte JavaDoc.class)
510         {
511             if (trimValue.length() == 0)
512             {
513                 return null;
514             }
515
516             return Byte.valueOf(trimValue);
517         }
518
519         if (paramType == Byte.TYPE)
520         {
521             if (trimValue.length() == 0)
522             {
523                 return new Byte JavaDoc((byte) 0);
524             }
525
526             return Byte.valueOf(trimValue);
527         }
528
529         if (paramType == Long JavaDoc.class)
530         {
531             if (trimValue.length() == 0)
532             {
533                 return null;
534             }
535
536             return Long.valueOf(trimValue);
537         }
538
539         if (paramType == Long.TYPE)
540         {
541             if (trimValue.length() == 0)
542             {
543                 return new Long JavaDoc(0);
544             }
545
546             return Long.valueOf(trimValue);
547         }
548
549         if (paramType == Float JavaDoc.class)
550         {
551             if (trimValue.length() == 0)
552             {
553                 return null;
554             }
555
556             return Float.valueOf(trimValue);
557         }
558
559         if (paramType == Float.TYPE)
560         {
561             if (trimValue.length() == 0)
562             {
563                 return new Float JavaDoc(0);
564             }
565
566             return Float.valueOf(trimValue);
567         }
568
569         if (paramType == Double JavaDoc.class)
570         {
571             if (trimValue.length() == 0)
572             {
573                 return null;
574             }
575
576             return Double.valueOf(trimValue);
577         }
578
579         if (paramType == Double.TYPE)
580         {
581             if (trimValue.length() == 0)
582             {
583                 return new Double JavaDoc(0);
584             }
585
586             return Double.valueOf(trimValue);
587         }
588
589         throw new IllegalArgumentException JavaDoc("Unsupported conversion type: " + paramType.getName());
590     }
591
592     /**
593      * Get the short class name (i.e. without the package part)
594      * @param clazz the class to get the short name of
595      * @return the class name of the class without the package name
596      */

597     public static String JavaDoc getShortClassName(Class JavaDoc clazz)
598     {
599         String JavaDoc className = clazz.getName();
600
601         char[] chars = className.toCharArray();
602         int lastDot = 0;
603         for (int i = 0; i < chars.length; i++)
604         {
605             if (chars[i] == '.')
606             {
607                 lastDot = i + 1;
608             }
609             else if (chars[i] == '$')
610             {
611                 chars[i] = '.';
612             }
613         }
614
615         // This might come up in scans for locale/charset issues. It's not an
616
// issue since we are talking about chars.
617
return new String JavaDoc(chars, lastDot, chars.length - lastDot);
618     }
619
620     /**
621      * Is this object property one that we can use in a JSON style or do we need
622      * to get fancy. i.e does it contain only letters and numbers with an
623      * initial letter.
624      * @param name The name to test for JSON compatibility
625      * @return true if the name is simple
626      */

627     public static boolean isSimpleName(String JavaDoc name)
628     {
629         if (name.length() == 0)
630         {
631             return false;
632         }
633
634         if (JavascriptUtil.isReservedWord(name))
635         {
636             return false;
637         }
638
639         boolean isSimple = Character.isLetter(name.charAt(0));
640         for (int i = 1; isSimple && i < name.length(); i++)
641         {
642             if (!Character.isLetterOrDigit(name.charAt(i)))
643             {
644                 isSimple = false;
645             }
646         }
647
648         return isSimple;
649     }
650
651     /**
652      * Utility to essentially do Class forName and allow configurable
653      * Classloaders.
654      * <p>The initial implementation makes use of the context classloader for
655      * the current thread.
656      * @param className The class to create
657      * @return The class if it is safe or null otherwise.
658      * @throws ClassNotFoundException If <code>className</code> is not valid
659      */

660     public static Class JavaDoc classForName(String JavaDoc className) throws ClassNotFoundException JavaDoc
661     {
662         // Class.forName(className);
663
return Thread.currentThread().getContextClassLoader().loadClass(className);
664     }
665
666     /**
667      * Calling methods using reflection is useful for graceful fallback - this
668      * is a helper method to make this easy
669      * @param object The object to use as 'this'
670      * @param method The method to call, can be null in which case null is returned
671      * @param params The parameters to pass to the reflection call
672      * @return The results of calling method.invoke() or null
673      * @throws IllegalStateException If anything goes wrong
674      */

675     public static Object JavaDoc invoke(Object JavaDoc object, Method JavaDoc method, Object JavaDoc[] params) throws IllegalStateException JavaDoc
676     {
677         Object JavaDoc reply = null;
678         if (method != null)
679         {
680             try
681             {
682                 reply = method.invoke(object, params);
683             }
684             catch (InvocationTargetException JavaDoc ex)
685             {
686                 throw new IllegalStateException JavaDoc("InvocationTargetException calling " + method.getName() + ": " + ex.getTargetException().toString());
687             }
688             catch (Exception JavaDoc ex)
689             {
690                 throw new IllegalStateException JavaDoc("Reflection error calling " + method.getName() + ": " + ex.toString());
691             }
692         }
693
694         return reply;
695     }
696
697     /**
698      * Utility to essentially do Class forName with the assumption that the
699      * environment expects failures for missing jar files and can carry on if
700      * this process fails.
701      * @param name The name for debugging purposes
702      * @param className The class to create
703      * @param impl The implementation class - what should className do?
704      * @return The class if it is safe or null otherwise.
705      */

706     public static Class JavaDoc classForName(String JavaDoc name, String JavaDoc className, Class JavaDoc impl)
707     {
708         Class JavaDoc clazz;
709
710         try
711         {
712             clazz = classForName(className);
713         }
714         catch (ClassNotFoundException JavaDoc ex)
715         {
716             // We expect this sometimes, hence debug
717
log.debug("Skipping '" + name + "' due to ClassNotFoundException on " + className + ". Cause: " + ex.getMessage());
718             return null;
719         }
720         catch (NoClassDefFoundError JavaDoc ex)
721         {
722             // We expect this sometimes, hence debug
723
log.debug("Skipping '" + name + "' due to NoClassDefFoundError on " + className + ". Cause: " + ex.getMessage());
724             return null;
725         }
726         catch (TransformerFactoryConfigurationError JavaDoc ex)
727         {
728             // We expect this sometimes, hence debug
729
log.debug("Skipping '" + name + "' due to TransformerFactoryConfigurationError on " + className + ". Cause: " + ex.getMessage());
730             log.debug("Maybe you need to add xalan.jar to your webserver?");
731             return null;
732         }
733
734         // Check it is of the right type
735
if (!impl.isAssignableFrom(clazz))
736         {
737             log.error("Class '" + clazz.getName() + "' does not implement '" + impl.getName() + "'.");
738             return null;
739         }
740
741         // Check we can create it
742
try
743         {
744             clazz.newInstance();
745         }
746         catch (InstantiationException JavaDoc ex)
747         {
748             log.error("InstantiationException for '" + name + "' failed:", ex);
749             return null;
750         }
751         catch (IllegalAccessException JavaDoc ex)
752         {
753             log.error("IllegalAccessException for '" + name + "' failed:", ex);
754             return null;
755         }
756         catch (NoClassDefFoundError JavaDoc ex)
757         {
758             // We expect this sometimes, hence debug
759
log.debug("Skipping '" + name + "' due to NoClassDefFoundError on " + className + ". Cause: " + ex.getMessage());
760             return null;
761         }
762         catch (TransformerFactoryConfigurationError JavaDoc ex)
763         {
764             // We expect this sometimes, hence debug
765
log.debug("Skipping '" + name + "' due to TransformerFactoryConfigurationError on " + className + ". Cause: " + ex.getMessage());
766             log.debug("Maybe you need to add xalan.jar to your webserver?");
767             return null;
768         }
769         catch (Exception JavaDoc ex)
770         {
771             // For some reason we can't catch this?
772
if (ex instanceof ClassNotFoundException JavaDoc)
773             {
774                 // We expect this sometimes, hence debug
775
log.debug("Skipping '" + name + "' due to ClassNotFoundException on " + className + ". Cause: " + ex.getMessage());
776                 return null;
777             }
778             else
779             {
780                 log.error("Failed to load '" + name + "' (" + className + ")", ex);
781                 return null;
782             }
783         }
784
785         return clazz;
786     }
787
788     /**
789      * Utility to essentially do Class forName and newInstance with the
790      * assumption that the environment expects failures for missing jar files
791      * and can carry on if this process fails.
792      * @param name The name for debugging purposes
793      * @param className The class to create
794      * @param impl The implementation class - what should className do?
795      * @return The new instance if it is safe or null otherwise.
796      */

797     public static Object JavaDoc classNewInstance(String JavaDoc name, String JavaDoc className, Class JavaDoc impl)
798     {
799         Class JavaDoc clazz;
800
801         try
802         {
803             clazz = LocalUtil.classForName(className);
804         }
805         catch (ClassNotFoundException JavaDoc ex)
806         {
807             // We expect this sometimes, hence debug
808
log.debug("Skipping '" + name + "' due to ClassNotFoundException on " + className + ". Cause: " + ex.getMessage());
809             return null;
810         }
811         catch (NoClassDefFoundError JavaDoc ex)
812         {
813             // We expect this sometimes, hence debug
814
log.debug("Skipping '" + name + "' due to NoClassDefFoundError on " + className + ". Cause: " + ex.getMessage());
815             return null;
816         }
817         catch (TransformerFactoryConfigurationError JavaDoc ex)
818         {
819             // We expect this sometimes, hence debug
820
log.debug("Skipping '" + name + "' due to TransformerFactoryConfigurationError on " + className + ". Cause: " + ex.getMessage());
821             return null;
822         }
823
824         // Check it is of the right type
825
if (!impl.isAssignableFrom(clazz))
826         {
827             log.error("Class '" + clazz.getName() + "' does not implement '" + impl.getName() + "'.");
828             return null;
829         }
830
831         // Check we can create it
832
try
833         {
834             return clazz.newInstance();
835         }
836         catch (InstantiationException JavaDoc ex)
837         {
838             log.error("InstantiationException for '" + name + "' failed:", ex);
839             return null;
840         }
841         catch (IllegalAccessException JavaDoc ex)
842         {
843             log.error("IllegalAccessException for '" + name + "' failed:", ex);
844             return null;
845         }
846         catch (TransformerFactoryConfigurationError JavaDoc ex)
847         {
848             log.error("TransformerFactoryConfigurationError for '" + name + "' failed:", ex);
849             return null;
850         }
851         catch (Exception JavaDoc ex)
852         {
853             log.error("Failed to load creator '" + name + "', classname=" + className + ": ", ex);
854             return null;
855         }
856     }
857
858     /**
859      * InputStream closer that can cope if the input stream is null.
860      * If anything goes wrong, the errors are logged and ignored.
861      * @param in The resource to close
862      */

863     public static void close(InputStream JavaDoc in)
864     {
865         if (in == null)
866         {
867             return;
868         }
869
870         try
871         {
872             in.close();
873         }
874         catch (IOException JavaDoc ex)
875         {
876             log.warn(ex.getMessage(), ex);
877         }
878     }
879
880     /**
881      * InputStream closer that can cope if the input stream is null.
882      * If anything goes wrong, the errors are logged and ignored.
883      * @param in The resource to close
884      */

885     public static void close(RandomAccessFile JavaDoc in)
886     {
887         if (in == null)
888         {
889             return;
890         }
891
892         try
893         {
894             in.close();
895         }
896         catch (IOException JavaDoc ex)
897         {
898             log.warn(ex.getMessage(), ex);
899         }
900     }
901
902     /**
903      * Return a List of superclasses for the given class.
904      * @param clazz the class to look up
905      * @return the List of superclasses in order going up from this one
906      */

907     public static List JavaDoc getAllSuperclasses(Class JavaDoc clazz)
908     {
909         List JavaDoc classes = new ArrayList JavaDoc();
910
911         Class JavaDoc superclass = clazz.getSuperclass();
912         while (superclass != null)
913         {
914             classes.add(superclass);
915             superclass = superclass.getSuperclass();
916         }
917
918         return classes;
919     }
920
921     /**
922      * Return a list of all fields (whatever access status, and on whatever
923      * superclass they were defined) that can be found on this class.
924      * <p>This is like a union of {@link Class#getDeclaredFields()} which
925      * ignores and superclasses, and {@link Class#getFields()} which ignored
926      * non-pubic fields
927      * @param clazz The class to introspect
928      * @return The complete list of fields
929      */

930     public static Field JavaDoc[] getAllFields(Class JavaDoc clazz)
931     {
932         List JavaDoc classes = getAllSuperclasses(clazz);
933         classes.add(clazz);
934         return getAllFields(classes);
935     }
936
937     /**
938      * As {@link #getAllFields(Class)} but acts on a list of {@link Class}s and
939      * uses only {@link Class#getDeclaredFields()}.
940      * @param classes The list of classes to reflect on
941      * @return The complete list of fields
942      */

943     private static Field JavaDoc[] getAllFields(List JavaDoc classes)
944     {
945         Set JavaDoc fields = new HashSet JavaDoc();
946         for (Iterator JavaDoc it = classes.iterator(); it.hasNext();)
947         {
948             Class JavaDoc clazz = (Class JavaDoc) it.next();
949             fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
950         }
951
952         return (Field JavaDoc[]) fields.toArray(new Field JavaDoc[fields.size()]);
953     }
954
955     /**
956      * The log stream
957      */

958     private static final Logger log = Logger.getLogger(LocalUtil.class);
959
960     /**
961      * Have we given a warning about URLDecoder.decode() in jdk 1.3
962      */

963     private static boolean warn13 = false;
964
965     /**
966      * Have we tested for the correct URLDecoder.decode()
967      */

968     private static boolean testedDecoder = false;
969
970     /**
971      * Are we using the jdk 1.4 version of URLDecoder.decode()
972      */

973     private static Method JavaDoc decode14 = null;
974 }
975
Popular Tags