View Javadoc

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