/* * Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute * Copyright [2016-2017] EMBL-European Bioinformatics Institute * * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ensembl; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.JarURLConnection; import java.net.URL; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.regex.Pattern; /** * Collection of static methods for finding classes in a package. * */ public class PackageScan { /** * Retrieve classes that belong to the specified package from directories and jars on the classpath. Does not include * subpackages - use {@link #getClassesForPackage(String, boolean)} for this * behaviour. note that this will not support zip files. * * @author dstaines (fixed behaviour for subclasses) * @author Thanos.Panousis from * http://forums.sun.com/thread.jspa?messageID=10115467#10115467 * @param pckgname * name of package * @return list of matching classes * @throws ClassNotFoundException */ public static List<Class<?>> getClassesForPackage(String pckgname) throws ClassNotFoundException { return getClassesForPackage(pckgname, false); } /** * Retrieve classes that belong to the specified package. note that this will not support zip files. * * @author dstaines (fixed behaviour for subclasses) * @author Thanos.Panousis from * http://forums.sun.com/thread.jspa?messageID=10115467#10115467 * @param pckgname * name of package * @param sub * if true, include subpackages * @return list of matching classes * @throws ClassNotFoundException */ public static List<Class<?>> getClassesForPackage(String pckgname, boolean sub) throws ClassNotFoundException { // This will hold a list of directories matching the pckgname. // There may be more than one if a package is split over multiple // jars/paths List<Class<?>> classes = new ArrayList<Class<?>>(); List<File> directories = new ArrayList<File>(); Pattern classPattern = null; if (sub) { classPattern = Pattern.compile("^" + pckgname.replace('.', '/') + "[/A-z0-9_]+\\.class"); } else { classPattern = Pattern.compile("^" + pckgname.replace('.', '/') + "/[A-z0-9_]+\\.class"); } try { ClassLoader cld = Thread.currentThread().getContextClassLoader(); if (cld == null) { throw new ClassNotFoundException("Can't get class loader."); } // Ask for all resources for the path Enumeration<URL> resources = cld.getResources(pckgname.replace('.', '/')); while (resources.hasMoreElements()) { URL res = resources.nextElement(); if (res.getProtocol().equalsIgnoreCase("jar")) { JarURLConnection conn = (JarURLConnection) res .openConnection(); JarFile jar = conn.getJarFile(); for (JarEntry e : Collections.list(jar.entries())) { if (classPattern.matcher(e.getName()).matches()) { String className = e.getName().replace("/", ".") .substring(0, e.getName().length() - 6); classes.add(Class.forName(className)); } } } else directories.add(new File(URLDecoder.decode(res.getPath(), "UTF-8"))); } } catch (NullPointerException x) { throw new ClassNotFoundException(pckgname + " does not appear to be " + "a valid package (Null pointer exception)"); } catch (UnsupportedEncodingException encex) { throw new ClassNotFoundException(pckgname + " does not appear to be " + "a valid package (Unsupported encoding)"); } catch (IOException ioex) { throw new ClassNotFoundException( "IOException was thrown when trying " + "to get all resources for " + pckgname); } // For every directory identified capture all the .class files for (File directory : directories) { classes.addAll(getClassesForDirectory(directory, pckgname, sub)); } return classes; } protected static List<Class<?>> getClassesForDirectory(File directory, String pckgname, boolean sub) throws ClassNotFoundException { List<Class<?>> classes = new ArrayList<Class<?>>(); if (directory.exists() && directory.isDirectory()) { for (File f : directory.listFiles()) { if (f.isDirectory() && sub) { classes.addAll(getClassesForDirectory(f, pckgname + "." + f.getName(), sub)); } else { String name = f.getName(); if (name.matches("^[A-z0-9-]+\\.class$")) { // removes the .class extension try { String clazzName = pckgname + '.' + name.substring(0, name.length() - 6); classes.add(Class.forName(clazzName)); } catch (ClassNotFoundException e) { throw new ClassNotFoundException(pckgname + " (" + f.getPath() + ") does not appear to be a valid package"); } } } } } return classes; } }