View Javadoc

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