View Javadoc

1   /*
2    * Copyright 1999-2004 The Apache Software Foundation.
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    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  
18  package org.apache.commons.modeler.util;
19  
20  import java.io.File;
21  import java.io.FilenameFilter;
22  import java.io.IOException;
23  import java.lang.reflect.InvocationTargetException;
24  import java.lang.reflect.Method;
25  import java.net.InetAddress;
26  import java.net.MalformedURLException;
27  import java.net.URL;
28  import java.net.UnknownHostException;
29  import java.util.Hashtable;
30  import java.util.StringTokenizer;
31  import java.util.Vector;
32  
33  // Depends:
34  //    JDK1.1
35  
36  /***
37   *  Utils for introspection and reflection
38   *
39   *  Source: jakarta-tomcat-connector/util
40   */
41  public final class IntrospectionUtils {
42      static final Class NO_PARAMS[]=new Class[0];
43      static final Class STRING_OBJ_PARAM[]=new Class[] {
44          String.class, Object.class };
45      static final Class STRING_PARAM[]=new Class[] {
46          String.class };
47  
48      /*** Execute a no-param method.
49       */
50      public static void execute( Object proxy, String method  )
51  	throws Exception
52      {
53  	Method executeM=null;
54  	Class c=proxy.getClass();
55  	executeM=findMethod( c, method, NO_PARAMS );
56  	if( executeM == null ) {
57  	    throw new RuntimeException("No method " + method + " in " +
58                      proxy.getClass() );
59  	}
60  	executeM.invoke(proxy, (Object [])null );
61      }
62  
63      /***
64       *  Call void setAttribute( String ,Object )
65       */
66      public static void setAttribute( Object proxy, String n, Object v)
67  	throws Exception
68      {
69  	if( proxy instanceof AttributeHolder ) {
70  	    ((AttributeHolder)proxy).setAttribute( n, v );
71  	    return;
72  	}
73  
74  	Method executeM=null;
75  	Class c=proxy.getClass();
76  	executeM=findMethod( c, "setAttribute", STRING_OBJ_PARAM );
77  
78  	if( executeM == null ) {
79  	    System.out.println("No setAttribute in " + proxy.getClass() );
80  	    return;
81  	}
82  	executeM.invoke(proxy, new Object[] { n, v });
83  	return;
84      }
85  
86  
87      /***
88       *  Call void getAttribute( String )
89       */
90      public static Object getAttribute( Object proxy, String n)
91  	throws Exception
92      {
93  	Method executeM=null;
94  	Class c=proxy.getClass();
95  	executeM=findMethod( c, "getAttribute", STRING_PARAM);
96  	if( executeM == null ) {
97  	    System.out.println("No getAttribute in " + proxy.getClass() );
98  	    return null;
99  	}
100 	return executeM.invoke(proxy, new Object[] { n });
101     }
102 
103 
104     /*** Construct a URLClassLoader. Will compile and work in JDK1.1 too.
105      */
106     public static ClassLoader getURLClassLoader( URL urls[],
107 						 ClassLoader parent )
108     {
109 	try {
110 	    Class urlCL=Class.forName( "java.net.URLClassLoader");
111 	    Class paramT[]=new Class[2];
112 	    paramT[0]= urls.getClass();
113 	    paramT[1]=ClassLoader.class;
114 	    Method m=findMethod( urlCL, "newInstance", paramT);
115 	    if( m==null ) return null;
116 
117 	    ClassLoader cl=(ClassLoader)m.invoke( urlCL,
118 						  new Object[] { urls,
119 								 parent } );
120 	    return cl;
121 	} catch(ClassNotFoundException ex ) {
122 	    // jdk1.1
123 	    return null;
124 	} catch(Exception ex ) {
125 	    ex.printStackTrace();
126 	    return null;
127 	}
128     }
129 
130 
131     public static String guessInstall(String installSysProp,
132 		String homeSysProp, String jarName) {
133 	return guessInstall( installSysProp, homeSysProp, jarName, null);
134     }
135 
136     /*** Guess a product install/home by analyzing the class path.
137      *  It works for product using the pattern: lib/executable.jar
138      *  or if executable.jar is included in classpath by a shell
139      *  script. ( java -jar also works )
140      *
141      *  Insures both "install" and "home" System properties are set.
142      *  If either or both System properties are unset, "install" and
143      *  "home" will be set to the same value.  This value will be
144      *  the other System  property that is set, or the guessed value
145      *  if neither is set.
146      */
147     public static String guessInstall(String installSysProp, String homeSysProp,
148 			String jarName,	String classFile) {
149 	String install=null;
150 	String home=null;
151 
152 	if ( installSysProp != null )
153 	    install=System.getProperty( installSysProp );
154 
155 	if( homeSysProp != null )
156 	    home=System.getProperty( homeSysProp );
157 
158 	if ( install != null ) {
159 	    if ( home == null )
160 		System.getProperties().put( homeSysProp, install );
161 	    return install;
162 	}
163 
164 	// Find the directory where jarName.jar is located
165 
166 	String cpath=System.getProperty( "java.class.path");
167 	String pathSep=System.getProperty( "path.separator");
168 	StringTokenizer st=new StringTokenizer( cpath, pathSep );
169 	while( st.hasMoreTokens() ) {
170 	    String path=st.nextToken();
171 	    //	    log( "path " + path );
172 	    if( path.endsWith( jarName ) ) {
173 		home=path.substring( 0, path.length() - jarName.length() );
174 		try {
175                     if( "".equals(home) ) {
176                         home=new File("./").getCanonicalPath();
177                     } else if( home.endsWith(File.separator) ) {
178 			home = home.substring(0,home.length()-1);
179 		    }
180                     File f=new File( home );
181 		    String parentDir = f.getParent();
182 		    if(parentDir == null)
183 			parentDir = home;  // unix style
184 		    File f1=new File ( parentDir );
185 		    install = f1.getCanonicalPath();
186 		    if( installSysProp != null )
187 			System.getProperties().put( installSysProp, install );
188 		    if( home == null && homeSysProp != null )
189 			System.getProperties().put( homeSysProp, install );
190 		    return install;
191 		} catch( Exception ex ) {
192 		    ex.printStackTrace();
193 		}
194 	    } else  {
195 		String fname=path + ( path.endsWith("/") ?"":"/" ) + classFile;
196 		if( new File( fname ).exists()) {
197 		    try {
198 			File f=new File( path );
199 			String parentDir = f.getParent();
200 			if( parentDir == null )
201 			    parentDir = path; // unix style
202 			File f1=new File ( parentDir );
203 			install = f1.getCanonicalPath();
204 			if( installSysProp != null )
205 			    System.getProperties().put( installSysProp,
206 							install );
207 			if( home == null && homeSysProp != null )
208 			    System.getProperties().put( homeSysProp, install );
209 			return install;
210 		    } catch( Exception ex ) {
211 			ex.printStackTrace();
212 		    }
213 		}
214 	    }
215 	}
216 
217         // if install directory can't be found, use home as the default
218 	if ( home != null ) {
219 	    System.getProperties().put( installSysProp, home );
220 	    return home;
221 	}
222 
223 	return null;
224     }
225 
226     /*** Debug method, display the classpath
227      */
228     public static void displayClassPath( String msg, URL[] cp ) {
229 	System.out.println(msg);
230 	for( int i=0; i<cp.length; i++ ) {
231 	    System.out.println( cp[i].getFile() );
232 	}
233     }
234 
235     public static String PATH_SEPARATOR = System.getProperty("path.separator");
236     /***
237      * Adds classpath entries from a vector of URL's to the
238      * "tc_path_add" System property.  This System property lists
239      * the classpath entries common to web applications. This System
240      * property is currently used by Jasper when its JSP servlet
241      * compiles the Java file for a JSP.
242     */
243     public static String classPathAdd(URL urls[], String cp )
244     {
245 	if( urls==null ) return cp;
246 
247 	for( int i=0; i<urls.length; i++ ) {
248             if( cp != null)
249                 cp += PATH_SEPARATOR + urls[i].getFile();
250             else
251                 cp = urls[i].getFile();
252         }
253         return cp;
254     }
255 
256     /*** Find a method with the right name
257 	If found, call the method ( if param is int or boolean we'll convert
258 	value to the right type before) - that means you can have setDebug(1).
259     */
260     public static void setProperty( Object o, String name, String value ) {
261 	if( dbg > 1 ) d("setProperty(" +
262 			o.getClass() + " " +  name + "="  +
263 			value  +")" );
264 
265 	String setter= "set" +capitalize(name);
266 
267 	try {
268 	    Method methods[]=findMethods( o.getClass() );
269 	    Method setPropertyMethod=null;
270 
271 	    // First, the ideal case - a setFoo( String ) method
272 	    for( int i=0; i< methods.length; i++ ) {
273 		Class paramT[]=methods[i].getParameterTypes();
274 		if( setter.equals( methods[i].getName() ) &&
275 		    paramT.length == 1 &&
276 		    "java.lang.String".equals( paramT[0].getName())) {
277 
278 		    methods[i].invoke( o, new Object[] { value } );
279 		    return;
280 		}
281 	    }
282 
283 	    // Try a setFoo ( int ) or ( boolean )
284 	    for( int i=0; i< methods.length; i++ ) {
285 		boolean ok=true;
286 		if( setter.equals( methods[i].getName() ) &&
287 		    methods[i].getParameterTypes().length == 1) {
288 
289 		    // match - find the type and invoke it
290 		    Class paramType=methods[i].getParameterTypes()[0];
291 		    Object params[]=new Object[1];
292 
293 		    // Try a setFoo ( int )
294 		    if ("java.lang.Integer".equals( paramType.getName()) ||
295 			"int".equals( paramType.getName())) {
296 			try {
297 			    params[0]=new Integer(value);
298 			} catch( NumberFormatException ex ) {ok=false;}
299 
300 		    // Try a setFoo ( boolean )
301 		    } else if ("java.lang.Boolean".
302 			       equals( paramType.getName()) ||
303 			"boolean".equals( paramType.getName())) {
304 			params[0]=new Boolean(value);
305 
306 		    // Try a setFoo ( InetAddress )
307 		    } else if ("java.net.InetAddress".
308 				equals( paramType.getName())){
309 			try{
310  			    params[0]= InetAddress.getByName(value);
311  			}catch(UnknownHostException exc) {
312  			    d("Unable to resolve host name:" + value);
313  			    ok=false;
314  			}
315 
316                     // Try a setFoo ( Object )
317                     } else if ("java.lang.Object".
318                                equals( paramType.getName())) {
319                         params[0] = value;
320 
321  		    // Unknown type
322 		    } else {
323 			d("Unknown type " + paramType.getName() );
324 		    }
325 
326 		    if( ok ) {
327 			methods[i].invoke( o, params );
328 			return;
329 		    }
330 		}
331 
332 		// save "setProperty" for later
333 		if( "setProperty".equals( methods[i].getName())) {
334 		    setPropertyMethod=methods[i];
335 		}
336 	    }
337 
338 	    // Ok, no setXXX found, try a setProperty("name", "value")
339 	    if( setPropertyMethod != null ) {
340 		Object params[]=new Object[2];
341 		params[0]=name;
342 		params[1]=value;
343 		setPropertyMethod.invoke( o, params );
344 	    }
345 
346 	} catch( IllegalArgumentException ex2 ) {
347             System.err.println("IAE " + o + " " + name + " " + value);
348             ex2.printStackTrace();
349 	} catch( SecurityException ex1 ) {
350 	    if( dbg > 0 )
351 		d("SecurityException for " + o.getClass() + " " +
352 			name + "="  + value  +")" );
353 	    if( dbg > 1 ) ex1.printStackTrace();
354 	} catch (IllegalAccessException iae) {
355 	    if( dbg > 0 )
356 		d("IllegalAccessException for " +
357 			o.getClass() + " " +  name + "="  + value  +")" );
358 	    if( dbg > 1 ) iae.printStackTrace();
359 	} catch (InvocationTargetException ie) {
360 	    if( dbg > 0 )
361 		d("InvocationTargetException for " + o.getClass() +
362 			" " +  name + "="  + value  +")" );
363 	    if( dbg > 1 ) ie.printStackTrace();
364 	}
365     }
366 
367     public static Object getProperty( Object o, String name ) {
368 	String getter= "get" +capitalize(name);
369 
370 	try {
371 	    Method methods[]=findMethods( o.getClass() );
372 	    Method getPropertyMethod=null;
373 
374 	    // First, the ideal case - a getFoo() method
375 	    for( int i=0; i< methods.length; i++ ) {
376 		Class paramT[]=methods[i].getParameterTypes();
377 		if( getter.equals( methods[i].getName() ) &&
378 		    paramT.length == 0 ) {
379 		    return methods[i].invoke( o, (Object [])null );
380 		}
381 
382 		if( "getProperty".equals( methods[i].getName())) {
383 		    getPropertyMethod=methods[i];
384 		}
385 		if( "getAttribute".equals( methods[i].getName())) {
386 		    getPropertyMethod=methods[i];
387 		}
388 	    }
389 
390 	    // Ok, no setXXX found, try a getProperty("name")
391 	    if( getPropertyMethod != null ) {
392 		Object params[]=new Object[1];
393 		params[0]=name;
394 		getPropertyMethod.invoke( o, params );
395 	    }
396 
397 	} catch( IllegalArgumentException ex2 ) {
398             System.err.println("IAE " + o + " " + name );
399             ex2.printStackTrace();
400 	} catch( SecurityException ex1 ) {
401 	    if( dbg > 0 )
402 		d("SecurityException for " + o.getClass() + " " +
403 			name + ")" );
404 	    if( dbg > 1 ) ex1.printStackTrace();
405 	} catch (IllegalAccessException iae) {
406 	    if( dbg > 0 )
407 		d("IllegalAccessException for " +
408 			o.getClass() + " " +  name  +")" );
409 	    if( dbg > 1 ) iae.printStackTrace();
410 	} catch (InvocationTargetException ie) {
411 	    if( dbg > 0 )
412 		d("InvocationTargetException for " + o.getClass() +
413 			" " +  name   +")" );
414 	    if( dbg > 1 ) ie.printStackTrace();
415 	}
416         return null;
417     }
418 
419     /***
420      */
421     public static void setProperty( Object o, String name ) {
422 	String setter= "set" +capitalize(name);
423 	try {
424 	    Method methods[]=findMethods( o.getClass() );
425 	    Method setPropertyMethod=null;
426 	    // find setFoo() method
427 	    for( int i=0; i< methods.length; i++ ) {
428 		Class paramT[]=methods[i].getParameterTypes();
429 		if( setter.equals( methods[i].getName() ) &&
430 		    paramT.length == 0 ) {
431 		    methods[i].invoke( o, new Object[] {} );
432 		    return;
433 		}
434 	    }
435 	} catch( Exception ex1 ) {
436 	    if( dbg > 0 )
437 		d("Exception for " + o.getClass() + " " + name);
438 	    if( dbg > 1 ) ex1.printStackTrace();
439 	}
440     }
441 
442     /*** Replace ${NAME} with the property value
443      *  @deprecated Use the explicit method
444      */
445     public static String replaceProperties(String value,
446 					   Object getter )
447     {
448         if( getter instanceof Hashtable )
449             return replaceProperties( value, (Hashtable)getter, null );
450 
451         if( getter instanceof PropertySource ) {
452             PropertySource src[]=new PropertySource[] {(PropertySource)getter};
453             return replaceProperties( value, null,  src);
454         }
455         return value;
456     }
457 
458     /*** Replace ${NAME} with the property value
459      */
460     public static String replaceProperties(String value,
461 					   Hashtable staticProp, PropertySource dynamicProp[] )
462     {
463         StringBuffer sb=new StringBuffer();
464         int prev=0;
465         // assert value!=nil
466         int pos;
467         while( (pos=value.indexOf( "$", prev )) >= 0 ) {
468             if(pos>0) {
469                 sb.append( value.substring( prev, pos ) );
470             }
471             if( pos == (value.length() - 1)) {
472                 sb.append('$');
473                 prev = pos + 1;
474             }
475             else if (value.charAt( pos + 1 ) != '{' ) {
476                 sb.append( value.charAt( pos + 1 ) );
477                 prev=pos+2; // XXX
478             } else {
479                 int endName=value.indexOf( '}', pos );
480                 if( endName < 0 ) {
481 		    sb.append( value.substring( pos ));
482 		    prev=value.length();
483 		    continue;
484                 }
485                 String n=value.substring( pos+2, endName );
486 		String v= null;
487 		if( staticProp != null ) {
488 		    v=(String)((Hashtable)staticProp).get(n);
489 		}
490                 if( v==null && dynamicProp != null) {
491                     for( int i=0; i<dynamicProp.length; i++ ) {
492                         v=dynamicProp[i].getProperty( n );
493                         if( v!=null ) {
494                             break;
495                         }
496                     }
497 		}
498 		if( v== null )
499 		    v = "${"+n+"}";
500 
501                 sb.append( v );
502                 prev=endName+1;
503             }
504         }
505         if( prev < value.length() ) sb.append( value.substring( prev ) );
506         return sb.toString();
507     }
508 
509     /*** Reverse of Introspector.decapitalize
510      */
511     public static String capitalize(String name) {
512 	if (name == null || name.length() == 0) {
513 	    return name;
514 	}
515 	char chars[] = name.toCharArray();
516 	chars[0] = Character.toUpperCase(chars[0]);
517 	return new String(chars);
518     }
519 
520     public static String unCapitalize(String name) {
521 	if (name == null || name.length() == 0) {
522 	    return name;
523 	}
524 	char chars[] = name.toCharArray();
525 	chars[0] = Character.toLowerCase(chars[0]);
526 	return new String(chars);
527     }
528 
529     // -------------------- Class path tools --------------------
530 
531     /*** Add all the jar files in a dir to the classpath,
532      *  represented as a Vector of URLs.
533      */
534     public static void addToClassPath( Vector cpV, String dir ) {
535 	try{
536             String cpComp[]=getFilesByExt(dir, ".jar");
537             if (cpComp != null){
538                 int jarCount=cpComp.length;
539                 for( int i=0; i< jarCount ; i++ ) {
540 		    URL url=getURL(  dir , cpComp[i] );
541                     if( url!=null )
542 			cpV.addElement( url );
543                 }
544             }
545         }catch(Exception ex){
546             ex.printStackTrace();
547         }
548     }
549 
550 
551     public static void addToolsJar( Vector v )
552     {
553 	try {
554             // Add tools.jar in any case
555             File f=new File( System.getProperty( "java.home" ) +
556                              "/../lib/tools.jar");
557 
558             if( ! f.exists() ) {
559                 // On some systems java.home gets set to the root of jdk.
560                 // That's a bug, but we can work around and be nice.
561                 f=new File( System.getProperty( "java.home" ) +
562                                  "/lib/tools.jar");
563                 if( f.exists() ) {
564                     System.out.println("Detected strange java.home value " +
565                                        System.getProperty( "java.home" ) +
566                                        ", it should point to jre");
567                 }
568             }
569             URL url=new URL( "file", "" , f.getAbsolutePath() );
570 
571 	    v.addElement( url );
572 	} catch ( MalformedURLException ex ) {
573 	    ex.printStackTrace();
574 	}
575     }
576 
577 
578     /*** Return all files with a given extension in a dir
579      */
580     public static String[] getFilesByExt( String ld, String ext ) {
581 	File dir = new File(ld);
582         String[] names=null;
583 	final String lext=ext;
584         if (dir.isDirectory()){
585             names = dir.list( new FilenameFilter(){
586             public boolean accept(File d, String name) {
587                 if (name.endsWith(lext)){
588                     return true;
589                 }
590                 return false;
591             }
592             });
593         }
594 	return names;
595     }
596 
597 
598     /*** Construct a file url from a file, using a base dir
599      */
600     public static URL getURL( String base, String file ) {
601         try {
602             File baseF = new File(base);
603             File f = new File(baseF,file);
604             String path = f.getCanonicalPath();
605             if( f.isDirectory() ){
606                     path +="/";
607             }
608 	    if( ! f.exists() ) return null;
609             return new URL( "file", "", path );
610         } catch (Exception ex) {
611             ex.printStackTrace();
612             return null;
613         }
614     }
615 
616     /***
617      * add elements from the classpath <i>cp</i> to a Vector
618      * <i>jars</i> as file URLs (We use Vector for JDK 1.1 compat).
619      *
620      * @param jars A vector of URLs
621      * @param cp a String classpath of directory or jar file
622      *                    elements separated by path.separator delimiters.
623      */
624     public static void addJarsFromClassPath(Vector jars, String cp)
625             throws IOException,MalformedURLException
626     {
627         String sep = System.getProperty("path.separator");
628         String token;
629         StringTokenizer st;
630         if(cp!=null){
631             st = new StringTokenizer(cp,sep);
632             while(st.hasMoreTokens()){
633                 File f = new File(st.nextToken());
634                 String path = f.getCanonicalPath();
635                 if(f.isDirectory()){
636                         path += "/";
637                 }
638                 URL url = new URL("file","",path);
639                 if(!jars.contains(url)){
640                         jars.addElement(url);
641                 }
642             }
643         }
644     }
645 
646     /*** Return a URL[] that can be used to construct a class loader
647      */
648     public static URL[] getClassPath(Vector v){
649         URL[] urls=new URL[ v.size() ];
650         for( int i=0; i<v.size(); i++ ) {
651             urls[i]=(URL)v.elementAt( i );
652         }
653         return urls;
654     }
655 
656     /*** Construct a URL classpath from files in a directory,
657      *  a cpath property, and tools.jar.
658      */
659     public static URL[] getClassPath( String dir, String cpath,
660 				      String cpathProp, boolean addTools )
661 	throws IOException, MalformedURLException
662     {
663 	Vector jarsV = new Vector();
664 	if( dir!=null ) {
665 	    // Add dir/classes first, if it exists
666 	    URL url=getURL( dir, "classes");
667 	    if( url!=null )
668 		jarsV.addElement(url);
669 	    addToClassPath( jarsV, dir );
670 	}
671 
672 	if( cpath != null )
673 	    addJarsFromClassPath(jarsV,cpath);
674 
675 	if( cpathProp!=null ) {
676 	    String cpath1=System.getProperty( cpathProp );
677 	    addJarsFromClassPath(jarsV,cpath1);
678 	}
679 
680 	if(addTools)
681 	    addToolsJar( jarsV );
682 
683 	return getClassPath(jarsV);
684     }
685 
686     // -------------------- Mapping command line params to setters
687 
688     public static boolean processArgs(Object proxy, String args[] )
689 	throws Exception
690     {
691 	String args0[]=null;
692 	if( null != findMethod( proxy.getClass(),
693 				"getOptions1", new Class[] {} )) {
694 	    args0=(String[])callMethod0( proxy, "getOptions1");
695 	}
696 
697 	if( args0==null ) {
698 	    //args0=findVoidSetters(proxy.getClass());
699 	    args0=findBooleanSetters(proxy.getClass());
700 	}
701 	Hashtable h=null;
702 	if( null != findMethod( proxy.getClass(),
703 				"getOptionAliases", new Class[] {} )) {
704 	    h=(Hashtable)callMethod0( proxy, "getOptionAliases");
705 	}
706 	return processArgs( proxy, args, args0, null, h );
707     }
708 
709     public static boolean processArgs(Object proxy, String args[],
710 				      String args0[], String args1[],
711 				      Hashtable aliases )
712 	throws Exception
713     {
714 	for( int i=0; i< args.length; i++ ) {
715 	    String arg=args[i];
716 	    if( arg.startsWith("-"))
717 		arg=arg.substring(1);
718 	    if( aliases != null && aliases.get( arg ) != null)
719 		arg=(String)aliases.get(arg);
720 
721 	    if( args0!=null ) {
722 		boolean set=false;
723 		for( int j=0; j< args0.length ; j++ ) {
724 		    if( args0[j].equalsIgnoreCase( arg )) {
725 			setProperty( proxy, args0[j], "true");
726 			set=true;
727 			break;
728 		    }
729 		}
730 		if( set ) continue;
731 	    }
732 	    if( args1!=null ) {
733 		for( int j=0; j< args1.length ; j++ ) {
734 		    if( args1[j].equalsIgnoreCase( arg )) {
735 			i++;
736 			if( i >= args.length )
737 			    return false;
738 			setProperty( proxy, arg, args[i]);
739 			break;
740 		    }
741 		}
742 	    } else {
743 		// if args1 is not specified,assume all other options have param
744 		i++;
745 		if( i >= args.length )
746 		    return false;
747 		setProperty( proxy,arg, args[i]);
748 	    }
749 
750 	}
751 	return true;
752     }
753 
754     // -------------------- other utils  --------------------
755     public static String[] findVoidSetters( Class c ) {
756 	Method m[]=findMethods( c );
757 	if( m==null ) return null;
758 	Vector v=new Vector();
759 	for( int i=0; i<m.length; i++ ) {
760 	    if( m[i].getName().startsWith("set") &&
761 		m[i].getParameterTypes().length == 0 ) {
762 		String arg=m[i].getName().substring( 3 );
763 		v.addElement( unCapitalize( arg ));
764 	    }
765 	}
766 	String s[]=new String[v.size()];
767 	for( int i=0; i<s.length; i++ ) {
768 	    s[i]=(String)v.elementAt( i );
769 	}
770 	return s;
771     }
772 
773     public static String[] findBooleanSetters( Class c ) {
774 	Method m[]=findMethods( c );
775 	if( m==null ) return null;
776 	Vector v=new Vector();
777 	for( int i=0; i<m.length; i++ ) {
778 	    if( m[i].getName().startsWith("set") &&
779 	    	m[i].getParameterTypes().length == 1 &&
780 	    	"boolean".equalsIgnoreCase( m[i].getParameterTypes()[0].getName()) ) {
781 	    	String arg=m[i].getName().substring( 3 );
782 	    	v.addElement( unCapitalize( arg ));
783 	    }
784 	}
785 	String s[]=new String[v.size()];
786 	for( int i=0; i<s.length; i++ ) {
787 	    s[i]=(String)v.elementAt( i );
788 	}
789 	return s;
790     }
791 
792     static Hashtable objectMethods=new Hashtable();
793 
794     public static void clear() {
795         objectMethods.clear();
796     }
797 
798     public static Method[] findMethods( Class c ) {
799 	Method methods[]= (Method [])objectMethods.get( c );
800 	if( methods != null ) return methods;
801 
802 	methods=c.getMethods();
803 	objectMethods.put( c, methods );
804 	return methods;
805     }
806 
807     public static Method findMethod( Class c, String name, Class params[] ) {
808 	Method methods[] = findMethods( c );
809 	if( methods==null ) return null;
810 	for (int i = 0; i < methods.length; i++) {
811 	    if (methods[i].getName().equals(name) ) {
812 		Class methodParams[]=methods[i].getParameterTypes();
813 		if( methodParams==null )
814 		    if( params==null || params.length==0 )
815 			return methods[i];
816 		if( params==null )
817 		    if( methodParams==null || methodParams.length==0 )
818 			return methods[i];
819 		if( params.length != methodParams.length )
820 		    continue;
821 		boolean found=true;
822 		for( int j=0; j< params.length; j++ ) {
823 		    if( params[j] != methodParams[j] ) {
824 			found=false;
825 			break;
826 		    }
827 		}
828 		if( found ) return methods[i];
829 	    }
830 	}
831 	return null;
832     }
833 
834     /*** Test if the object implements a particular
835      *  method
836      */
837     public static boolean hasHook( Object obj, String methodN ) {
838 	try {
839 	    Method myMethods[]=findMethods( obj.getClass() );
840 	    for( int i=0; i< myMethods.length; i++ ) {
841 		if( methodN.equals ( myMethods[i].getName() )) {
842 		    // check if it's overriden
843 		    Class declaring=myMethods[i].getDeclaringClass();
844 		    Class parentOfDeclaring=declaring.getSuperclass();
845 		    // this works only if the base class doesn't extend
846 		    // another class.
847 
848 		    // if the method is declared in a top level class
849 		    // like BaseInterceptor parent is Object, otherwise
850 		    // parent is BaseInterceptor or an intermediate class
851 		    if( ! "java.lang.Object".
852 			equals(parentOfDeclaring.getName() )) {
853 			return true;
854 		    }
855 		}
856 	    }
857 	} catch ( Exception ex ) {
858 	    ex.printStackTrace();
859 	}
860 	return false;
861     }
862 
863     public static void callMain( Class c, String args[] )
864 	throws Exception
865     {
866 	Class p[]=new Class[1];
867 	p[0]=args.getClass();
868 	Method m=c.getMethod( "main", p);
869 	m.invoke( c, new Object[] {args} );
870     }
871 
872     public static Object callMethod1( Object target,
873 				    String methodN,
874 				    Object param1,
875 				    String typeParam1,
876 				    ClassLoader cl)
877 	throws Exception
878     {
879 	if( target==null || param1==null ) {
880 	    d("Assert: Illegal params " + target + " " + param1 );
881 	}
882 	if( dbg > 0 ) d("callMethod1 " + target.getClass().getName() +
883 			" " + param1.getClass().getName() +
884 			" " + typeParam1 );
885 
886 	Class params[]=new Class[1];
887 	if( typeParam1==null )
888 	    params[0]=param1.getClass();
889 	else
890 	    params[0]=cl.loadClass( typeParam1 );
891 	Method m=findMethod( target.getClass(), methodN, params);
892 	if( m==null )
893 	    throw new NoSuchMethodException(target.getClass().getName() +
894 					    " " + methodN);
895 	return m.invoke(target,  new Object[] {param1 } );
896     }
897 
898     public static Object callMethod0( Object target,
899 				    String methodN)
900 	throws Exception
901     {
902 	if( target==null ) {
903 	    d("Assert: Illegal params " + target );
904 	    return null;
905 	}
906 	if( dbg > 0 )
907 	    d("callMethod0 " + target.getClass().getName() + "." + methodN);
908 
909 	Class params[]=new Class[0];
910 	Method m=findMethod( target.getClass(), methodN, params);
911 	if( m==null )
912 	    throw new NoSuchMethodException(target.getClass().getName() +
913 					    " " + methodN);
914 	return m.invoke(target,  emptyArray );
915     }
916 
917     static Object[] emptyArray=new Object[] {};
918 
919     public static Object callMethodN( Object target,  String methodN,
920 				    Object params[],  Class typeParams[] )
921 	throws Exception
922     {
923 	Method m=null;
924 	m=findMethod( target.getClass(), methodN, typeParams );
925         if( m== null ) {
926 	    d("Can't find method " + methodN + " in " +
927 	      target + " CLASS " + target.getClass());
928 	    return null;
929 	}
930 	Object o=m.invoke( target, params );
931 
932 	if(dbg > 0 ) {
933 	    // debug
934 	    StringBuffer sb=new StringBuffer();
935 	    sb.append("" + target.getClass().getName() + "." + methodN + "( " );
936 	    for(int i=0; i<params.length; i++ ) {
937 		if(i>0) sb.append( ", ");
938 		sb.append(params[i]);
939 	    }
940 	    sb.append(")");
941 	    d(sb.toString());
942 	}
943 	return o;
944     }
945 
946     // -------------------- Get property --------------------
947     // This provides a layer of abstraction
948 
949     public static interface PropertySource {
950 
951 	public String getProperty( String key );
952 
953     }
954 
955     public static interface AttributeHolder {
956 
957 	public void setAttribute( String key, Object o );
958 
959     }
960 
961 
962     // debug --------------------
963     static final int dbg=0;
964     static void d(String s ) {
965 	System.out.println("IntrospectionUtils: " + s );
966     }
967 }