Mega Code Archive

 
Categories / Java / Reflection
 

Search over classpath retrieving classes that implement a certain interface

/*  * The contents of this file are subject to the Sapient Public License  * Version 1.0 (the "License"); you may not use this file except in compliance  * with the License. You may obtain a copy of the License at  * http://carbon.sf.net/License.html.  *  * Software distributed under the License is distributed on an "AS IS" basis,  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for  * the specific language governing rights and limitations under the License.  *  * The Original Code is The Carbon Component Framework.  *  * The Initial Developer of the Original Code is Sapient Corporation  *  * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.  */ import java.io.File; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.StringTokenizer; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /**  * <p>This class implements the capability to search over the current classpath  * retrieving classes that implement a certain interface.</p>  *  * Copyright 2001 Sapient  * @since carbon 1.0  * @author Greg Hinkle, June 2001  * @version $Revision: 1.10 $($Author: dvoet $ / $Date: 2003/05/05 21:21:23 $)  */ public class ClassFinder {     /**      * Tracks the count of classes found that match the      * provided criteria.      */     protected long foundClasses = 0;     /**      * The super class criteria      */     protected Class superClass = null;     /**      * The required substring path criteria for this searcher      */     protected String requiredPathSubstring = null;     /**      * The set of classes found matching the provided criteria.      */     protected Set classes = new HashSet(2000);     /**      * <p>Instantiates the type of MBeanHarvester that will return all classes      * in the entire classpath.</p>      */     public ClassFinder() {     }     /**      * <p>Instantiates the type of MBeanHarvester that will return all classes      * that are assignable to the supplied class. This would include all      * implementations of it, if it is an interface or it and all subclasses      * of it if it's a class.</p>      *      * @param superClass the Class that should be searched for along with      *   implementations and subclasses      */     public ClassFinder(Class superClass) {         this.superClass = superClass;     }     /**      * <p>Instantiates the type of MBeanHarvester that will return all classes      * that are assignable to the supplied class and are part of the supplied      * package. This would include all  implementations of it, if it is an      * interface or it and all subclasses of it if it's a class. The      * supplied <code>requiredPathSubstring must be part of the fully      * qualified classname.</p>      *      * @param superClass the Class that should be searched for along with      *   implementations and subclasses      * @param requiredPathSubstring the String part that must be found in the      *   classes FQN      */     public ClassFinder(Class superClass, String requiredPathSubstring) {         this.superClass = superClass;         this.requiredPathSubstring = requiredPathSubstring;     }     /**      * <p>Adds a class name to the list of found classes if and only if it meets      * the configured requirements.</p>      *      * @param className the FQN String name of the class to add      */     protected void addClassName(String className) {         // Only add this class if we're not checking for a particular         // substring of the FQN or we find that substring         if ((this.requiredPathSubstring == null) ||             (className.indexOf(this.requiredPathSubstring) >= 0)) {             if (this.superClass == null) {                 this.classes.add(className);             } else {                 try {                     // TODO: GH - add a way to search other classpaths and the                     // system classpath.                     Class theClass =                         Class.forName(                             className,                             false,                             this.getClass().getClassLoader());                     if (this.superClass.isAssignableFrom(theClass)) {                         this.classes.add(className);                     }                 } catch (ClassNotFoundException cnfe) {                     // Used to catch mis-parsed classnames                 } catch (Throwable t) {                     // Used to catch JVM security and linkage errors                 }             }         }     }     /**      * <p>Used to retrieve the results <code>Set</code> from this harvester's      * search.</p>      *      * @return Set the set of classes that meet this harvester's requirements      */     public Set getClasses() {         // 1) tokenize classpath         String classpath = System.getProperty("java.class.path");         String pathSeparator = System.getProperty("path.separator");         StringTokenizer st = new StringTokenizer(classpath,pathSeparator);         // 2) for each element in the classpath         while (st.hasMoreTokens()) {             File currentDirectory = new File(st.nextToken());             processFile(currentDirectory.getAbsolutePath(),"");         }         return this.classes;     }     /**      * Recursively search through Directories with special checks to recognize      * zip and jar files. (Zip and Jar files return true from      * &lt;File&gt;.isDirectory())      * @param base the base file path to search      * @param current the current recursively searched file path being searched      */     private void processFile(String base, String current) {         File currentDirectory = new File(base + File.separatorChar + current);         // Handle special for archives         if (isArchive(currentDirectory.getName())) {             try {                 processZip(new ZipFile(currentDirectory));             } catch (Exception e) {                 // The directory was not found so the classpath was probably in                 // error or we don't have rights to it             }             return;         } else {             Set directories = new HashSet();             File[] children = currentDirectory.listFiles();             // if no children, return             if (children == null || children.length == 0) {                 return;             }             // check for classfiles             for (int i = 0; i < children.length; i++) {                 File child = children[i];                 if (child.isDirectory()) {                     directories.add(children[i]);                 } else {                     if (child.getName().endsWith(".class")) {                         String className =                             getClassName(                                 current +                                 ((current == "") ? "" : File.separator) +                                 child.getName());                         addClassName(className);                         this.foundClasses++;                     }                 }             }             //call process file on each directory.  This is an iterative call!!             for (Iterator i = directories.iterator(); i.hasNext(); ) {                 processFile(base, current + ((current=="")?"":File.separator) +                     ((File)i.next()).getName());             }         }     }     /**      * <p>Looks at the name of a file to determine if it is an archive</p>      * @param name the name of a file      * @return true if a file in the classpath is an archive      * such as a Jar or Zip file      */     protected boolean isArchive(String name) {         if ((name.endsWith(".jar") ||             (name.endsWith(".zip")))) {             return true;         } else {             return false;         }     }     /**      * <p>Returns the Fully Qualified Class name of a class from it's path      * @param fileName the full path to a class      * @return the FQN of a class      */     protected String getClassName(String fileName) {         String newName =  fileName.replace(File.separatorChar,'.');         // Because zipfiles don't have platform specific seperators         newName =  newName.replace('/','.');         return newName.substring(0, fileName.length() - 6);     }     /**      * <P>Iterates through the files in a zip looking for files that may be      * classes. This is not recursive as zip's in zip's are not searched by the      * classloader either.</p>      *      * @param file The ZipFile to be searched      */     protected void processZip(ZipFile file) {         Enumeration files = file.entries();         while (files.hasMoreElements()) {             Object tfile = files.nextElement();             ZipEntry child = (ZipEntry) tfile;             if (child.getName().endsWith(".class")) {                 addClassName(getClassName(child.getName()));                 this.foundClasses++;             }         }     } }