View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.util;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.lang.reflect.Constructor;
24  import java.lang.reflect.InvocationTargetException;
25  import java.lang.reflect.Method;
26  import java.lang.reflect.Modifier;
27  import java.net.URL;
28  import java.util.Arrays;
29  import java.util.Collections;
30  import java.util.HashMap;
31  import java.util.List;
32  
33  import org.eclipse.jetty.util.log.Log;
34  import org.eclipse.jetty.util.log.Logger;
35  
36  
37  /* ------------------------------------------------------------ */
38  /**
39   * TYPE Utilities.
40   * Provides various static utiltiy methods for manipulating types and their
41   * string representations.
42   *
43   * @since Jetty 4.1
44   */
45  public class TypeUtil
46  {
47      private static final Logger LOG = Log.getLogger(TypeUtil.class);
48      public static int CR = '\015';
49      public static int LF = '\012';
50  
51      /* ------------------------------------------------------------ */
52      private static final HashMap<String, Class<?>> name2Class=new HashMap<String, Class<?>>();
53      static
54      {
55          name2Class.put("boolean",java.lang.Boolean.TYPE);
56          name2Class.put("byte",java.lang.Byte.TYPE);
57          name2Class.put("char",java.lang.Character.TYPE);
58          name2Class.put("double",java.lang.Double.TYPE);
59          name2Class.put("float",java.lang.Float.TYPE);
60          name2Class.put("int",java.lang.Integer.TYPE);
61          name2Class.put("long",java.lang.Long.TYPE);
62          name2Class.put("short",java.lang.Short.TYPE);
63          name2Class.put("void",java.lang.Void.TYPE);
64  
65          name2Class.put("java.lang.Boolean.TYPE",java.lang.Boolean.TYPE);
66          name2Class.put("java.lang.Byte.TYPE",java.lang.Byte.TYPE);
67          name2Class.put("java.lang.Character.TYPE",java.lang.Character.TYPE);
68          name2Class.put("java.lang.Double.TYPE",java.lang.Double.TYPE);
69          name2Class.put("java.lang.Float.TYPE",java.lang.Float.TYPE);
70          name2Class.put("java.lang.Integer.TYPE",java.lang.Integer.TYPE);
71          name2Class.put("java.lang.Long.TYPE",java.lang.Long.TYPE);
72          name2Class.put("java.lang.Short.TYPE",java.lang.Short.TYPE);
73          name2Class.put("java.lang.Void.TYPE",java.lang.Void.TYPE);
74  
75          name2Class.put("java.lang.Boolean",java.lang.Boolean.class);
76          name2Class.put("java.lang.Byte",java.lang.Byte.class);
77          name2Class.put("java.lang.Character",java.lang.Character.class);
78          name2Class.put("java.lang.Double",java.lang.Double.class);
79          name2Class.put("java.lang.Float",java.lang.Float.class);
80          name2Class.put("java.lang.Integer",java.lang.Integer.class);
81          name2Class.put("java.lang.Long",java.lang.Long.class);
82          name2Class.put("java.lang.Short",java.lang.Short.class);
83  
84          name2Class.put("Boolean",java.lang.Boolean.class);
85          name2Class.put("Byte",java.lang.Byte.class);
86          name2Class.put("Character",java.lang.Character.class);
87          name2Class.put("Double",java.lang.Double.class);
88          name2Class.put("Float",java.lang.Float.class);
89          name2Class.put("Integer",java.lang.Integer.class);
90          name2Class.put("Long",java.lang.Long.class);
91          name2Class.put("Short",java.lang.Short.class);
92  
93          name2Class.put(null,java.lang.Void.TYPE);
94          name2Class.put("string",java.lang.String.class);
95          name2Class.put("String",java.lang.String.class);
96          name2Class.put("java.lang.String",java.lang.String.class);
97      }
98  
99      /* ------------------------------------------------------------ */
100     private static final HashMap<Class<?>, String> class2Name=new HashMap<Class<?>, String>();
101     static
102     {
103         class2Name.put(java.lang.Boolean.TYPE,"boolean");
104         class2Name.put(java.lang.Byte.TYPE,"byte");
105         class2Name.put(java.lang.Character.TYPE,"char");
106         class2Name.put(java.lang.Double.TYPE,"double");
107         class2Name.put(java.lang.Float.TYPE,"float");
108         class2Name.put(java.lang.Integer.TYPE,"int");
109         class2Name.put(java.lang.Long.TYPE,"long");
110         class2Name.put(java.lang.Short.TYPE,"short");
111         class2Name.put(java.lang.Void.TYPE,"void");
112 
113         class2Name.put(java.lang.Boolean.class,"java.lang.Boolean");
114         class2Name.put(java.lang.Byte.class,"java.lang.Byte");
115         class2Name.put(java.lang.Character.class,"java.lang.Character");
116         class2Name.put(java.lang.Double.class,"java.lang.Double");
117         class2Name.put(java.lang.Float.class,"java.lang.Float");
118         class2Name.put(java.lang.Integer.class,"java.lang.Integer");
119         class2Name.put(java.lang.Long.class,"java.lang.Long");
120         class2Name.put(java.lang.Short.class,"java.lang.Short");
121 
122         class2Name.put(null,"void");
123         class2Name.put(java.lang.String.class,"java.lang.String");
124     }
125 
126     /* ------------------------------------------------------------ */
127     private static final HashMap<Class<?>, Method> class2Value=new HashMap<Class<?>, Method>();
128     static
129     {
130         try
131         {
132             Class<?>[] s ={java.lang.String.class};
133 
134             class2Value.put(java.lang.Boolean.TYPE,
135                            java.lang.Boolean.class.getMethod("valueOf",s));
136             class2Value.put(java.lang.Byte.TYPE,
137                            java.lang.Byte.class.getMethod("valueOf",s));
138             class2Value.put(java.lang.Double.TYPE,
139                            java.lang.Double.class.getMethod("valueOf",s));
140             class2Value.put(java.lang.Float.TYPE,
141                            java.lang.Float.class.getMethod("valueOf",s));
142             class2Value.put(java.lang.Integer.TYPE,
143                            java.lang.Integer.class.getMethod("valueOf",s));
144             class2Value.put(java.lang.Long.TYPE,
145                            java.lang.Long.class.getMethod("valueOf",s));
146             class2Value.put(java.lang.Short.TYPE,
147                            java.lang.Short.class.getMethod("valueOf",s));
148 
149             class2Value.put(java.lang.Boolean.class,
150                            java.lang.Boolean.class.getMethod("valueOf",s));
151             class2Value.put(java.lang.Byte.class,
152                            java.lang.Byte.class.getMethod("valueOf",s));
153             class2Value.put(java.lang.Double.class,
154                            java.lang.Double.class.getMethod("valueOf",s));
155             class2Value.put(java.lang.Float.class,
156                            java.lang.Float.class.getMethod("valueOf",s));
157             class2Value.put(java.lang.Integer.class,
158                            java.lang.Integer.class.getMethod("valueOf",s));
159             class2Value.put(java.lang.Long.class,
160                            java.lang.Long.class.getMethod("valueOf",s));
161             class2Value.put(java.lang.Short.class,
162                            java.lang.Short.class.getMethod("valueOf",s));
163         }
164         catch(Exception e)
165         {
166             throw new Error(e);
167         }
168     }
169 
170     /* ------------------------------------------------------------ */
171     /** Array to List.
172      * <p>
173      * Works like {@link Arrays#asList(Object...)}, but handles null arrays.
174      * @return a list backed by the array.
175      */
176     public static <T> List<T> asList(T[] a) 
177     {
178         if (a==null)
179             return Collections.emptyList();
180         return Arrays.asList(a);
181     }
182     
183     /* ------------------------------------------------------------ */
184     /** Class from a canonical name for a type.
185      * @param name A class or type name.
186      * @return A class , which may be a primitive TYPE field..
187      */
188     public static Class<?> fromName(String name)
189     {
190         return name2Class.get(name);
191     }
192 
193     /* ------------------------------------------------------------ */
194     /** Canonical name for a type.
195      * @param type A class , which may be a primitive TYPE field.
196      * @return Canonical name.
197      */
198     public static String toName(Class<?> type)
199     {
200         return class2Name.get(type);
201     }
202 
203     /* ------------------------------------------------------------ */
204     /** Convert String value to instance.
205      * @param type The class of the instance, which may be a primitive TYPE field.
206      * @param value The value as a string.
207      * @return The value as an Object.
208      */
209     public static Object valueOf(Class<?> type, String value)
210     {
211         try
212         {
213             if (type.equals(java.lang.String.class))
214                 return value;
215 
216             Method m = class2Value.get(type);
217             if (m!=null)
218                 return m.invoke(null, value);
219 
220             if (type.equals(java.lang.Character.TYPE) ||
221                 type.equals(java.lang.Character.class))
222                 return new Character(value.charAt(0));
223 
224             Constructor<?> c = type.getConstructor(java.lang.String.class);
225             return c.newInstance(value);
226         }
227         catch(NoSuchMethodException e)
228         {
229             // LogSupport.ignore(log,e);
230         }
231         catch(IllegalAccessException e)
232         {
233             // LogSupport.ignore(log,e);
234         }
235         catch(InstantiationException e)
236         {
237             // LogSupport.ignore(log,e);
238         }
239         catch(InvocationTargetException e)
240         {
241             if (e.getTargetException() instanceof Error)
242                 throw (Error)(e.getTargetException());
243             // LogSupport.ignore(log,e);
244         }
245         return null;
246     }
247 
248     /* ------------------------------------------------------------ */
249     /** Convert String value to instance.
250      * @param type classname or type (eg int)
251      * @param value The value as a string.
252      * @return The value as an Object.
253      */
254     public static Object valueOf(String type, String value)
255     {
256         return valueOf(fromName(type),value);
257     }
258 
259     /* ------------------------------------------------------------ */
260     /** Parse an int from a substring.
261      * Negative numbers are not handled.
262      * @param s String
263      * @param offset Offset within string
264      * @param length Length of integer or -1 for remainder of string
265      * @param base base of the integer
266      * @return the parsed integer
267      * @throws NumberFormatException if the string cannot be parsed
268      */
269     public static int parseInt(String s, int offset, int length, int base)
270         throws NumberFormatException
271     {
272         int value=0;
273 
274         if (length<0)
275             length=s.length()-offset;
276 
277         for (int i=0;i<length;i++)
278         {
279             char c=s.charAt(offset+i);
280 
281             int digit=c-'0';
282             if (digit<0 || digit>=base || digit>=10)
283             {
284                 digit=10+c-'A';
285                 if (digit<10 || digit>=base)
286                     digit=10+c-'a';
287             }
288             if (digit<0 || digit>=base)
289                 throw new NumberFormatException(s.substring(offset,offset+length));
290             value=value*base+digit;
291         }
292         return value;
293     }
294 
295     /* ------------------------------------------------------------ */
296     /** Parse an int from a byte array of ascii characters.
297      * Negative numbers are not handled.
298      * @param b byte array
299      * @param offset Offset within string
300      * @param length Length of integer or -1 for remainder of string
301      * @param base base of the integer
302      * @return the parsed integer
303      * @throws NumberFormatException if the array cannot be parsed into an integer
304      */
305     public static int parseInt(byte[] b, int offset, int length, int base)
306         throws NumberFormatException
307     {
308         int value=0;
309 
310         if (length<0)
311             length=b.length-offset;
312 
313         for (int i=0;i<length;i++)
314         {
315             char c=(char)(0xff&b[offset+i]);
316 
317             int digit=c-'0';
318             if (digit<0 || digit>=base || digit>=10)
319             {
320                 digit=10+c-'A';
321                 if (digit<10 || digit>=base)
322                     digit=10+c-'a';
323             }
324             if (digit<0 || digit>=base)
325                 throw new NumberFormatException(new String(b,offset,length));
326             value=value*base+digit;
327         }
328         return value;
329     }
330 
331     /* ------------------------------------------------------------ */
332     public static byte[] parseBytes(String s, int base)
333     {
334         byte[] bytes=new byte[s.length()/2];
335         for (int i=0;i<s.length();i+=2)
336             bytes[i/2]=(byte)TypeUtil.parseInt(s,i,2,base);
337         return bytes;
338     }
339 
340     /* ------------------------------------------------------------ */
341     public static String toString(byte[] bytes, int base)
342     {
343         StringBuilder buf = new StringBuilder();
344         for (byte b : bytes)
345         {
346             int bi=0xff&b;
347             int c='0'+(bi/base)%base;
348             if (c>'9')
349                 c= 'a'+(c-'0'-10);
350             buf.append((char)c);
351             c='0'+bi%base;
352             if (c>'9')
353                 c= 'a'+(c-'0'-10);
354             buf.append((char)c);
355         }
356         return buf.toString();
357     }
358 
359     /* ------------------------------------------------------------ */
360     /**
361      * @param b An ASCII encoded character 0-9 a-f A-F
362      * @return The byte value of the character 0-16.
363      */
364     public static byte convertHexDigit( byte b )
365     {
366         if ((b >= '0') && (b <= '9')) return (byte)(b - '0');
367         if ((b >= 'a') && (b <= 'f')) return (byte)(b - 'a' + 10);
368         if ((b >= 'A') && (b <= 'F')) return (byte)(b - 'A' + 10);
369         throw new IllegalArgumentException("!hex:"+Integer.toHexString(0xff&b));
370     }
371 
372     /* ------------------------------------------------------------ */
373     public static void toHex(byte b,Appendable buf)
374     {
375         try
376         {
377             int bi=0xff&b;
378             int c='0'+(bi/16)%16;
379             if (c>'9')
380                 c= 'A'+(c-'0'-10);
381             buf.append((char)c);
382             c='0'+bi%16;
383             if (c>'9')
384                 c= 'A'+(c-'0'-10);
385             buf.append((char)c);
386         }
387         catch(IOException e)
388         {
389             throw new RuntimeException(e);
390         }
391     }
392 
393     /* ------------------------------------------------------------ */
394     public static String toHexString(byte b)
395     {
396         return toHexString(new byte[]{b}, 0, 1);
397     }
398     
399     /* ------------------------------------------------------------ */
400     public static String toHexString(byte[] b)
401     {
402         return toHexString(b, 0, b.length);
403     }
404 
405     /* ------------------------------------------------------------ */
406     public static String toHexString(byte[] b,int offset,int length)
407     {
408         StringBuilder buf = new StringBuilder();
409         for (int i=offset;i<offset+length;i++)
410         {
411             int bi=0xff&b[i];
412             int c='0'+(bi/16)%16;
413             if (c>'9')
414                 c= 'A'+(c-'0'-10);
415             buf.append((char)c);
416             c='0'+bi%16;
417             if (c>'9')
418                 c= 'a'+(c-'0'-10);
419             buf.append((char)c);
420         }
421         return buf.toString();
422     }
423 
424     /* ------------------------------------------------------------ */
425     public static byte[] fromHexString(String s)
426     {
427         if (s.length()%2!=0)
428             throw new IllegalArgumentException(s);
429         byte[] array = new byte[s.length()/2];
430         for (int i=0;i<array.length;i++)
431         {
432             int b = Integer.parseInt(s.substring(i*2,i*2+2),16);
433             array[i]=(byte)(0xff&b);
434         }
435         return array;
436     }
437 
438 
439     public static void dump(Class<?> c)
440     {
441         System.err.println("Dump: "+c);
442         dump(c.getClassLoader());
443     }
444 
445     public static void dump(ClassLoader cl)
446     {
447         System.err.println("Dump Loaders:");
448         while(cl!=null)
449         {
450             System.err.println("  loader "+cl);
451             cl = cl.getParent();
452         }
453     }
454 
455 
456     /* ------------------------------------------------------------ */
457     public static byte[] readLine(InputStream in) throws IOException
458     {
459         byte[] buf = new byte[256];
460 
461         int i=0;
462         int loops=0;
463         int ch=0;
464 
465         while (true)
466         {
467             ch=in.read();
468             if (ch<0)
469                 break;
470             loops++;
471 
472             // skip a leading LF's
473             if (loops==1 && ch==LF)
474                 continue;
475 
476             if (ch==CR || ch==LF)
477                 break;
478 
479             if (i>=buf.length)
480             {
481                 byte[] old_buf=buf;
482                 buf=new byte[old_buf.length+256];
483                 System.arraycopy(old_buf, 0, buf, 0, old_buf.length);
484             }
485             buf[i++]=(byte)ch;
486         }
487 
488         if (ch==-1 && i==0)
489             return null;
490 
491         // skip a trailing LF if it exists
492         if (ch==CR && in.available()>=1 && in.markSupported())
493         {
494             in.mark(1);
495             ch=in.read();
496             if (ch!=LF)
497                 in.reset();
498         }
499 
500         byte[] old_buf=buf;
501         buf=new byte[i];
502         System.arraycopy(old_buf, 0, buf, 0, i);
503 
504         return buf;
505     }
506 
507     public static URL jarFor(String className)
508     {
509         try
510         {
511             className=className.replace('.','/')+".class";
512             // hack to discover jstl libraries
513             URL url = Loader.getResource(null,className,false);
514             String s=url.toString();
515             if (s.startsWith("jar:file:"))
516                 return new URL(s.substring(4,s.indexOf("!/")));
517         }
518         catch(Exception e)
519         {
520             LOG.ignore(e);
521         }
522         return null;
523     }
524     
525     public static Object call(Class<?> oClass, String method, Object obj, Object[] arg) 
526        throws InvocationTargetException, NoSuchMethodException
527     {
528         // Lets just try all methods for now
529         Method[] methods = oClass.getMethods();
530         for (int c = 0; methods != null && c < methods.length; c++)
531         {
532             if (!methods[c].getName().equals(method))
533                 continue;
534             if (methods[c].getParameterTypes().length != arg.length)
535                 continue;
536             if (Modifier.isStatic(methods[c].getModifiers()) != (obj == null))
537                 continue;
538             if ((obj == null) && methods[c].getDeclaringClass() != oClass)
539                 continue;
540 
541             try
542             {
543                 return methods[c].invoke(obj,arg);
544             }
545             catch (IllegalAccessException e)
546             {
547                 LOG.ignore(e);
548             }
549             catch (IllegalArgumentException e)
550             {
551                 LOG.ignore(e);
552             }
553         }
554 
555         throw new NoSuchMethodException(method);
556     }
557 }