Show the start button when a plugin is not running, and the stop button when a plugin is running.

This commit is contained in:
HungryHobo
2010-04-16 03:58:48 +00:00
parent 10d37a9be5
commit ecbc0a2a2d
6 changed files with 99 additions and 5 deletions

View File

@ -147,9 +147,11 @@ public class ConfigClientsHelper extends HelperBase {
} }
desc.append("</table>"); desc.append("</table>");
boolean enableStop = !Boolean.valueOf(appProps.getProperty("disableStop")).booleanValue(); boolean enableStop = !Boolean.valueOf(appProps.getProperty("disableStop")).booleanValue();
enableStop &= PluginStarter.isPluginRunning(app, _context);
boolean enableStart = !PluginStarter.isPluginRunning(app, _context);
renderForm(buf, app, app, false, renderForm(buf, app, app, false,
"true".equals(val), false, desc.toString(), false, false, "true".equals(val), false, desc.toString(), false, false,
updateURL != null, enableStop, true, true); updateURL != null, enableStop, true, enableStart);
} }
} }
buf.append("</table>\n"); buf.append("</table>\n");

View File

@ -7,18 +7,22 @@ import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.router.Job;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.router.startup.ClientAppConfig; import net.i2p.router.startup.ClientAppConfig;
import net.i2p.router.startup.LoadClientAppsJob; import net.i2p.router.startup.LoadClientAppsJob;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.FileUtil; import net.i2p.util.FileUtil;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.Translate; import net.i2p.util.Translate;
@ -42,6 +46,8 @@ public class PluginStarter implements Runnable {
"susimail", "addressbook", "routerconsole" }; "susimail", "addressbook", "routerconsole" };
private static final String[] STANDARD_THEMES = { "images", "light", "dark", "classic", private static final String[] STANDARD_THEMES = { "images", "light", "dark", "classic",
"midnight" }; "midnight" };
private static Map<String, ThreadGroup> pluginThreadGroups = new ConcurrentHashMap<String, ThreadGroup>(); // one thread group per plugin (map key=plugin name)
private static Map<String, Collection<Job>> pluginJobs = new ConcurrentHashMap<String, Collection<Job>>();
public PluginStarter(RouterContext ctx) { public PluginStarter(RouterContext ctx) {
_context = ctx; _context = ctx;
@ -362,6 +368,15 @@ public class PluginStarter implements Runnable {
*/ */
private static void runClientApps(RouterContext ctx, File pluginDir, List<ClientAppConfig> apps, String action) throws Exception { 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);
// initialize pluginThreadGroup and pluginJobs
String pluginName = pluginDir.getName();
if (!pluginThreadGroups.containsKey(pluginName))
pluginThreadGroups.put(pluginName, new ThreadGroup(pluginName));
ThreadGroup pluginThreadGroup = pluginThreadGroups.get(pluginName);
if (action.equals("start"))
pluginJobs.put(pluginName, new ConcurrentHashSet<Job>());
for(ClientAppConfig app : apps) { for(ClientAppConfig app : apps) {
if (action.equals("start") && app.disabled) if (action.equals("start") && app.disabled)
continue; continue;
@ -407,16 +422,48 @@ public class PluginStarter implements Runnable {
// quick check, will throw ClassNotFoundException on error // quick check, will throw ClassNotFoundException on error
LoadClientAppsJob.testClient(app.className); 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, pluginThreadGroup);
} else { } else {
// quick check, will throw ClassNotFoundException on error // quick check, will throw ClassNotFoundException on error
LoadClientAppsJob.testClient(app.className); 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)); Job job = new LoadClientAppsJob.DelayedRunClient(ctx, app.className, app.clientName, argVal, app.delay, pluginThreadGroup);
ctx.jobQueue().addJob(job);
pluginJobs.get(pluginName).add(job);
} }
} }
} }
public static boolean isPluginRunning(String pluginName, RouterContext ctx) {
Log log = ctx.logManager().getLog(PluginStarter.class);
boolean isJobRunning = false;
if (pluginJobs.containsKey(pluginName))
for (Job job: pluginJobs.get(pluginName))
if (ctx.jobQueue().isJobActive(job)) {
isJobRunning = true;
break;
}
log.debug("plugin name = <" + pluginName + ">; threads running? " + isClientThreadRunning(pluginName) + "; webapp runing? " + WebAppStarter.isWebAppRunning(pluginName) + "; jobs running? " + isJobRunning);
return isClientThreadRunning(pluginName) || WebAppStarter.isWebAppRunning(pluginName) || isJobRunning;
}
/**
* Returns <code>true</code> if one or more client threads are running in a given plugin.
* @param pluginName
* @return
*/
private static boolean isClientThreadRunning(String pluginName) {
ThreadGroup group = pluginThreadGroups.get(pluginName);
if (group == null)
return false;
Thread[] activeThreads = new Thread[1];
group.enumerate(activeThreads);
return activeThreads[0] != null;
}
/** /**
* Perhaps there's an easy way to use Thread.setContextClassLoader() * Perhaps there's an easy way to use Thread.setContextClassLoader()
* but I don't see how to make it magically get used for everything. * but I don't see how to make it magically get used for everything.

View File

@ -87,6 +87,13 @@ public class WebAppStarter {
} catch (IllegalStateException ise) {} } catch (IllegalStateException ise) {}
} }
static boolean isWebAppRunning(String appName) {
Server server = WebAppStarter.getConsoleServer();
// this will return a new context if one does not exist
HttpContext wac = server.getContext('/' + appName);
return wac.isStarted();
}
/** see comments in ConfigClientsHandler */ /** see comments in ConfigClientsHandler */
static Server getConsoleServer() { static Server getConsoleServer() {
Collection c = Server.getHttpServers(); Collection c = Server.getHttpServers();

View File

@ -55,6 +55,12 @@ public class I2PThread extends Thread {
_createdBy = new Exception("Created by"); _createdBy = new Exception("Created by");
} }
public I2PThread(ThreadGroup g, Runnable r) {
super(g, r);
if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
_createdBy = new Exception("Created by");
}
private void log(int level, String msg) { log(level, msg, null); } private void log(int level, String msg) { log(level, msg, null); }
private void log(int level, String msg, Throwable t) { private void log(int level, String msg, Throwable t) {
// we cant assume log is created // we cant assume log is created

View File

@ -11,6 +11,7 @@ package net.i2p.router;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -192,6 +193,19 @@ public class JobQueue {
} }
} }
/**
* Returns <code>true</code> if a given job is waiting or running;
* <code>false</code> if the job is finished or doesn't exist in the queue.
*/
public boolean isJobActive(Job job) {
if (_readyJobs.contains(job) | _timedJobs.contains(job))
return true;
for (JobQueueRunner runner: _queueRunners.values())
if (runner.getCurrentJob() == job)
return true;
return false;
}
public void timingUpdated() { public void timingUpdated() {
synchronized (_jobLock) { synchronized (_jobLock) {
_jobLock.notifyAll(); _jobLock.notifyAll();

View File

@ -4,6 +4,7 @@ import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch;
import net.i2p.router.JobImpl; import net.i2p.router.JobImpl;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
@ -55,18 +56,24 @@ public class LoadClientAppsJob extends JobImpl {
private String _clientName; private String _clientName;
private String _args[]; private String _args[];
private Log _log; private Log _log;
private ThreadGroup _threadGroup;
public DelayedRunClient(RouterContext enclosingContext, String className, String clientName, String args[], long delay) { public DelayedRunClient(RouterContext enclosingContext, String className, String clientName, String args[], long delay) {
this(enclosingContext, className, clientName, args, delay, null);
}
public DelayedRunClient(RouterContext enclosingContext, String className, String clientName, String args[], long delay, ThreadGroup threadGroup) {
super(enclosingContext); super(enclosingContext);
_className = className; _className = className;
_clientName = clientName; _clientName = clientName;
_args = args; _args = args;
_log = enclosingContext.logManager().getLog(LoadClientAppsJob.class); _log = enclosingContext.logManager().getLog(LoadClientAppsJob.class);
_threadGroup = threadGroup;
getTiming().setStartAfter(getContext().clock().now() + delay); getTiming().setStartAfter(getContext().clock().now() + delay);
} }
public String getName() { return "Delayed client job"; } public String getName() { return "Delayed client job"; }
public void runJob() { public void runJob() {
runClient(_className, _clientName, _args, _log); runClient(_className, _clientName, _args, _log, _threadGroup);
} }
} }
@ -149,9 +156,20 @@ public class LoadClientAppsJob extends JobImpl {
* Run client in a new thread. * 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) {
runClient(className, clientName, args, log, null);
}
/**
* Run client in a new thread.
*/
public static void runClient(String className, String clientName, String args[], Log log, ThreadGroup threadGroup) {
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));
I2PThread t = new I2PThread(new RunApp(className, clientName, args, log)); I2PThread t;
if (threadGroup != null)
t = new I2PThread(threadGroup, new RunApp(className, clientName, args, log));
else
t = new I2PThread(new RunApp(className, clientName, args, log));
if (clientName == null) if (clientName == null)
clientName = className + " client"; clientName = className + " client";
t.setName(clientName); t.setName(clientName);