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