/**
* SPINdle (version 2.2.2)
* Copyright (C) 2009-2012 NICTA Ltd.
*
* This file is part of SPINdle project.
*
* SPINdle is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SPINdle 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SPINdle. If not, see <http://www.gnu.org/licenses/>.
*
* @author H.-P. Lam (oleklam@gmail.com), National ICT Australia - Queensland Research Laboratory
*/
package com.app.utils;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;
public class ClassList {
private ClassLoader classLoader = null;
private Set<String> interfaceFilter = null;
private Set<String> packageFilter = null;
private Set<String> jarFilter = null;
public ClassList() {
this.classLoader = ResourcesUtils.class.getClassLoader();
}
public Map<String, Set<String>> findClass(Set<String> interfaceFilter, Set<String> packageFilter, Set<String> jarFilter)
throws IOException, ClassNotFoundException {
this.interfaceFilter = (null == interfaceFilter) ? new HashSet<String>() : interfaceFilter;
this.packageFilter = (null == packageFilter) ? new HashSet<String>() : packageFilter;
this.jarFilter = (null == jarFilter) ? new HashSet<String>() : jarFilter;
Map<String, Set<String>> classTable = new HashMap<String, Set<String>>();
Object[] classPaths = null;
try {
classPaths = ((java.net.URLClassLoader) ResourcesUtils.class.getClassLoader()).getURLs();
} catch (Exception e) {
classPaths = System.getProperty("java.class.path", "").split(File.pathSeparator);
}
for (int i = 0; i < classPaths.length; i++) {
File classPath = new File((URL.class).isInstance(classPaths[i]) ? ((URL) classPaths[i]).getFile() : classPaths[i].toString());
JarFile module = null;
@SuppressWarnings("rawtypes")
Enumeration files = null;
if (classPath.isDirectory() && this.jarFilter.size() == 0) {
Set<String> filesListing = new HashSet<String>();
listFiles(classPath, filesListing, classPath.toString());
files = Collections.enumeration(filesListing);
} else if (classPath.getName().endsWith(".jar")) {
if (this.jarFilter.size() != 0 && !this.jarFilter.contains(classPath.getName())) continue;
module = new JarFile(classPath);
files = module.entries();
}
while (files.hasMoreElements()) {
String filename = files.nextElement().toString();
if (filename.endsWith(".class")) {
String className = convertClassName(filename);
Set<String> interfaceNames = verifyClass(className);
if (null != interfaceNames && interfaceNames.size() > 0) {
Set<String> classList = null;
for (String interfaceName : interfaceNames) {
classList = classTable.get(interfaceName);
if (null == classList) {
classList = new HashSet<String>();
classTable.put(interfaceName, classList);
}
// if (classTable.containsKey(interfaceName)) {
// classList = classTable.get(interfaceName);
// } else {
// classList = new HashSet<String>();
// classTable.put(interfaceName, classList);
// }
if (!classList.contains(className)) classList.add(className);
}
}
}
}
if (null != module) module.close();
}
return classTable;
}
private String convertClassName(String filename) {
String f = filename.endsWith(".class") ? filename.substring(0, filename.length() - 6) : filename;
return f.replaceAll("[\\\\/]", ".");
}
public Map<String, Set<String>> identifyInterface(Set<String> interfaceNames, Set<String> classNames) throws ClassNotFoundException {
this.interfaceFilter = (null == interfaceFilter) ? new HashSet<String>() : interfaceFilter;
this.packageFilter = new HashSet<String>();
this.jarFilter = new HashSet<String>();
Map<String, Set<String>> classTable = new HashMap<String, Set<String>>();
for (String className : classNames) {
Set<String> interfaces = verifyClass(convertClassName(className));
for (String interfaceName : interfaceNames) {
if (interfaces.contains(interfaceName)) {
Set<String> classList = classTable.get(interfaceName);
if (null == classList) {
classList = new HashSet<String>();
classTable.put(interfaceName, classList);
}
if (!classList.contains(className)) classList.add(className);
}
}
}
return classTable;
}
private Set<String> verifyClass(String className) throws ClassNotFoundException {
try {
Class<?> clazz = (Class<?>) Class.forName(className, false, classLoader);
if (clazz.isInterface() || clazz.isEnum()) return null;
if (clazz.isAnnotation()) return null;
if (clazz.isSynthetic()) return null;
if (Modifier.isAbstract(clazz.getModifiers())) return null;
if (isRejectPackage(clazz.getPackage().getName())) return null;
Set<String> interfaceList = new HashSet<String>();
Set<String> s = new HashSet<String>();
getAllInterface(clazz, s);
for (String interfaceNameStr : s) {
if (!isRejectInterface(interfaceNameStr)) interfaceList.add(interfaceNameStr);
}
return (interfaceList.size() == 0) ? null : interfaceList;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void getAllInterface(Class<?> clazz, Set<String> interfacesSet) {
Class<?>[] interfaces = clazz.getInterfaces();
Class<?> c = clazz;
while (null != c) {
interfacesSet.add(c.getName());
c = c.getSuperclass();
}
for (Class<?> inte : interfaces) {
interfacesSet.add(inte.getName());
}
if (!clazz.getSuperclass().getName().equals("java.lang.Object")) {
getAllInterface(clazz.getSuperclass(), interfacesSet);
}
}
private boolean isRejectInterface(String interfaceName) {
if (interfaceFilter.size() == 0) return false;
if (interfaceFilter.contains(interfaceName)) return false;
return true;
}
private boolean isRejectPackage(String className) {
if (packageFilter.size() == 0) return false;
int loc = className.lastIndexOf(".");
String packageName = (loc > 0) ? className.substring(0, loc) : className;
for (String p : packageFilter) {
if (p.endsWith(".*") && packageName.startsWith(p.substring(0, p.length() - 2))) {
return false;
} else {
if (packageName.startsWith(p)) return false;
}
}
return true;
}
private void listFiles(File file, Set<String> fileListing, String parentPath) {
if (!file.exists()) return;
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
listFiles(f, fileListing, parentPath);
}
} else {
fileListing.add(file.toString().substring(parentPath.length() + 1));
}
}
public static void main(String... args) {
Set<String> interfaceFilter = new HashSet<String>();
interfaceFilter.add(spindle.io.TheoryParser.class.getName());
interfaceFilter.add(spindle.io.TheoryOutputter.class.getName());
System.out.println("f=" + interfaceFilter);
Set<String> packageFilter = new HashSet<String>();
packageFilter.add("spindle.*");
ClassList classList = new ClassList();
try {
classList.findClass(interfaceFilter, packageFilter, null);
} catch (Exception e) {
e.printStackTrace();
}
}
}