Search in sources :

Example 1 with JavaApp

use of com.cinchapi.concourse.server.io.process.JavaApp in project concourse by cinchapi.

the class PluginManager method stop.

/**
 * Stop the plugin manager and shutdown any managed plugins that are
 * running.
 */
public void stop() {
    streamLoop.interrupt();
    executor.shutdownNow();
    for (String id : registry.rowKeySet()) {
        JavaApp app = (JavaApp) registry.get(id, RegistryData.APP_INSTANCE);
        app.destroy();
    }
    registry.clear();
    running = false;
}
Also used : JavaApp(com.cinchapi.concourse.server.io.process.JavaApp)

Example 2 with JavaApp

use of com.cinchapi.concourse.server.io.process.JavaApp in project concourse by cinchapi.

the class PluginManager method runningPlugins.

/**
 * Return information about the running plugins as a mapping from each PID
 * to another mapping that contains key/value pairs with information about
 * the plugin.
 *
 * @return information about the running plugins
 */
public Map<Long, Map<String, String>> runningPlugins() {
    Map<Long, Map<String, String>> info = Maps.newLinkedHashMap();
    registry.rowMap().forEach((plugin, data) -> {
        PluginStatus status = (PluginStatus) data.get(RegistryData.STATUS);
        if (status == PluginStatus.ACTIVE) {
            JavaApp app = (JavaApp) data.get(RegistryData.APP_INSTANCE);
            long pid = app.pid();
            String bundle = (String) data.get(RegistryData.PLUGIN_BUNDLE);
            Map<String, String> attrs = Maps.newHashMap();
            attrs.put("name", plugin);
            attrs.put("bundle", bundle);
            info.put(pid, attrs);
        }
    });
    return info;
}
Also used : JavaApp(com.cinchapi.concourse.server.io.process.JavaApp) Map(java.util.Map) ConcurrentMap(java.util.concurrent.ConcurrentMap)

Example 3 with JavaApp

use of com.cinchapi.concourse.server.io.process.JavaApp in project concourse by cinchapi.

the class PluginManager method launch.

/**
 * <p>
 * This method is called from {@link #activate(String, ActivationType)} once
 * any pre-launch checks have successfully completed.
 * </p>
 * <p>
 * Launch the {@code plugin} from {@code dist} within a separate JVM
 * configured with the specified {@code classpath} and the values from the
 * {@code prefs} file.
 * </p>
 *
 * @param bundle the bundle directory that contains the plugin libraries
 * @param prefs the {@link Path} to the config file
 * @param plugin the class to launch in a separate JVM
 * @param classpath the classpath for the separate JVM
 */
