Search in sources :

Example 1 with Reflection

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);
    }
}
Also used : Version(com.github.zafarkhaja.semver.Version) AnyStrings(com.cinchapi.common.base.AnyStrings) JsonObject(com.google.gson.JsonObject) StringUtils(org.apache.commons.lang.StringUtils) URL(java.net.URL) Logger(com.cinchapi.concourse.util.Logger) HashBasedTable(com.google.common.collect.HashBasedTable) Reflections(org.reflections.Reflections) ByteBuffer(java.nio.ByteBuffer) DirectoryStream(java.nio.file.DirectoryStream) MessageQueue(com.cinchapi.concourse.server.plugin.io.MessageQueue) URLClassLoader(java.net.URLClassLoader) Future(java.util.concurrent.Future) Resources(com.cinchapi.concourse.util.Resources) CharStreams(com.google.common.io.CharStreams) Map(java.util.Map) ConcurrentMaps(com.cinchapi.concourse.util.ConcurrentMaps) AccessToken(com.cinchapi.concourse.thrift.AccessToken) Path(java.nio.file.Path) ZipException(java.util.zip.ZipException) FileSystem(com.cinchapi.concourse.server.io.FileSystem) ComplexTObject(com.cinchapi.concourse.thrift.ComplexTObject) Set(java.util.Set) Versions(com.cinchapi.concourse.server.plugin.util.Versions) Executors(java.util.concurrent.Executors) ClasspathHelper(org.reflections.util.ClasspathHelper) Sets(com.google.common.collect.Sets) ConcourseServer(com.cinchapi.concourse.server.ConcourseServer) List(java.util.List) Queues(com.cinchapi.concourse.util.Queues) WriteEvent(com.cinchapi.concourse.server.plugin.data.WriteEvent) Modifier(java.lang.reflect.Modifier) Entry(java.util.Map.Entry) CheckedExceptions(com.cinchapi.common.base.CheckedExceptions) TransactionToken(com.cinchapi.concourse.thrift.TransactionToken) JsonParser(com.google.gson.JsonParser) Constructor(java.lang.reflect.Constructor) ArrayList(java.util.ArrayList) ConcurrentMap(java.util.concurrent.ConcurrentMap) Reflection(com.cinchapi.common.reflect.Reflection) Lists(com.google.common.collect.Lists) BINARY_QUEUE(com.cinchapi.concourse.server.GlobalState.BINARY_QUEUE) ExecutorService(java.util.concurrent.ExecutorService) ConfigurationBuilder(org.reflections.util.ConfigurationBuilder) Time(com.cinchapi.concourse.time.Time) Iterator(java.util.Iterator) AfterInstallHook(com.cinchapi.concourse.server.plugin.hook.AfterInstallHook) Files(java.nio.file.Files) BaseEncoding(com.google.common.io.BaseEncoding) MorePaths(com.cinchapi.concourse.util.MorePaths) ZipFiles(com.cinchapi.concourse.util.ZipFiles) Throwables(com.google.common.base.Throwables) IOException(java.io.IOException) InputStreamReader(java.io.InputStreamReader) Maps(com.google.common.collect.Maps) File(java.io.File) JavaApp(com.cinchapi.concourse.server.io.process.JavaApp) ExecutionException(java.util.concurrent.ExecutionException) InterProcessCommunication(com.cinchapi.concourse.server.plugin.io.InterProcessCommunication) PluginSerializer(com.cinchapi.concourse.server.plugin.io.PluginSerializer) Paths(java.nio.file.Paths) Collections(java.util.Collections) Table(com.google.common.collect.Table) ConfigurationBuilder(org.reflections.util.ConfigurationBuilder) JsonObject(com.google.gson.JsonObject) URL(java.net.URL) ConcourseServer(com.cinchapi.concourse.server.ConcourseServer) Version(com.github.zafarkhaja.semver.Version) Reflections(org.reflections.Reflections) Path(java.nio.file.Path) Constructor(java.lang.reflect.Constructor) IOException(java.io.IOException) ZipException(java.util.zip.ZipException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) URLClassLoader(java.net.URLClassLoader) JsonObject(com.google.gson.JsonObject) ComplexTObject(com.cinchapi.concourse.thrift.ComplexTObject) File(java.io.File)

Aggregations

AnyStrings (com.cinchapi.common.base.AnyStrings)1 CheckedExceptions (com.cinchapi.common.base.CheckedExceptions)1 Reflection (com.cinchapi.common.reflect.Reflection)1 ConcourseServer (com.cinchapi.concourse.server.ConcourseServer)1 BINARY_QUEUE (com.cinchapi.concourse.server.GlobalState.BINARY_QUEUE)1 FileSystem (com.cinchapi.concourse.server.io.FileSystem)1 JavaApp (com.cinchapi.concourse.server.io.process.JavaApp)1 WriteEvent (com.cinchapi.concourse.server.plugin.data.WriteEvent)1 AfterInstallHook (com.cinchapi.concourse.server.plugin.hook.AfterInstallHook)1 InterProcessCommunication (com.cinchapi.concourse.server.plugin.io.InterProcessCommunication)1 MessageQueue (com.cinchapi.concourse.server.plugin.io.MessageQueue)1 PluginSerializer (com.cinchapi.concourse.server.plugin.io.PluginSerializer)1 Versions (com.cinchapi.concourse.server.plugin.util.Versions)1 AccessToken (com.cinchapi.concourse.thrift.AccessToken)1 ComplexTObject (com.cinchapi.concourse.thrift.ComplexTObject)1 TransactionToken (com.cinchapi.concourse.thrift.TransactionToken)1 Time (com.cinchapi.concourse.time.Time)1 ConcurrentMaps (com.cinchapi.concourse.util.ConcurrentMaps)1 Logger (com.cinchapi.concourse.util.Logger)1 MorePaths (com.cinchapi.concourse.util.MorePaths)1