View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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=convertHexDigit((int)c);
282             if (digit<0 || digit>=base)
283                 throw new NumberFormatException(s.substring(offset,offset+length));
284             value=value*base+digit;
285         }
286         return value;
287     }
288 
289     /* ------------------------------------------------------------ */
290     /** Parse an int from a byte array of ascii characters.
291      * Negative numbers are not handled.
292      * @param b byte array
293      * @param offset Offset within string
294      * @param length Length of integer or -1 for remainder of string
295      * @param base base of the integer
296      * @return the parsed integer
297      * @throws NumberFormatException if the array cannot be parsed into an integer
298      */
299     public static int parseInt(byte[] b, int offset, int length, int base)
300         throws NumberFormatException
301     {
302         int value=0;
303 
304         if (length<0)
305             length=b.length-offset;
306 
307         for (int i=0;i<length;i++)
308         {
309             char c=(char)(0xff&b[offset+i]);
310 
311             int digit=c-'0';
312             if (digit<0 || digit>=base || digit>=10)
313             {
314                 digit=10+c-'A';
315                 if (digit<10 || digit>=base)
316                     digit=10+c-'a';
317             }
318             if (digit<0 || digit>=base)
319                 throw new NumberFormatException(new String(b,offset,length));
320             value=value*base+digit;
321         }
322         return value;
323     }
324 
325     /* ------------------------------------------------------------ */
326     public static byte[] parseBytes(String s, int base)
327     {
328         byte[] bytes=new byte[s.length()/2];
329         for (int i=0;i<s.length();i+=2)
330             bytes[i/2]=(byte)TypeUtil.parseInt(s,i,2,base);
331         return bytes;
332     }
333 
334     /* ------------------------------------------------------------ */
335     public static String toString(byte[] bytes, int base)
336     {
337         StringBuilder buf = new StringBuilder();
338         for (byte b : bytes)
339         {
340             int bi=0xff&b;
341             int c='0'+(bi/base)%base;
342             if (c>'9')
343                 c= 'a'+(c-'0'-10);
344             buf.append((char)c);
345             c='0'+bi%base;
346             if (c>'9')
347                 c= 'a'+(c-'0'-10);
348             buf.append((char)c);
349         }
350         return buf.toString();
351     }
352 
353     /* ------------------------------------------------------------ */
354     /**
355      * @param c An ASCII encoded character 0-9 a-f A-F
356      * @return The byte value of the character 0-16.
357      */
358     public static byte convertHexDigit( byte c )
359     {
360         byte b = (byte)((c & 0x1f) + ((c >> 6) * 0x19) - 0x10);
361         if (b<0 || b>15)
362             throw new IllegalArgumentException("!hex "+c);
363         return b;
364     }
365     
366     /* ------------------------------------------------------------ */
367     /**
368      * @param c An ASCII encoded character 0-9 a-f A-F
369      * @return The byte value of the character 0-16.
370      */
371     public static int convertHexDigit( int c )
372     {
373         int d= ((c & 0x1f) + ((c >> 6) * 0x19) - 0x10);
374         if (d<0 || d>15)
375             throw new NumberFormatException("!hex "+c);
376         return d;
377     }
378 
379     /* ------------------------------------------------------------ */
380     public static void toHex(byte b,Appendable buf)
381     {
382         try
383         {
384             int d=0xf&((0xF0&b)>>4);
385             buf.append((char)((d>9?('A'-10):'0')+d));
386             d=0xf&b;
387             buf.append((char)((d>9?('A'-10):'0')+d));
388         }
389         catch(IOException e)
390         {
391             throw new RuntimeException(e);
392         }
393     }
394 
395     /* ------------------------------------------------------------ */
396     public static void toHex(int value,Appendable buf) throws IOException
397     {
398         int d=0xf&((0xF0000000&value)>>28);
399         buf.append((char)((d>9?('A'-10):'0')+d));
400         d=0xf&((0x0F000000&value)>>24);
401         buf.append((char)((d>9?('A'-10):'0')+d));
402         d=0xf&((0x00F00000&value)>>20);
403         buf.append((char)((d>9?('A'-10):'0')+d));
404         d=0xf&((0x000F0000&value)>>16);
405         buf.append((char)((d>9?('A'-10):'0')+d));
406         d=0xf&((0x0000F000&value)>>12);
407         buf.append((char)((d>9?('A'-10):'0')+d));
408         d=0xf&((0x00000F00&value)>>8);
409         buf.append((char)((d>9?('A'-10):'0')+d));
410         d=0xf&((0x000000F0&value)>>4);
411         buf.append((char)((d>9?('A'-10):'0')+d));
412         d=0xf&value;
413         buf.append((char)((d>9?('A'-10):'0')+d));
414     
415         Integer.toString(0,36);
416     }
417     
418     
419     /* ------------------------------------------------------------ */
420     public static void toHex(long value,Appendable buf) throws IOException
421     {
422         toHex((int)(value>>32),buf);
423         toHex((int)value,buf);
424     }
425 
426     /* ------------------------------------------------------------ */
427     public static String toHexString(byte b)
428     {
429         return toHexString(new byte[]{b}, 0, 1);
430     }
431     
432     /* ------------------------------------------------------------ */
433     public static String toHexString(byte[] b)
434     {
435         return toHexString(b, 0, b.length);
436     }
437 
438     /* ------------------------------------------------------------ */
439     public static String toHexString(byte[] b,int offset,int length)
440     {
441         StringBuilder buf = new StringBuilder();
442         for (int i=offset;i<offset+length;i++)
443         {
444             int bi=0xff&b[i];
445             int c='0'+(bi/16)%16;
446             if (c>'9')
447                 c= 'A'+(c-'0'-10);
448             buf.append((char)c);
449             c='0'+bi%16;
450             if (c>'9')
451                 c= 'a'+(c-'0'-10);
452             buf.append((char)c);
453         }
454         return buf.toString();
455     }
456 
457     /* ------------------------------------------------------------ */
458     public static byte[] fromHexString(String s)
459     {
460         if (s.length()%2!=0)
461             throw new IllegalArgumentException(s);
462         byte[] array = new byte[s.length()/2];
463         for (int i=0;i<array.length;i++)
464         {
465             int b = Integer.parseInt(s.substring(i*2,i*2+2),16);
466             array[i]=(byte)(0xff&b);
467         }
468         return array;
469     }
470 
471 
472     public static void dump(Class<?> c)
473     {
474         System.err.println("Dump: "+c);
475         dump(c.getClassLoader());
476     }
477 
478     public static void dump(ClassLoader cl)
479     {
480         System.err.println("Dump Loaders:");
481         while(cl!=null)
482         {
483             System.err.println("  loader "+cl);
484             cl = cl.getParent();
485         }
486     }
487 
488 
489     /* ------------------------------------------------------------ */
490     public static byte[] readLine(InputStream in) throws IOException
491     {
492         byte[] buf = new byte[256];
493 
494         int i=0;
495         int loops=0;
496         int ch=0;
497 
498         while (true)
499         {
500             ch=in.read();
501             if (ch<0)
502                 break;
503             loops++;
504 
505             // skip a leading LF's
506             if (loops==1 && ch==LF)
507                 continue;
508 
509             if (ch==CR || ch==LF)
510                 break;
511 
512             if (i>=buf.length)
513             {
514                 byte[] old_buf=buf;
515                 buf=new byte[old_buf.length+256];
516                 System.arraycopy(old_buf, 0, buf, 0, old_buf.length);
517             }
518             buf[i++]=(byte)ch;
519         }
520 
521         if (ch==-1 && i==0)
522             return null;
523 
524         // skip a trailing LF if it exists
525         if (ch==CR && in.available()>=1 && in.markSupported())
526         {
527             in.mark(1);
528             ch=in.read();
529             if (ch!=LF)
530                 in.reset();
531         }
532 
533         byte[] old_buf=buf;
534         buf=new byte[i];
535         System.arraycopy(old_buf, 0, buf, 0, i);
536 
537         return buf;
538     }
539 
540     public static URL jarFor(String className)
541     {
542         try
543         {
544             className=className.replace('.','/')+".class";
545             // hack to discover jstl libraries
546             URL url = Loader.getResource(null,className,false);
547             String s=url.toString();
548             if (s.startsWith("jar:file:"))
549                 return new URL(s.substring(4,s.indexOf("!/")));
550         }
551         catch(Exception e)
552         {
553             LOG.ignore(e);
554         }
555         return null;
556     }
557     
558     public static Object call(Class<?> oClass, String method, Object obj, Object[] arg) 
559        throws InvocationTargetException, NoSuchMethodException
560     {
561         // Lets just try all methods for now
562         Method[] methods = oClass.getMethods();
563         for (int c = 0; methods != null && c < methods.length; c++)
564         {
565             if (!methods[c].getName().equals(method))
566                 continue;
567             if (methods[c].getParameterTypes().length != arg.length)
568                 continue;
569             if (Modifier.isStatic(methods[c].getModifiers()) != (obj == null))
570                 continue;
571             if ((obj == null) && methods[c].getDeclaringClass() != oClass)
572                 continue;
573 
574             try
575             {
576                 return methods[c].invoke(obj,arg);
577             }
578             catch (IllegalAccessException e)
579             {
580                 LOG.ignore(e);
581             }
582             catch (IllegalArgumentException e)
583             {
584                 LOG.ignore(e);
585             }
586         }
587 
588         throw new NoSuchMethodException(method);
589     }
590 }