diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java index 1f433b60f..a496cd399 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java @@ -1,6 +1,7 @@ package net.i2p.router.web; import java.io.File; +import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -69,9 +70,11 @@ public class ConfigClientsHandler extends FormHandler { } else { try { PluginStarter.stopPlugin(_context, app); - } catch (Exception e) {} - PluginStarter.deletePlugin(_context, app); - addFormNotice(_("Deleted plugin {0}", app)); + PluginStarter.deletePlugin(_context, app); + addFormNotice(_("Deleted plugin {0}", app)); + } catch (IOException e) { + addFormError(_("Error deleting plugin {0}", app) + ": " + e); + } } return; } @@ -81,7 +84,7 @@ public class ConfigClientsHandler extends FormHandler { String app = _action.substring(5); try { PluginStarter.stopPlugin(_context, app); - } catch (Exception e) {} + } catch (IOException e) {} addFormNotice(_("Stopped plugin {0}", app)); return; } 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 5b92ec0c3..c6dd398cb 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java @@ -77,6 +77,7 @@ public class PluginStarter implements Runnable { log.error("Cannot start nonexistent plugin: " + appName); return false; } + //log.error("Starting plugin: " + appName); // load and start things in clients.config File clientConfig = new File(pluginDir, "clients.config"); @@ -84,7 +85,7 @@ public class PluginStarter implements Runnable { Properties props = new Properties(); DataHelper.loadProps(props, clientConfig); List clients = ClientAppConfig.getClientApps(clientConfig); - runClientApps(ctx, pluginDir, clients, true); + runClientApps(ctx, pluginDir, clients, "start"); } // start console webapps in console/webapps @@ -98,6 +99,7 @@ public class PluginStarter implements Runnable { for (int i = 0; i < fileNames.length; i++) { try { String warName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war")); + //log.error("Found webapp: " + warName); // check for duplicates in $I2P // easy way for now... if (warName.equals("i2psnark") || warName.equals("susidns") || warName.equals("i2ptunnel") || @@ -107,6 +109,7 @@ public class PluginStarter implements Runnable { } String enabled = props.getProperty(PREFIX + warName + ENABLED); if (! "false".equals(enabled)) { + //log.error("Starting webapp: " + warName); String path = new File(webappDir, fileNames[i]).getCanonicalPath(); WebAppStarter.startWebApp(ctx, server, warName, path); } @@ -157,7 +160,7 @@ public class PluginStarter implements Runnable { } /** @return true on success */ - static boolean stopPlugin(RouterContext ctx, String appName) throws Exception { + static boolean stopPlugin(RouterContext ctx, String appName) throws IOException { Log log = ctx.logManager().getLog(PluginStarter.class); File pluginDir = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName); if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) { @@ -171,7 +174,7 @@ public class PluginStarter implements Runnable { Properties props = new Properties(); DataHelper.loadProps(props, clientConfig); List clients = ClientAppConfig.getClientApps(clientConfig); - runClientApps(ctx, pluginDir, clients, false); + runClientApps(ctx, pluginDir, clients, "stop"); } // stop console webapps in console/webapps @@ -201,17 +204,26 @@ public class PluginStarter implements Runnable { if (name != null && name.length() > 0) NavHelper.unregisterApp(name); + log.error("Stopping plugin: " + appName); return true; } /** @return true on success - call stopPlugin() first */ - static boolean deletePlugin(RouterContext ctx, String appName) { + static boolean deletePlugin(RouterContext ctx, String appName) throws IOException { 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; } + // uninstall things in clients.config + File clientConfig = new File(pluginDir, "clients.config"); + if (clientConfig.exists()) { + Properties props = new Properties(); + DataHelper.loadProps(props, clientConfig); + List clients = ClientAppConfig.getClientApps(clientConfig); + runClientApps(ctx, pluginDir, clients, "uninstall"); + } FileUtil.rmdir(pluginDir, false); Properties props = pluginProperties(); for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) { @@ -313,20 +325,28 @@ public class PluginStarter implements Runnable { return null; } - /** @param start true=start, false=stop */ - private static void runClientApps(RouterContext ctx, File pluginDir, List apps, boolean start) { + /** @param action "start" or "stop" or "uninstall" */ + private static void runClientApps(RouterContext ctx, File pluginDir, List apps, String action) { Log log = ctx.logManager().getLog(PluginStarter.class); for(ClientAppConfig app : apps) { - if (start && app.disabled) + if (action.equals("start") && app.disabled) continue; String argVal[]; - if (start) { + if (action.equals("start")) { + // start argVal = LoadClientAppsJob.parseArgs(app.args); } else { - // stopargs must be present - if (app.stopargs == null || app.stopargs.length() <= 0) + String args; + if (action.equals("stop")) + args = app.stopargs; + else if (action.equals("uninstall")) + args = app.uninstallargs; + else + throw new IllegalArgumentException("bad action"); + // args must be present + if (args == null || args.length() <= 0) continue; - argVal = LoadClientAppsJob.parseArgs(app.stopargs); + argVal = LoadClientAppsJob.parseArgs(args); } // do this after parsing so we don't need to worry about quoting for (int i = 0; i < argVal.length; i++) { @@ -345,7 +365,7 @@ public class PluginStarter implements Runnable { } addToClasspath(cp, app.clientName, log); } - if (app.delay == 0 || !start) { + if (app.delay == 0 || !action.equals("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 8e0ba021f..903000fbd 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java @@ -308,7 +308,7 @@ public class PluginUpdateHandler extends UpdateHandler { if (!PluginStarter.stopPlugin(_context, appName)) { // failed, ignore } - } catch (Exception e) {} // ignore + } catch (IOException e) {} // ignore } else { if (Boolean.valueOf(props.getProperty("update-only")).booleanValue()) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/WebAppConfiguration.java b/apps/routerconsole/java/src/net/i2p/router/web/WebAppConfiguration.java index d903d83ca..121145bf3 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/WebAppConfiguration.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/WebAppConfiguration.java @@ -53,8 +53,10 @@ public class WebAppConfiguration implements WebApplicationContext.Configuration I2PAppContext i2pContext = I2PAppContext.getGlobalContext(); File libDir = new File(i2pContext.getBaseDir(), "lib"); - File pluginLibDir = new File(i2pContext.getAppDir(), - PluginUpdateHandler.PLUGIN_DIR + ctxPath + '/' + "lib"); + // FIXME this only works if war is the same name as the plugin + File pluginDir = new File(i2pContext.getAppDir(), + PluginUpdateHandler.PLUGIN_DIR + ctxPath); + File dir = libDir; String cp; if (ctxPath.equals("/susidns")) { @@ -63,10 +65,11 @@ public class WebAppConfiguration implements WebApplicationContext.Configuration } else if (ctxPath.equals("/i2psnark")) { // duplicate classes removed from the .war in 0.7.12 cp = "i2psnark.jar"; - } else if (pluginLibDir.exists()) { - Properties props = RouterConsoleRunner.webAppProperties(pluginLibDir.getAbsolutePath()); + } else if (pluginDir.exists()) { + File consoleDir = new File(pluginDir, "console"); + Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath()); cp = props.getProperty(RouterConsoleRunner.PREFIX + appName + CLASSPATH); - dir = pluginLibDir; + dir = pluginDir; } else { Properties props = RouterConsoleRunner.webAppProperties(); cp = props.getProperty(RouterConsoleRunner.PREFIX + appName + CLASSPATH); @@ -79,6 +82,8 @@ public class WebAppConfiguration implements WebApplicationContext.Configuration String path; if (elem.startsWith("$I2P")) path = i2pContext.getBaseDir().getAbsolutePath() + '/' + elem.substring(4); + else if (elem.startsWith("$PLUGIN")) + path = dir.getAbsolutePath() + '/' + elem.substring(7); else path = dir.getAbsolutePath() + '/' + elem; System.err.println("Adding " + path + " to classpath for " + appName); diff --git a/router/java/src/net/i2p/router/startup/ClientAppConfig.java b/router/java/src/net/i2p/router/startup/ClientAppConfig.java index 3d57699a3..4c5125bc2 100644 --- a/router/java/src/net/i2p/router/startup/ClientAppConfig.java +++ b/router/java/src/net/i2p/router/startup/ClientAppConfig.java @@ -37,6 +37,8 @@ public class ClientAppConfig { public String classpath; /** @since 0.7.12 */ public String stopargs; + /** @since 0.7.12 */ + public String uninstallargs; public ClientAppConfig(String cl, String client, String a, long d, boolean dis) { className = cl; @@ -47,10 +49,11 @@ public class ClientAppConfig { } /** @since 0.7.12 */ - public ClientAppConfig(String cl, String client, String a, long d, boolean dis, String cp, String sa) { + public ClientAppConfig(String cl, String client, String a, long d, boolean dis, String cp, String sa, String ua) { this(cl, client, a, d, dis); classpath = cp; stopargs = sa; + uninstallargs = ua; } public static File configFile(I2PAppContext ctx) { @@ -118,6 +121,7 @@ public class ClientAppConfig { String disabled = clientApps.getProperty(PREFIX + i + ".startOnLoad"); String classpath = clientApps.getProperty(PREFIX + i + ".classpath"); String stopargs = clientApps.getProperty(PREFIX + i + ".stopargs"); + String uninstallargs = clientApps.getProperty(PREFIX + i + ".uninstallargs"); i++; boolean dis = disabled != null && "false".equals(disabled); @@ -129,7 +133,8 @@ 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, stopargs)); + rv.add(new ClientAppConfig(className, clientName, args, delay, dis, + classpath, stopargs, uninstallargs)); } return rv; }