diff --git a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java index df777712c2a7f9ba7d6ccd69eb6de7bbbeb85c1c..0bf04dc134dbc38a6f5e321669da6dfcd7dedf45 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java @@ -76,7 +76,7 @@ public class PluginStarter implements Runnable { Properties props = new Properties(); DataHelper.loadProps(props, clientConfig); List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig); - runClientApps(ctx, pluginDir, clients); + runClientApps(ctx, pluginDir, clients, true); } // start console webapps in console/webapps @@ -142,6 +142,37 @@ public class PluginStarter implements Runnable { return true; } + /** @return true on success */ + static boolean stopPlugin(RouterContext ctx, String appName) throws Exception { + Log log = ctx.logManager().getLog(PluginStarter.class); + File pluginDir = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName); + if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) { + log.error("Cannot stop nonexistent plugin: " + appName); + return false; + } + + // stop things in clients.config + File clientConfig = new File(pluginDir, "clients.config"); + if (clientConfig.exists()) { + Properties props = new Properties(); + DataHelper.loadProps(props, clientConfig); + List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig); + runClientApps(ctx, pluginDir, clients, false); + } + + // stop console webapps in console/webapps + + // remove summary bar link + Properties props = pluginProperties(ctx, appName); + String name = props.getProperty("consoleLinkName_" + Messages.getLanguage(ctx)); + if (name == null) + name = props.getProperty("consoleLinkName"); + if (name != null && name.length() > 0) + NavHelper.unregisterApp(name); + + return true; + } + /** plugin.config */ public static Properties pluginProperties(I2PAppContext ctx, String appName) { File cfgFile = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName + '/' + "plugin.config"); @@ -202,12 +233,21 @@ public class PluginStarter implements Runnable { return null; } - private static void runClientApps(RouterContext ctx, File pluginDir, List<ClientAppConfig> apps) { + /** @param start true=start, false=stop */ + private static void runClientApps(RouterContext ctx, File pluginDir, List<ClientAppConfig> apps, boolean start) { Log log = ctx.logManager().getLog(PluginStarter.class); for(ClientAppConfig app : apps) { - if (app.disabled) + if (start && app.disabled) continue; - String argVal[] = LoadClientAppsJob.parseArgs(app.args); + String argVal[]; + if (start) { + argVal = LoadClientAppsJob.parseArgs(app.args); + } else { + // stopargs must be present + if (app.stopargs == null || app.stopargs.length() <= 0) + continue; + argVal = LoadClientAppsJob.parseArgs(app.stopargs); + } // do this after parsing so we don't need to worry about quoting for (int i = 0; i < argVal.length; i++) { if (argVal[i].indexOf("$") >= 0) { @@ -225,7 +265,7 @@ public class PluginStarter implements Runnable { } addToClasspath(cp, app.clientName, log); } - if (app.delay == 0) { + if (app.delay == 0 || !start) { // run this guy now LoadClientAppsJob.runClient(app.className, app.clientName, argVal, log); } else { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java index 7eb343a685fb18aac5dcd4a2bc6ead913997bb7b..c68346b99a8008cd6f2a6ec41fc9bc0a78822940 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java @@ -287,7 +287,12 @@ public class PluginUpdateHandler extends UpdateHandler { return; } - // check if it is running now and stop it? + // check if it is running first? + try { + if (!PluginStarter.stopPlugin(_context, appName)) { + // failed, ignore + } + } catch (Exception e) {} // ignore } else { if (Boolean.valueOf(props.getProperty("update-only")).booleanValue()) { diff --git a/router/java/src/net/i2p/router/startup/ClientAppConfig.java b/router/java/src/net/i2p/router/startup/ClientAppConfig.java index 7afd0fc99237b2de97a22efc916a186b0515c8e4..3d57699a33811db3e9c33aea698b919f347469e3 100644 --- a/router/java/src/net/i2p/router/startup/ClientAppConfig.java +++ b/router/java/src/net/i2p/router/startup/ClientAppConfig.java @@ -35,6 +35,8 @@ public class ClientAppConfig { public boolean disabled; /** @since 0.7.12 */ public String classpath; + /** @since 0.7.12 */ + public String stopargs; public ClientAppConfig(String cl, String client, String a, long d, boolean dis) { className = cl; @@ -45,9 +47,10 @@ public class ClientAppConfig { } /** @since 0.7.12 */ - public ClientAppConfig(String cl, String client, String a, long d, boolean dis, String cp) { + public ClientAppConfig(String cl, String client, String a, long d, boolean dis, String cp, String sa) { this(cl, client, a, d, dis); classpath = cp; + stopargs = sa; } public static File configFile(I2PAppContext ctx) { @@ -114,6 +117,7 @@ public class ClientAppConfig { String onBoot = clientApps.getProperty(PREFIX + i + ".onBoot"); String disabled = clientApps.getProperty(PREFIX + i + ".startOnLoad"); String classpath = clientApps.getProperty(PREFIX + i + ".classpath"); + String stopargs = clientApps.getProperty(PREFIX + i + ".stopargs"); i++; boolean dis = disabled != null && "false".equals(disabled); @@ -125,12 +129,12 @@ public class ClientAppConfig { if (delayStr != null && !onStartup) try { delay = 1000*Integer.parseInt(delayStr); } catch (NumberFormatException nfe) {} - rv.add(new ClientAppConfig(className, clientName, args, delay, dis, classpath)); + rv.add(new ClientAppConfig(className, clientName, args, delay, dis, classpath, stopargs)); } return rv; } - /** classpath not supported */ + /** classpath and stopargs not supported */ public static void writeClientAppConfig(RouterContext ctx, List apps) { File cfgFile = configFile(ctx); FileOutputStream fos = null;