package be.lightinject.context;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.function.Predicate;
import static java.lang.Runtime.getRuntime;
import static java.lang.Thread.currentThread;
@SuppressWarnings("UnusedDeclaration")
public class PackageScanner {
private String packageName;
private Predicate<Class<?>> classFilter;
private final ClassLoader classLoader;
private final ForkJoinPool forkJoinPool;
private PackageScanner() {
classLoader = currentThread().getContextClassLoader();
assert classLoader != null;
forkJoinPool = new ForkJoinPool(getRuntime().availableProcessors());
classFilter = Predicates.alwaysTrue();
}
public static PackageScanner packageScanner() {
return new PackageScanner();
}
public PackageScanner from(String packageName){
this.packageName = packageName;
return this;
}
public PackageScanner with(Predicate<Class<?>> classFilter){
this.classFilter = classFilter;
return this;
}
public List<Class<?>> scan() {
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
List<ClassFinder> finders = new ArrayList<>();
getDirectoryToScan(getResourcesInPackage()).stream()
.map(directory -> new ClassFinder(directory, packageName, classFilter))
.forEach((finder) -> {
finders.add(finder);
forkJoinPool.execute(finder);
});
ArrayList<Class<?>> classes = new ArrayList<>();
finders.forEach((finder) -> classes.addAll(finder.join()));
return classes;
}
private List<String> getDirectoryToScan(Enumeration<URL> resources) {
try {
List<String> dirs = new ArrayList<>();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
dirs.add(URLDecoder.decode(resource.getFile(), "UTF-8"));
}
return dirs;
} catch(IOException e) {
throw new RuntimeException(e);
}
}
private Enumeration<URL> getResourcesInPackage() {
try {
String path = packageName.replace('.', '/');
return classLoader.getResources(path);
} catch(IOException e) {
throw new RuntimeException(e);
}
}
}