/*
* 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;
}
}
}