* Clients:

- Negative delay means run immediately and inline
      - Add methods to test class and run inline,
        to propagate errors to the console
      - Add javadoc for clients.config format
      - Use new methods for plugins
This commit is contained in:
zzz
2010-03-15 16:19:19 +00:00
parent c151352910
commit 16a14d4ebd
3 changed files with 92 additions and 7 deletions

View File

@ -180,7 +180,7 @@ public class PluginStarter implements Runnable {
* @return true on success * @return true on success
* @throws just about anything, caller would be wise to catch Throwable * @throws just about anything, caller would be wise to catch Throwable
*/ */
static boolean stopPlugin(RouterContext ctx, String appName) throws IOException { static boolean stopPlugin(RouterContext ctx, String appName) throws Exception {
Log log = ctx.logManager().getLog(PluginStarter.class); Log log = ctx.logManager().getLog(PluginStarter.class);
File pluginDir = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName); File pluginDir = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName);
if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) { if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
@ -228,7 +228,7 @@ public class PluginStarter implements Runnable {
} }
/** @return true on success - caller should call stopPlugin() first */ /** @return true on success - caller should call stopPlugin() first */
static boolean deletePlugin(RouterContext ctx, String appName) throws IOException { static boolean deletePlugin(RouterContext ctx, String appName) throws Exception {
Log log = ctx.logManager().getLog(PluginStarter.class); Log log = ctx.logManager().getLog(PluginStarter.class);
File pluginDir = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName); File pluginDir = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName);
if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) { if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
@ -348,8 +348,12 @@ public class PluginStarter implements Runnable {
} catch (IOException ioe) {} } catch (IOException ioe) {}
} }
/** @param action "start" or "stop" or "uninstall" */ /**
private static void runClientApps(RouterContext ctx, File pluginDir, List<ClientAppConfig> apps, String action) { * @param action "start" or "stop" or "uninstall"
* @throws just about anything if an app has a delay less than zero, caller would be wise to catch Throwable
* If no apps have a delay less than zero, it shouldn't throw anything
*/
private static void runClientApps(RouterContext ctx, File pluginDir, List<ClientAppConfig> apps, String action) throws Exception {
Log log = ctx.logManager().getLog(PluginStarter.class); Log log = ctx.logManager().getLog(PluginStarter.class);
for(ClientAppConfig app : apps) { for(ClientAppConfig app : apps) {
if (action.equals("start") && app.disabled) if (action.equals("start") && app.disabled)
@ -388,10 +392,18 @@ public class PluginStarter implements Runnable {
} }
addToClasspath(cp, app.clientName, log); addToClasspath(cp, app.clientName, log);
} }
if (app.delay == 0 || !action.equals("start")) {
if (app.delay < 0 && action.equals("start")) {
// this will throw exceptions
LoadClientAppsJob.runClientInline(app.className, app.clientName, argVal, log);
} else if (app.delay == 0 || !action.equals("start")) {
// quick check, will throw ClassNotFoundException on error
LoadClientAppsJob.testClient(app.className);
// run this guy now // run this guy now
LoadClientAppsJob.runClient(app.className, app.clientName, argVal, log); LoadClientAppsJob.runClient(app.className, app.clientName, argVal, log);
} else { } else {
// quick check, will throw ClassNotFoundException on error
LoadClientAppsJob.testClient(app.className);
// wait before firing it up // wait before firing it up
ctx.jobQueue().addJob(new LoadClientAppsJob.DelayedRunClient(ctx, app.className, app.clientName, argVal, app.delay)); ctx.jobQueue().addJob(new LoadClientAppsJob.DelayedRunClient(ctx, app.className, app.clientName, argVal, app.delay));
} }

View File

