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;
}
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;
}
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);
}
Aggregations