use of com.cinchapi.common.reflect.Reflection in project concourse by cinchapi.
the class PluginManager method activate.
/**
* Activating a {@code bundle} means that all the plugins with the bundle
* are loaded from disk and stored within the {@link #registry}. Depending
* on the {@code type} some pre-launch hooks may be run. If all those hooks
* are successful, each of the plugins in the bundle are
* {@link #launch(String, Path, Class, List) launched}.
*
* @param bundle the name of the plugin bundle
* @param type the {@link ActivationType type} of activation
*/
protected void activate(String bundle, ActivationType type) {
Logger.debug("Activating plugins from {}", bundle);
Path home = Paths.get(this.home, bundle);
Path lib = home.resolve("lib");
Path prefs = home.resolve("conf").resolve(PluginConfiguration.PLUGIN_PREFS_FILENAME);
Path prefsDev = home.resolve("conf").resolve(PluginConfiguration.PLUGIN_PREFS_DEV_FILENAME);
if (Files.exists(prefsDev)) {
prefs = prefsDev;
prefsDev = null;
}
try (DirectoryStream<Path> stream = Files.newDirectoryStream(lib)) {
Iterator<Path> jars = stream.iterator();
// Go through all the jars in the plugin's lib directory and compile
// the appropriate classpath while identifying jars that might
// contain plugin endpoints.
List<URL> urls = Lists.newArrayList();
List<String> classpath = Lists.newArrayList();
while (jars.hasNext()) {
String filename = jars.next().getFileName().toString();
Path path = lib.resolve(filename);
URL url = new File(path.toString()).toURI().toURL();
if (!SYSTEM_JARS.contains(filename) || type.mightRequireHooks()) {
// NOTE: by checking for exact name matches, we will
// accidentally include system jars that contain different
// versions.
// NOTE: if a hook must be run, we have to include all the
// jars (including system ones) so that the full context in
// which the hook was written is available.
urls.add(url);
}
classpath.add(url.getFile());
}
// Create a ClassLoader that only contains jars with possible plugin
// endpoints and search for any applicable classes.
URLClassLoader loader = new URLClassLoader(urls.toArray(new URL[0]), null);
Class parent = loader.loadClass(Plugin.class.getName());
Class realTimeParent = loader.loadClass(RealTimePlugin.class.getName());
Reflections reflection = new Reflections(new ConfigurationBuilder().addClassLoader(loader).addUrls(ClasspathHelper.forClassLoader(loader)));
Set<Class<?>> subTypes = reflection.getSubTypesOf(parent);
Iterable<Class<?>> plugins = subTypes.stream().filter((clz) -> !clz.isInterface() && !Modifier.isAbstract(clz.getModifiers()))::iterator;
JsonObject manifest = loadBundleManifest(bundle);
Version version = Versions.parseSemanticVersion(manifest.get("bundleVersion").getAsString());
for (final Class<?> plugin : plugins) {
boolean launch = true;
List<Throwable> errors = Lists.newArrayListWithCapacity(0);
// actually be launched
if (type.mightRequireHooks()) {
try {
Class contextClass = loader.loadClass(PluginContext.class.getName());
Constructor contextConstructor = contextClass.getDeclaredConstructor(Path.class, String.class, String.class);
contextConstructor.setAccessible(true);
String concourseVersion = Versions.parseSemanticVersion(com.cinchapi.concourse.util.Version.getVersion(ConcourseServer.class).toString()).toString();
Object context = contextConstructor.newInstance(home, version.toString(), concourseVersion);
Class iface;
switch(type) {
case INSTALL:
default:
iface = loader.loadClass(AfterInstallHook.class.getName());
break;
}
Set<Class<?>> potential = reflection.getSubTypesOf(iface);
Iterable<Class<?>> hooks = potential.stream().filter((hook) -> !hook.isInterface() && !Modifier.isAbstract(hook.getModifiers()))::iterator;
for (Class<?> hook : hooks) {
Logger.info("Running hook '{}' for plugin '{}'", hook.getName(), plugin);
Object instance = Reflection.newInstance(hook);
Reflection.call(instance, "run", context);
}
} catch (Exception e) {
Throwable error = Throwables.getRootCause(e);
Logger.error("Could not run {} hook for {}:", type, plugin, error);
launch = false;
errors.add(error);
}
}
if (launch && errors.isEmpty()) {
launch(bundle, prefs, plugin, classpath);
startEventLoop(plugin.getName());
if (realTimeParent.isAssignableFrom(plugin)) {
startStreamToPlugin(plugin.getName());
}
} else {
// to consequences.
if (type == ActivationType.INSTALL) {
Logger.error("Errors occurred when trying to " + "install {}: {}", bundle, errors);
throw new PluginInstallException("Could not install " + bundle + " due to the following errors: " + errors);
} else {
Logger.error("An error occurred when trying to " + "activate {}", bundle);
// TODO: call deactivate(bundle) whenever that method is
// ready
}
break;
}
}
bundles.put(bundle, version);
} catch (IOException | ClassNotFoundException e) {
Logger.error("An error occurred while trying to activate the plugin bundle '{}'", bundle, e);
throw CheckedExceptions.wrapAsRuntimeException(e);
}
}
Aggregations