forked from I2P_Developers/i2p.i2p
* ClientAppManager: Add method to look up clients by class and args
* Console: Implement stopping of clients using the ClientApp interface
(ticket #347)
This commit is contained in:
@@ -18,7 +18,7 @@ public class RouterVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
public final static String VERSION = CoreVersion.VERSION;
|
||||
public final static long BUILD = 4;
|
||||
public final static long BUILD = 5;
|
||||
|
||||
/** for example "-test" */
|
||||
public final static String EXTRA = "";
|
||||
|
||||
@@ -87,8 +87,18 @@ public class LoadClientAppsJob extends JobImpl {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse arg string into an array of args.
|
||||
* Spaces or tabs separate args.
|
||||
* Args may be single- or double-quoted if they contain spaces or tabs.
|
||||
* There is no provision for escaping quotes.
|
||||
* A quoted string may not contain a quote of any kind.
|
||||
*
|
||||
* @param args may be null
|
||||
* @return non-null, 0-length if args is null
|
||||
*/
|
||||
public static String[] parseArgs(String args) {
|
||||
List argList = new ArrayList(4);
|
||||
List<String> argList = new ArrayList(4);
|
||||
if (args != null) {
|
||||
char data[] = args.toCharArray();
|
||||
StringBuilder buf = new StringBuilder(32);
|
||||
@@ -130,8 +140,9 @@ public class LoadClientAppsJob extends JobImpl {
|
||||
}
|
||||
}
|
||||
String rv[] = new String[argList.size()];
|
||||
for (int i = 0; i < argList.size(); i++)
|
||||
rv[i] = (String)argList.get(i);
|
||||
for (int i = 0; i < argList.size(); i++) {
|
||||
rv[i] = argList.get(i);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -151,6 +162,7 @@ public class LoadClientAppsJob extends JobImpl {
|
||||
|
||||
/**
|
||||
* Run client in this thread.
|
||||
* Used for plugin sub-clients only. Does not register with the ClientAppManager.
|
||||
*
|
||||
* @param clientName can be null
|
||||
* @param args can be null
|
||||
@@ -163,6 +175,7 @@ public class LoadClientAppsJob extends JobImpl {
|
||||
|
||||
/**
|
||||
* Run client in this thread.
|
||||
* Used for plugin sub-clients only. Does not register with the ClientAppManager.
|
||||
*
|
||||
* @param clientName can be null
|
||||
* @param args can be null
|
||||
@@ -249,13 +262,13 @@ public class LoadClientAppsJob extends JobImpl {
|
||||
RouterAppManager mgr = _ctx.clientAppManager();
|
||||
Object[] conArgs = new Object[] {_ctx, _ctx.clientAppManager(), _args};
|
||||
RouterApp app = (RouterApp) con.newInstance(conArgs);
|
||||
mgr.addAndStart(app);
|
||||
mgr.addAndStart(app, _args);
|
||||
} else if (isClientApp(cls)) {
|
||||
Constructor con = cls.getConstructor(I2PAppContext.class, ClientAppManager.class, String[].class);
|
||||
RouterAppManager mgr = _ctx.clientAppManager();
|
||||
Object[] conArgs = new Object[] {_ctx, _ctx.clientAppManager(), _args};
|
||||
ClientApp app = (ClientApp) con.newInstance(conArgs);
|
||||
mgr.addAndStart(app);
|
||||
mgr.addAndStart(app, _args);
|
||||
} else {
|
||||
Method method = cls.getMethod("main", new Class[] { String[].class });
|
||||
method.invoke(cls, new Object[] { _args });
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package net.i2p.router.startup;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.i2p.app.*;
|
||||
import static net.i2p.app.ClientAppState.*;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.ConcurrentHashSet;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -19,26 +19,59 @@ public class RouterAppManager implements ClientAppManager {
|
||||
|
||||
private final RouterContext _context;
|
||||
private final Log _log;
|
||||
private final Set<ClientApp> _clients;
|
||||
// client to args
|
||||
// this assumes clients do not override equals()
|
||||
private final ConcurrentHashMap<ClientApp, String[]> _clients;
|
||||
// registered name to client
|
||||
private final ConcurrentHashMap<String, ClientApp> _registered;
|
||||
|
||||
public RouterAppManager(RouterContext ctx) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(RouterAppManager.class);
|
||||
_clients = new ConcurrentHashSet(16);
|
||||
_clients = new ConcurrentHashMap(16);
|
||||
_registered = new ConcurrentHashMap(8);
|
||||
}
|
||||
|
||||
public void addAndStart(ClientApp app) {
|
||||
_clients.add(app);
|
||||
/**
|
||||
* @param args the args that were used to instantiate the app, non-null, may be zero-length
|
||||
* @return success
|
||||
* @throws IllegalArgumentException if already added
|
||||
*/
|
||||
public boolean addAndStart(ClientApp app, String[] args) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Adding and starting " + app + " with class " + app.getClass().getName() + " and args " + Arrays.toString(args));
|
||||
String[] old = _clients.put(app, args);
|
||||
if (old != null)
|
||||
throw new IllegalArgumentException("already added");
|
||||
try {
|
||||
app.startup();
|
||||
return true;
|
||||
} catch (Throwable t) {
|
||||
_clients.remove(app);
|
||||
_log.error("Client " + app + " failed to start", t);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first known ClientApp with this class name and exact arguments.
|
||||
* Caller may then retrieve or control the state of the returned client.
|
||||
* A client will generally be found only if it is running or transitioning;
|
||||
* after it is stopped it will not be tracked by the manager.
|
||||
*
|
||||
* @param args non-null, may be zero-length
|
||||
* @return client app or null
|
||||
* @since 0.9.6
|
||||
*/
|
||||
public ClientApp getClientApp(String className, String[] args) {
|
||||
for (Map.Entry<ClientApp, String[]> e : _clients.entrySet()) {
|
||||
if (e.getKey().getClass().getName().equals(className) &&
|
||||
Arrays.equals(e.getValue(), args))
|
||||
return e.getKey();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ClientAppManager methods
|
||||
|
||||
/**
|
||||
@@ -97,7 +130,7 @@ public class RouterAppManager implements ClientAppManager {
|
||||
* @return true if successful, false if duplicate name
|
||||
*/
|
||||
public boolean register(ClientApp app) {
|
||||
if (!_clients.contains(app))
|
||||
if (!_clients.containsKey(app))
|
||||
return false;
|
||||
// TODO if old app in there is not running and != this app, allow replacement
|
||||
return _registered.putIfAbsent(app.getName(), app) == null;
|
||||
|
||||
Reference in New Issue
Block a user