MOA 12.03
Real Time Analytics for Data Streams
|
00001 /* 00002 * AutoClassDiscovery.java 00003 * Copyright (C) 2007 University of Waikato, Hamilton, New Zealand 00004 * @author Richard Kirkby ([email protected]) 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 3 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 * 00019 */ 00020 package moa.core; 00021 00022 import java.io.File; 00023 import java.io.IOException; 00024 import java.net.URL; 00025 import java.net.URLClassLoader; 00026 import java.net.URISyntaxException; 00027 import java.util.ArrayList; 00028 import java.util.Arrays; 00029 import java.util.Enumeration; 00030 import java.util.HashMap; 00031 import java.util.HashSet; 00032 import java.util.Map; 00033 import java.util.jar.JarEntry; 00034 import java.util.jar.JarFile; 00035 00042 public class AutoClassDiscovery { 00043 00044 protected static final Map<String, String[]> cachedClassNames = new HashMap<String, String[]>(); 00045 00046 public static String[] findClassNames(String packageNameToSearch) { 00047 String[] cached = cachedClassNames.get(packageNameToSearch); 00048 if (cached == null) { 00049 HashSet<String> classNames = new HashSet<String>(); 00050 /*StringTokenizer pathTokens = new StringTokenizer(System 00051 .getProperty("java.class.path"), File.pathSeparator);*/ 00052 String packageDirName = packageNameToSearch.replace('.', 00053 File.separatorChar); 00054 String packageJarName = packageNameToSearch.length() > 0 ? (packageNameToSearch.replace('.', '/') + "/") 00055 : ""; 00056 String part = ""; 00057 00058 00059 AutoClassDiscovery adc = new AutoClassDiscovery(); 00060 URLClassLoader sysLoader = (URLClassLoader) adc.getClass().getClassLoader(); 00061 URL[] cl_urls = sysLoader.getURLs(); 00062 00063 for (int i = 0; i < cl_urls.length; i++) { 00064 part = cl_urls[i].toString(); 00065 if (part.startsWith("file:")) { 00066 part = part.replace(" ", "%20"); 00067 try { 00068 File temp = new File(new java.net.URI(part)); 00069 part = temp.getAbsolutePath(); 00070 } catch (URISyntaxException e) { 00071 e.printStackTrace(); 00072 } 00073 } 00074 00075 // find classes 00076 ArrayList<File> files = new ArrayList<File>(); 00077 File dir = new File(part); 00078 if (dir.isDirectory()) { 00079 File root = new File(dir.toString() + File.separatorChar + packageDirName); 00080 String[] names = findClassesInDirectoryRecursive(root, ""); 00081 classNames.addAll(Arrays.asList(names)); 00082 } else { 00083 try { 00084 JarFile jar = new JarFile(part); 00085 Enumeration<JarEntry> jarEntries = jar.entries(); 00086 while (jarEntries.hasMoreElements()) { 00087 String jarEntry = jarEntries.nextElement().getName(); 00088 if (jarEntry.startsWith(packageJarName)) { 00089 String relativeName = jarEntry.substring(packageJarName.length()); 00090 if (relativeName.endsWith(".class")) { 00091 relativeName = relativeName.replace('/', 00092 '.'); 00093 classNames.add(relativeName.substring(0, 00094 relativeName.length() 00095 - ".class".length())); 00096 } 00097 } 00098 } 00099 } catch (IOException ignored) { 00100 // ignore unreadable files 00101 } 00102 } 00103 } 00104 00105 /*while (pathTokens.hasMoreElements()) { 00106 String pathToSearch = pathTokens.nextElement().toString(); 00107 if (pathToSearch.endsWith(".jar")) { 00108 try { 00109 JarFile jar = new JarFile(pathToSearch); 00110 Enumeration<JarEntry> jarEntries = jar.entries(); 00111 while (jarEntries.hasMoreElements()) { 00112 String jarEntry = jarEntries.nextElement() 00113 .getName(); 00114 if (jarEntry.startsWith(packageJarName)) { 00115 String relativeName = jarEntry 00116 .substring(packageJarName.length()); 00117 if (relativeName.endsWith(".class")) { 00118 relativeName = relativeName.replace('/', 00119 '.'); 00120 classNames.add(relativeName.substring(0, 00121 relativeName.length() 00122 - ".class".length())); 00123 } 00124 } 00125 } 00126 } catch (IOException ignored) { 00127 // ignore unreadable files 00128 } 00129 } else { 00130 File root = new File(pathToSearch + File.separatorChar 00131 + packageDirName); 00132 String[] names = findClassesInDirectoryRecursive(root, ""); 00133 for (String name : names) { 00134 classNames.add(name); 00135 } 00136 } 00137 } */ 00138 cached = classNames.toArray(new String[classNames.size()]); 00139 Arrays.sort(cached); 00140 cachedClassNames.put(packageNameToSearch, cached); 00141 } 00142 return cached; 00143 } 00144 00145 protected static String[] findClassesInDirectoryRecursive(File root, 00146 String packagePath) { 00147 HashSet<String> classNames = new HashSet<String>(); 00148 if (root.isDirectory()) { 00149 String[] list = root.list(); 00150 for (String string : list) { 00151 if (string.endsWith(".class")) { 00152 classNames.add(packagePath 00153 + string.substring(0, string.length() 00154 - ".class".length())); 00155 } else { 00156 File testDir = new File(root.getPath() + File.separatorChar 00157 + string); 00158 if (testDir.isDirectory()) { 00159 String[] names = findClassesInDirectoryRecursive( 00160 testDir, packagePath + string + "."); 00161 classNames.addAll(Arrays.asList(names)); 00162 } 00163 } 00164 } 00165 } 00166 return classNames.toArray(new String[classNames.size()]); 00167 } 00168 00169 public static Class[] findClassesOfType(String packageNameToSearch, 00170 Class<?> typeDesired) { 00171 ArrayList<Class<?>> classesFound = new ArrayList<Class<?>>(); 00172 String[] classNames = findClassNames(packageNameToSearch); 00173 for (String className : classNames) { 00174 String fullName = packageNameToSearch.length() > 0 ? (packageNameToSearch 00175 + "." + className) 00176 : className; 00177 if (isPublicConcreteClassOfType(fullName, typeDesired)) { 00178 try { 00179 classesFound.add(Class.forName(fullName)); 00180 } catch (Exception ignored) { 00181 // ignore classes that we cannot instantiate 00182 } 00183 } 00184 } 00185 return classesFound.toArray(new Class[classesFound.size()]); 00186 } 00187 00188 public static boolean isPublicConcreteClassOfType(String className, 00189 Class<?> typeDesired) { 00190 Class<?> testClass = null; 00191 try { 00192 testClass = Class.forName(className); 00193 } catch (Exception e) { 00194 return false; 00195 } 00196 int classModifiers = testClass.getModifiers(); 00197 return (java.lang.reflect.Modifier.isPublic(classModifiers) 00198 && !java.lang.reflect.Modifier.isAbstract(classModifiers) 00199 && typeDesired.isAssignableFrom(testClass) && hasEmptyConstructor(testClass)); 00200 } 00201 00202 public static boolean hasEmptyConstructor(Class<?> type) { 00203 try { 00204 type.getConstructor(); 00205 return true; 00206 } catch (Exception ignored) { 00207 return false; 00208 } 00209 } 00210 }