@ -18,6 +18,49 @@ import net.i2p.router.RouterContext;
* so they can be used both by LoadClientAppsJob and by the configuration * so they can be used both by LoadClientAppsJob and by the configuration
* page in the router console. * page in the router console.
* *
* <pre>
*
* clients.config format:
*
* Lines are of the form clientApp.x.prop=val, where x is the app number.
* App numbers MUST start with 0 and be consecutive.
*
* Properties are as follows:
* main: Full class name. Required. The main() method in this
* class will be run.
* name: Name to be displayed on console.
* args: Arguments to the main class, separated by spaces or tabs.
* Arguments containing spaces or tabs may be quoted with ' or "
* delay: Seconds before starting, default 120
* onBoot: {true|false}, default false, forces a delay of 0,
* overrides delay setting
* startOnLoad: {true|false} Is the client to be run at all?
* Default true
*
* The following additional properties are used only by plugins:
* stopargs: Arguments to stop the client.
* uninstallargs: Arguments to stop the client.
* classpath: Additional classpath elements for the client,
* separated by commas.
*
* The following substitutions are made in the args, stopargs,
* uninstallargs, and classpath lines, for plugins only:
* $I2P: The base I2P install directory
* $CONFIG: The user's configuration directory (e.g. ~/.i2p)
* $PLUGIN: This plugin's directory (e.g. ~/.i2p/plugins/foo)
*
* All properties except "main" are optional.
* Lines starting with "#" are comments.
*
* If the delay is less than zero, the client is run immediately,
* in the same thread, so that exceptions may be propagated to the console.
* In this case, the client should either throw an exception, return quickly,
* or spawn its own thread.
* If the delay is greater than or equal to zero, it will be run
* in a new thread, and exceptions will be logged but not propagated
* to the console.
*
* </pre>
*/ */
public class ClientAppConfig { public class ClientAppConfig {
/** wait 2 minutes before starting up client apps */ /** wait 2 minutes before starting up client apps */

View File

@ -11,7 +11,7 @@ import net.i2p.util.I2PThread;
import net.i2p.util.Log; import net.i2p.util.Log;
/** /**
* Run any client applications specified in the router.config. If any clientApp * Run any client applications specified in clients.config. If any clientApp
* contains the config property ".onBoot=true" it'll be launched immediately, otherwise * contains the config property ".onBoot=true" it'll be launched immediately, otherwise
* it'll get queued up for starting 2 minutes later. * it'll get queued up for starting 2 minutes later.
* *
@ -40,7 +40,7 @@ public class LoadClientAppsJob extends JobImpl {
if (app.disabled) if (app.disabled)
continue; continue;
String argVal[] = parseArgs(app.args); String argVal[] = parseArgs(app.args);
if (app.delay == 0) { if (app.delay <= 0) {
// run this guy now // run this guy now
runClient(app.className, app.clientName, argVal, _log); runClient(app.className, app.clientName, argVal, _log);
} else { } else {
@ -118,6 +118,36 @@ public class LoadClientAppsJob extends JobImpl {
return rv; return rv;
} }
/**
* Use to test if the class is present,
* to propagate an error back to the user,
* since runClient() runs in a separate thread.
*
* @since 0.7.13
*/
public static void testClient(String className) throws ClassNotFoundException {
Class.forName(className);
}
/**
* Run client in this thread.
*
* @throws just about anything, caller would be wise to catch Throwable
* @since 0.7.13
*/
public static void runClientInline(String className, String clientName, String args[], Log log) throws Exception {
if (log.shouldLog(Log.INFO))
log.info("Loading up the client application " + clientName + ": " + className + " " + Arrays.toString(args));
if (args == null)
args = new String[0];
Class cls = Class.forName(className);
Method method = cls.getMethod("main", new Class[] { String[].class });
method.invoke(cls, new Object[] { args });
}
/**
* Run client in a new thread.
*/
public static void runClient(String className, String clientName, String args[], Log log) { public static void runClient(String className, String clientName, String args[], Log log) {
if (log.shouldLog(Log.INFO)) if (log.shouldLog(Log.INFO))
log.info("Loading up the client application " + clientName + ": " + className + " " + Arrays.toString(args)); log.info("Loading up the client application " + clientName + ": " + className + " " + Arrays.toString(args));