/* * AutoClassDiscovery.java * Copyright (C) 2007 University of Waikato, Hamilton, New Zealand * @author Richard Kirkby (rkirkby@cs.waikato.ac.nz) * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package tr.gov.ulakbim.jDenetX.core; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.*; import java.util.jar.JarEntry; import java.util.jar.JarFile; public class AutoClassDiscovery { protected static final Map<String, String[]> cachedClassNames = new HashMap<String, String[]>(); public static String[] findClassNames(String packageNameToSearch) { String[] cached = cachedClassNames.get(packageNameToSearch); if (cached == null) { HashSet<String> classNames = new HashSet<String>(); /*StringTokenizer pathTokens = new StringTokenizer(System .getProperty("java.class.path"), File.pathSeparator);*/ String packageDirName = packageNameToSearch.replace('.', File.separatorChar); String packageJarName = packageNameToSearch.length() > 0 ? (packageNameToSearch .replace('.', '/') + "/") : ""; String part = ""; AutoClassDiscovery adc = new AutoClassDiscovery(); URLClassLoader sysLoader = (URLClassLoader) adc.getClass().getClassLoader(); URL[] cl_urls = sysLoader.getURLs(); for (int i = 0; i < cl_urls.length; i++) { part = cl_urls[i].toString(); if (part.startsWith("file:")) { part = part.replace(" ", "%20"); try { File temp = new File(new java.net.URI(part)); part = temp.getAbsolutePath(); } catch (URISyntaxException e) { e.printStackTrace(); } } // find classes ArrayList<File> files = new ArrayList<File>(); File dir = new File(part); if (dir.isDirectory()) { File root = new File(dir.toString() + File.separatorChar + packageDirName); String[] names = findClassesInDirectoryRecursive(root, ""); for (String name : names) { classNames.add(name); } } else { try { JarFile jar = new JarFile(part); Enumeration<JarEntry> jarEntries = jar.entries(); while (jarEntries.hasMoreElements()) { String jarEntry = jarEntries.nextElement() .getName(); if (jarEntry.startsWith(packageJarName)) { String relativeName = jarEntry .substring(packageJarName.length()); if (relativeName.endsWith(".class")) { relativeName = relativeName.replace('/', '.'); classNames.add(relativeName.substring(0, relativeName.length() - ".class".length())); } } } } catch (IOException ignored) { // ignore unreadable files } } } /*while (pathTokens.hasMoreElements()) { String pathToSearch = pathTokens.nextElement().toString(); if (pathToSearch.endsWith(".jar")) { try { JarFile jar = new JarFile(pathToSearch); Enumeration<JarEntry> jarEntries = jar.entries(); while (jarEntries.hasMoreElements()) { String jarEntry = jarEntries.nextElement() .getName(); if (jarEntry.startsWith(packageJarName)) { String relativeName = jarEntry .substring(packageJarName.length()); if (relativeName.endsWith(".class")) { relativeName = relativeName.replace('/', '.'); classNames.add(relativeName.substring(0, relativeName.length() - ".class".length())); } } } } catch (IOException ignored) { // ignore unreadable files } } else { File root = new File(pathToSearch + File.separatorChar + packageDirName); String[] names = findClassesInDirectoryRecursive(root, ""); for (String name : names) { classNames.add(name); } } } */ cached = classNames.toArray(new String[classNames.size()]); Arrays.sort(cached); cachedClassNames.put(packageNameToSearch, cached); } return cached; } protected static String[] findClassesInDirectoryRecursive(File root, String packagePath) { HashSet<String> classNames = new HashSet<String>(); if (root.isDirectory()) { String[] list = root.list(); for (String string : list) { if (string.endsWith(".class")) { classNames.add(packagePath + string.substring(0, string.length() - ".class".length())); } else { File testDir = new File(root.getPath() + File.separatorChar + string); if (testDir.isDirectory()) { String[] names = findClassesInDirectoryRecursive( testDir, packagePath + string + "."); for (String name : names) { classNames.add(name); } } } } } return classNames.toArray(new String[classNames.size()]); } public static Class[] findClassesOfType(String packageNameToSearch, Class<?> typeDesired) { ArrayList<Class<?>> classesFound = new ArrayList<Class<?>>(); String[] classNames = findClassNames(packageNameToSearch); for (String className : classNames) { String fullName = packageNameToSearch.length() > 0 ? (packageNameToSearch + "." + className) : className; if (isPublicConcreteClassOfType(fullName, typeDesired)) { try { classesFound.add(Class.forName(fullName)); } catch (Exception ignored) { // ignore classes that we cannot instantiate } } } return classesFound.toArray(new Class[classesFound.size()]); } public static boolean isPublicConcreteClassOfType(String className, Class<?> typeDesired) { Class<?> testClass = null; try { testClass = Class.forName(className); } catch (Exception e) { return false; } int classModifiers = testClass.getModifiers(); return (java.lang.reflect.Modifier.isPublic(classModifiers) && !java.lang.reflect.Modifier.isAbstract(classModifiers) && typeDesired.isAssignableFrom(testClass) && hasEmptyConstructor(testClass)); } public static boolean hasEmptyConstructor(Class<?> type) { try { type.getConstructor(); return true; } catch (Exception ignored) { return false; } } }