package com.subhajit.classbench;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.zip.ZipFile;
import com.subhajit.common.util.CommonUtils;
import com.subhajit.common.util.CompletionExecutor;
import com.subhajit.common.util.CommonUtils.IResource;
public class ClasspathUtils {
/**
* Parses a directory or JAR file and returns an {@link Iterator} of
* {@link IResource} objects.
*
* @author sdasgupta
*
*/
private static final class ResourceParserCallable0 implements
Callable<Iterator<IResource>> {
private final File file;
private ResourceParserCallable0(File file) {
this.file = file;
}
public Iterator<IResource> call() throws Exception {
CommonUtils.IRepositoryParser parser = null;
try {
ZipFile zipFile = null;
try {
if (file.isDirectory()) {
parser = new CommonUtils.DirectoryParser(file);
} else if (file.isFile()) {
zipFile = new ZipFile(file);
parser = new CommonUtils.ZipParser(zipFile);
}
return parser.iterator();
} finally {
if (zipFile != null) {
zipFile.close();
}
}
} finally {
if (parser != null) {
parser.close();
}
}
}
}
/**
* Finds duplicate classes defined within the context of the given
* {@link Classpath}.
*
* @param cp
* @param packages
* @return
* @throws IOException
* @throws ClassNotFoundException
* @throws InterruptedException
*/
public static Set<String> findDuplicateClasses(Classpath cp,
String... packages) throws IOException, ClassNotFoundException,
InterruptedException {
return findDuplicateClassesAndLocations(cp, packages).keySet();
}
/**
* Returns a {@link Map} containing {@link Entry}'s in which the
* {@link Entry#getKey()} is the name of a class, and the
* {@link Entry#getValue()} is a {@link List} of {@link File}'s in which the
* class is found.
*
* @param cp
* @param packages
* @return
* @throws InterruptedException
* @throws IOException
* @throws ClassNotFoundException
*/
public static Map<String, List<File>> findDuplicateClassesAndLocations(
Classpath cp, String... packages) throws InterruptedException,
IOException, ClassNotFoundException {
Map<String, List<File>> map = new HashMap<String, List<File>>();
CompletionExecutor<Iterator<IResource>> ce = null;
try {
ce = new CompletionExecutor<Iterator<IResource>>(5);
for (final File file : cp.getElements()) {
ce.submit(new ResourceParserCallable0(file));
}
while (true) {
try {
Map.Entry<Boolean, Iterator<IResource>> entry = ce
.getNextSubmitted();
if (!entry.getKey()) {
break;
}
while (entry.getValue().hasNext()) {
IResource resource = entry.getValue().next();
if (!resource.isDirectory()
&& resource.getName().endsWith(".class")) {
List<File> files = map.get(resource.getName());
if (files == null) {
files = new ArrayList<File>();
map.put(resource.getName(), files);
}
files.add(resource.getFile());
}
}
} catch (ExecutionException exc) {
if (exc.getCause() instanceof InterruptedException) {
throw (InterruptedException) exc.getCause();
} else if (exc.getCause() instanceof IOException) {
throw (IOException) exc.getCause();
} else if (exc.getCause() instanceof ClassNotFoundException) {
throw (ClassNotFoundException) exc.getCause();
} else {
throw new UndeclaredThrowableException(exc.getCause());
}
}
}
Map<String, List<File>> duplicateClasses = new HashMap<String, List<File>>();
for (Map.Entry<String, List<File>> entry : map.entrySet()) {
if (entry.getValue().size() > 1) {
String className = entry.getKey().substring(0,
entry.getKey().lastIndexOf(".class")).replace('/',
'.');
duplicateClasses.put(className, entry.getValue());
}
}
return duplicateClasses;
} finally {
if (ce != null) {
ce.close();
}
}
}
public static Set<String> getAllClasses(Classpath cp)
throws InterruptedException, IOException, ClassNotFoundException {
Map<String, List<File>> map = new HashMap<String, List<File>>();
CompletionExecutor<Iterator<IResource>> ce = null;
try {
ce = new CompletionExecutor<Iterator<IResource>>(5);
for (final File file : cp.getElements()) {
ce.submit(new ResourceParserCallable0(file));
}
while (true) {
try {
Map.Entry<Boolean, Iterator<IResource>> entry = ce
.getNextSubmitted();
if (!entry.getKey()) {
break;
}
while (entry.getValue().hasNext()) {
IResource resource = entry.getValue().next();
if (!resource.isDirectory()
&& resource.getName().endsWith(".class")) {
List<File> files = map.get(resource.getName());
if (files == null) {
files = new ArrayList<File>();
map.put(resource.getName(), files);
}
files.add(resource.getFile());
}
}
} catch (ExecutionException exc) {
if (exc.getCause() instanceof InterruptedException) {
throw (InterruptedException) exc.getCause();
} else if (exc.getCause() instanceof IOException) {
throw (IOException) exc.getCause();
} else if (exc.getCause() instanceof ClassNotFoundException) {
throw (ClassNotFoundException) exc.getCause();
} else {
throw new UndeclaredThrowableException(exc.getCause());
}
}
}
return map.keySet();
} finally {
if (ce != null) {
ce.close();
}
}
}
public static Map<String, List<File>> findClassLocations(Classpath cp,
String... classNames) throws IOException, ClassNotFoundException,
InterruptedException {
final Map<String, List<File>> map = new HashMap<String, List<File>>();
CompletionExecutor<Iterator<IResource>> ce = null;
try {
ce = new CompletionExecutor<Iterator<IResource>>(5);
for (final File file : cp.getElements()) {
ce.submit(new ResourceParserCallable0(file));
}
Set<String> classNamesSet = new HashSet<String>();
for (String className : classNames) {
classNamesSet.add(className.replace('.', '/') + ".class");
}
while (true) {
try {
Map.Entry<Boolean, Iterator<IResource>> entry = ce
.getNextSubmitted();
if (!entry.getKey()) {
break;
}
while (entry.getValue().hasNext()) {
IResource resource = entry.getValue().next();
String resourceName = resource.getName();
if (!resource.isDirectory()
&& classNamesSet.contains(resourceName)) {
List<File> files = map.get(resourceName);
if (files == null) {
files = new ArrayList<File>();
map.put(resourceName, files);
}
files.add(resource.getFile());
}
}
} catch (ExecutionException exc) {
if (exc.getCause() instanceof InterruptedException) {
throw (InterruptedException) exc.getCause();
} else if (exc.getCause() instanceof IOException) {
throw (IOException) exc.getCause();
} else if (exc.getCause() instanceof ClassNotFoundException) {
throw (ClassNotFoundException) exc.getCause();
} else {
throw new UndeclaredThrowableException(exc.getCause());
}
}
}
Map<String, List<File>> ret = new HashMap<String, List<File>>();
for (Map.Entry<String, List<File>> entry : map.entrySet()) {
ret.put(getClassName(entry.getKey()), entry.getValue());
}
map.clear();
return ret;
} finally {
if (ce != null) {
ce.close();
}
}
}
private static String getClassName(String resourceName) {
return resourceName.substring(0, resourceName.lastIndexOf(".class"))
.replace('/', '.');
}
}