Show the start button when a plugin is not running, and the stop button when a plugin is running.
This commit is contained in:
@ -147,9 +147,11 @@ public class ConfigClientsHelper extends HelperBase {
|
||||
}
|
||||
desc.append("</table>");
|
||||
boolean enableStop = !Boolean.valueOf(appProps.getProperty("disableStop")).booleanValue();
|
||||
enableStop &= PluginStarter.isPluginRunning(app, _context);
|
||||
boolean enableStart = !PluginStarter.isPluginRunning(app, _context);
|
||||
renderForm(buf, app, app, false,
|
||||
"true".equals(val), false, desc.toString(), false, false,
|
||||
updateURL != null, enableStop, true, true);
|
||||
updateURL != null, enableStop, true, enableStart);
|
||||
}
|
||||
}
|
||||
buf.append("</table>\n");
|
||||
|
@ -7,18 +7,22 @@ import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.Job;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.startup.ClientAppConfig;
|
||||
import net.i2p.router.startup.LoadClientAppsJob;
|
||||
import net.i2p.util.ConcurrentHashSet;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.Translate;
|
||||
@ -42,6 +46,8 @@ public class PluginStarter implements Runnable {
|
||||
"susimail", "addressbook", "routerconsole" };
|
||||
private static final String[] STANDARD_THEMES = { "images", "light", "dark", "classic",
|
||||
"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) {
|
||||
_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 {
|
||||
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) {
|
||||
if (action.equals("start") && app.disabled)
|
||||
continue;
|
||||
@ -407,16 +422,48 @@ public class PluginStarter implements Runnable {
|
||||
// quick check, will throw ClassNotFoundException on error
|
||||
LoadClientAppsJob.testClient(app.className);
|
||||
// run this guy now
|
||||
LoadClientAppsJob.runClient(app.className, app.clientName, argVal, log);
|
||||
LoadClientAppsJob.runClient(app.className, app.clientName, argVal, log, pluginThreadGroup);
|
||||
} else {
|
||||
// quick check, will throw ClassNotFoundException on error
|
||||
LoadClientAppsJob.testClient(app.className);
|
||||
// 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()
|
||||
* but I don't see how to make it magically get used for everything.
|
||||
|
@ -87,6 +87,13 @@ public class WebAppStarter {
|
||||
} 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 */
|
||||
static Server getConsoleServer() {
|
||||
Collection c = Server.getHttpServers();
|
||||
|
@ -55,6 +55,12 @@ public class I2PThread extends Thread {
|
||||
_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, Throwable t) {
|
||||
// we cant assume log is created
|
||||
|
@ -11,6 +11,7 @@ package net.i2p.router;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
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() {
|
||||
synchronized (_jobLock) {
|
||||
_jobLock.notifyAll();
|
||||
|
@ -4,6 +4,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import net.i2p.router.JobImpl;
|
||||
import net.i2p.router.RouterContext;
|
||||
@ -55,18 +56,24 @@ public class LoadClientAppsJob extends JobImpl {
|
||||
private String _clientName;
|
||||
private String _args[];
|
||||
private Log _log;
|
||||
private ThreadGroup _threadGroup;
|
||||
|
||||
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);
|
||||
_className = className;
|
||||
_clientName = clientName;
|
||||
_args = args;
|
||||
_log = enclosingContext.logManager().getLog(LoadClientAppsJob.class);
|
||||
_threadGroup = threadGroup;
|
||||
getTiming().setStartAfter(getContext().clock().now() + delay);
|
||||
}
|
||||
public String getName() { return "Delayed client job"; }
|
||||
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.
|
||||
*/
|
||||
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))
|
||||
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)
|
||||
clientName = className + " client";
|
||||
t.setName(clientName);
|
||||
|
Reference in New Issue
Block a user