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.net.URL;
22  import java.util.Arrays;
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.ArrayList;
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         return 0;
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(b, 0, b.length);
390     }
391 
392     /* ------------------------------------------------------------ */
393     public static String toHexString(byte[] b,int offset,int length)
394     {
395         StringBuilder buf = new StringBuilder();
396         for (int i=offset;i<offset+length;i++)
397         {
398             int bi=0xff&b[i];
399             int c='0'+(bi/16)%16;
400             if (c>'9')
401                 c= 'A'+(c-'0'-10);
402             buf.append((char)c);
403             c='0'+bi%16;
404             if (c>'9')
405                 c= 'a'+(c-'0'-10);
406             buf.append((char)c);
407         }
408         return buf.toString();
409     }
410 
411     /* ------------------------------------------------------------ */
412     public static byte[] fromHexString(String s)
413     {
414         if (s.length()%2!=0)
415             throw new IllegalArgumentException(s);
416         byte[] array = new byte[s.length()/2];
417         for (int i=0;i<array.length;i++)
418         {
419             int b = Integer.parseInt(s.substring(i*2,i*2+2),16);
420             array[i]=(byte)(0xff&b);
421         }
422         return array;
423     }
424 
425 
426     public static void dump(Class c)
427     {
428         System.err.println("Dump: "+c);
429         dump(c.getClassLoader());
430     }
431 
432     public static void dump(ClassLoader cl)
433     {
434         System.err.println("Dump Loaders:");
435         while(cl!=null)
436         {
437             System.err.println("  loader "+cl);
438             cl = cl.getParent();
439         }
440     }
441 
442 
443     /* ------------------------------------------------------------ */
444     public static byte[] readLine(InputStream in) throws IOException
445     {
446         byte[] buf = new byte[256];
447 
448         int i=0;
449         int loops=0;
450         int ch=0;
451 
452         while (true)
453         {
454             ch=in.read();
455             if (ch<0)
456                 break;
457             loops++;
458 
459             // skip a leading LF's
460             if (loops==1 && ch==LF)
461                 continue;
462 
463             if (ch==CR || ch==LF)
464                 break;
465 
466             if (i>=buf.length)
467             {
468                 byte[] old_buf=buf;
469                 buf=new byte[old_buf.length+256];
470                 System.arraycopy(old_buf, 0, buf, 0, old_buf.length);
471             }
472             buf[i++]=(byte)ch;
473         }
474 
475         if (ch==-1 && i==0)
476             return null;
477 
478         // skip a trailing LF if it exists
479         if (ch==CR && in.available()>=1 && in.markSupported())
480         {
481             in.mark(1);
482             ch=in.read();
483             if (ch!=LF)
484                 in.reset();
485         }
486 
487         byte[] old_buf=buf;
488         buf=new byte[i];
489         System.arraycopy(old_buf, 0, buf, 0, i);
490 
491         return buf;
492     }
493 
494     public static URL jarFor(String className)
495     {
496         try
497         {
498             className=className.replace('.','/')+".class";
499             // hack to discover jstl libraries
500             URL url = Loader.getResource(null,className,false);
501             String s=url.toString();
502             if (s.startsWith("jar:file:"))
503                 return new URL(s.substring(4,s.indexOf("!/")));
504         }
505         catch(Exception e)
506         {
507             Log.ignore(e);
508         }
509         return null;
510     }
511 }