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