private void launch(final String bundle, final Path prefs, final Class<?> plugin, final List<String> classpath) {
    // Write an arbitrary main class that'll construct the Plugin and run it
    String launchClass = plugin.getName();
    String launchClassShort = plugin.getSimpleName();
    String processName = "Concourse_" + launchClassShort;
    String tempDir = getPluginTempDirectory(launchClass);
    String fromServer = FileSystem.tempFile(tempDir, "FS-", ".shm");
    String fromPlugin = FileSystem.tempFile(tempDir, "FP-", ".shm");
    String source = pluginLaunchClassTemplate.replace("INSERT_PROCESS_NAME", processName).replace("INSERT_IMPORT_STATEMENT", launchClass).replace("INSERT_FROM_SERVER", fromServer).replace("INSERT_FROM_PLUGIN", fromPlugin).replace("INSERT_CLASS_NAME", launchClassShort);
    // Create an external JavaApp in which the Plugin will run. Get the
    // plugin config to size the JVM properly.
    PluginConfiguration config = Reflection.newInstance(StandardPluginConfiguration.class, prefs);
    Logger.info("Configuring plugin '{}' from bundle '{}' with " + "preferences located in {}", plugin, bundle, prefs);
    long heapSize = config.getHeapSize() / BYTES_PER_MB;
    for (String alias : config.getAliases()) {
        if (!aliases.containsKey(alias) && !ambiguous.contains(alias)) {
            aliases.put(alias, plugin.getName());
            Logger.info("Registering '{}' as an alias for {}", alias, plugin);
        } else {
            aliases.remove(alias);
            ambiguous.add(alias);
            Logger.info("Alias '{}' can't be used because it is " + "associated with multiple plugins", alias);
        }
    }
    String pluginHome = home + File.separator + bundle;
    String serviceToken = BaseEncoding.base32Hex().encode(server.newServiceToken().bufferForData().array());
    ArrayList<String> options = new ArrayList<String>();
    if (config.getRemoteDebuggerEnabled()) {
        options.add("-Xdebug");
        options.add("-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=" + config.getRemoteDebuggerPort());
    }
    options.add("-Xms" + heapSize + "M");
    options.add("-Xmx" + heapSize + "M");
    options.add("-D" + Plugin.PLUGIN_HOME_JVM_PROPERTY + "=" + pluginHome);
    options.add("-D" + Plugin.PLUGIN_SERVICE_TOKEN_JVM_PROPERTY + "=" + serviceToken);
    String cp = StringUtils.join(classpath, JavaApp.CLASSPATH_SEPARATOR);
    JavaApp app = new JavaApp(cp, source, options);
    app.run();
    if (app.isRunning()) {
        Logger.info("Starting plugin '{}' from bundle '{}'", launchClass, bundle);
    }
    app.onPrematureShutdown((out, err) -> {
        try {
            List<String> outLines = CharStreams.readLines(new InputStreamReader(out));
            List<String> errLines = CharStreams.readLines(new InputStreamReader(err));
            Logger.warn("Plugin '{}' unexpectedly crashed. ", plugin);
            Logger.warn("Standard Output for {}: {}", plugin, StringUtils.join(outLines, System.lineSeparator()));
            Logger.warn("Standard Error for {}: {}", plugin, StringUtils.join(errLines, System.lineSeparator()));
            Logger.warn("Restarting {} now...", plugin);
            Iterator<Entry<String, String>> it = aliases.entrySet().iterator();
            while (it.hasNext()) {
                Entry<String, String> entry = it.next();
                if (entry.getValue().equals(plugin.getName())) {
                    it.remove();
                }
            }
            // TODO: it would be nice to just restart the same JavaApp
            // instance (e.g. app.restart();)
            launch(bundle, prefs, plugin, classpath);
        } catch (IOException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e);
        }
    });
    // Ensure that the Plugin is ready to run before adding it to the
    // registry to avoid premature invocations
    Path readyCheck = com.cinchapi.common.io.Files.getHashedFilePath(serviceToken);
    try {
        while (!Files.deleteIfExists(readyCheck)) {
            Thread.sleep(1000);
            continue;
        }
        Logger.info("Plugin '{}' is ready", plugin);
    } catch (IOException | InterruptedException e) {
    }
    // Store metadata about the Plugin
    String id = launchClass;
    registry.put(id, RegistryData.PLUGIN_BUNDLE, bundle);
    registry.put(id, RegistryData.FROM_SERVER, new MessageQueue(fromServer));
    registry.put(id, RegistryData.FROM_PLUGIN, new MessageQueue(fromPlugin));
    registry.put(id, RegistryData.STATUS, PluginStatus.ACTIVE);
    registry.put(id, RegistryData.APP_INSTANCE, app);
    registry.put(id, RegistryData.FROM_PLUGIN_RESPONSES, Maps.<AccessToken, RemoteMethodResponse>newConcurrentMap());
    Logger.debug("Shared memory for server-based communication to '{} is " + "located at '{}", id, fromServer);
    Logger.debug("Shared memory for plugin-based communication from '{} is " + "located at '{}", id, fromPlugin);
}
Also used : JavaApp(com.cinchapi.concourse.server.io.process.JavaApp) Path(java.nio.file.Path) InputStreamReader(java.io.InputStreamReader) ArrayList(java.util.ArrayList) IOException(java.io.IOException) Entry(java.util.Map.Entry) MessageQueue(com.cinchapi.concourse.server.plugin.io.MessageQueue)

Aggregations

JavaApp (com.cinchapi.concourse.server.io.process.JavaApp)3 MessageQueue (com.cinchapi.concourse.server.plugin.io.MessageQueue)1 IOException (java.io.IOException)1 InputStreamReader (java.io.InputStreamReader)1 Path (java.nio.file.Path)1 ArrayList (java.util.ArrayList)1 Map (java.util.Map)1 Entry (java.util.Map.Entry)1 ConcurrentMap (java.util.concurrent.ConcurrentMap)1