FactoryLoader.java
package net.morimekta.providence.generator.util;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.jar.Manifest;
public class FactoryLoader<Factory> {
private final String manifestProperty;
public FactoryLoader(String manifestProperty) {
this.manifestProperty = manifestProperty;
}
public List<Factory> getFactories(File path) {
try {
List<File> jars = findJarFiles(path);
List<Factory> factories = new ArrayList<>();
for (File jar : jars) {
URLClassLoader classLoader = getClassLoader(jar);
Factory factory = getFactory(classLoader);
if (factory != null) {
factories.add(factory);
}
}
return factories;
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
public Factory getFactory(File file) {
try {
return getFactory(getClassLoader(file));
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
private List<File> findJarFiles(File path) {
List<File> out = new ArrayList<>();
if (path.isFile()) {
out.add(path);
} else {
File[] files = path.listFiles();
if (files != null) {
for (File file : files) {
if (file.getName().toLowerCase(Locale.US).endsWith(".jar")) {
out.add(file);
}
}
}
}
return out;
}
private URLClassLoader getClassLoader(File file) throws MalformedURLException {
return URLClassLoader.newInstance(new URL[]{file.toURI().toURL()}, ClassLoader.getSystemClassLoader());
}
private Factory getFactory(URLClassLoader classLoader)
throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
URL url = classLoader.findResource("META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(url.openStream());
String factoryClass = manifest.getMainAttributes().getValue(manifestProperty);
if (factoryClass == null) {
return null;
}
@SuppressWarnings("unchecked")
Class<Factory> klass = (Class<Factory>) classLoader.loadClass(factoryClass);
try {
return klass.getConstructor().newInstance();
} catch (NoSuchMethodException | InvocationTargetException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
}