de.lmu.ifi.dbs.jfeaturelib.utils.PackageScanner.java Source code

Java tutorial

Introduction

Here is the source code for de.lmu.ifi.dbs.jfeaturelib.utils.PackageScanner.java

Source

/*
 * This file is part of the JFeatureLib project: http://jfeaturelib.googlecode.com
 * JFeatureLib is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * JFeatureLib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with JFeatureLib; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * You are kindly asked to refer to the papers of the according authors which 
 * should be mentioned in the Javadocs of the respective classes as well as the 
 * JFeatureLib project itself.
 * 
 * Hints how to cite the projects can be found at 
 * https://code.google.com/p/jfeaturelib/wiki/Citation
 */
package de.lmu.ifi.dbs.jfeaturelib.utils;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Modifier;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.log4j.Logger;

/**
 * The PackageScanner class is used to find classes deriving a certain class within a package.
 *
 * THis can be useful for example if you need all Classes extending the FeatureDescriptor interface within a certain
 * package.
 *
 * @author Franz
 */
public class PackageScanner<T> {

    private static final Logger log = Logger.getLogger(PackageScanner.class.getName());
    private boolean includeInnerClasses = false;
    private boolean includeInterfaces = false;
    private boolean includeAbstractClasses = false;

    List<String> getNames(Package inPackage)
            throws UnsupportedEncodingException, URISyntaxException, ZipException, IOException {
        List<String> binaryNames = new ArrayList<>();

        String packagePath = inPackage.getName();
        packagePath = packagePath.replace('.', '/');

        // During tests, this points to the classes/ directory, later, this points to the jar
        CodeSource src = PackageScanner.class.getProtectionDomain().getCodeSource();
        URL location = src.getLocation();
        // test case
        File dirOrJar = new File(location.toURI());
        if (dirOrJar.isDirectory()) {
            // +1 to include the slash after the directory name
            int basePathLength = dirOrJar.toString().length() + 1;
            File packageDir = new File(dirOrJar, packagePath);

            // list all .class files in this package directory
            for (File file : packageDir.listFiles((FilenameFilter) new SuffixFileFilter(".class"))) {
                // strip the leading directory
                String binaryName = file.getPath().substring(basePathLength);
                binaryName = pathToBinary(binaryName);
                binaryNames.add(binaryName);
            }

        } else {
            try (ZipFile jar = new ZipFile(dirOrJar)) {
                for (Enumeration entries = jar.entries(); entries.hasMoreElements();) {
                    String binaryName = ((ZipEntry) entries.nextElement()).getName();
                    if (!binaryName.endsWith(".class")) { // we only need classes
                        continue;
                    }
                    if (binaryName.startsWith(packagePath)) {
                        binaryName = pathToBinary(binaryName);
                        binaryNames.add(binaryName);
                    }
                }
            }
        }

        return binaryNames;
    }

    /**
     * Convert a path to a binary name by replacing (back) slashes to periods and removing '.class'
     *
     * @param path
     * @return binary name
     */
    private String pathToBinary(String path) {
        // directory to package
        path = path.replace("\\", ".");
        path = path.replace("/", ".");
        path = path.replace(".class", "");
        return path;
    }

    public List<Class<T>> scanForClass(Package thePackage, Class<T> needle)
            throws IOException, UnsupportedEncodingException, URISyntaxException {
        List<String> binaryNames = getNames(thePackage);
        List<Class<T>> list = new ArrayList<>();

        ClassLoader loader = ClassLoader.getSystemClassLoader();
        for (String binaryName : binaryNames) {
            if (binaryName.contains("$") && !includeInnerClasses) {
                log.debug("Skipped inner class: " + binaryName);
                continue;
            }

            try {
                Class<?> clazz = loader.loadClass(binaryName);
                int modifiers = clazz.getModifiers();
                if ((modifiers & Modifier.INTERFACE) != 0 && !includeInterfaces) {
                    log.debug("Skipped interface: " + binaryName);
                    continue;
                }
                if ((modifiers & Modifier.ABSTRACT) != 0 && !includeAbstractClasses) {
                    log.debug("Skipped abstract class: " + binaryName);
                    continue;
                }
                if (needle.isAssignableFrom(clazz)) {
                    log.debug("added class/interface/..: " + binaryName);
                    list.add((Class<T>) clazz);
                }
            } catch (ClassNotFoundException e) {
                // This should never happen
                log.warn("couldn't find class (?!): " + binaryName, e);
            }
        }
        return list;
    }

    //<editor-fold defaultstate="collapsed" desc="getter & setter">
    public boolean isIncludeInnerClasses() {
        return includeInnerClasses;
    }

    public void setIncludeInnerClasses(boolean includeInnerClasses) {
        this.includeInnerClasses = includeInnerClasses;
    }

    public boolean isIncludeInterfaces() {
        return includeInterfaces;
    }

    public void setIncludeInterfaces(boolean includeInterfaces) {
        this.includeInterfaces = includeInterfaces;
    }

    public boolean isIncludeAbstractClasses() {
        return includeAbstractClasses;
    }

    public void setIncludeAbstractClasses(boolean includeAbstractClasses) {
        this.includeAbstractClasses = includeAbstractClasses;
    }
    //</editor-fold>
}