diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java index 68b0dde82..ad81fdd2b 100644 --- a/core/java/src/net/i2p/I2PAppContext.java +++ b/core/java/src/net/i2p/I2PAppContext.java @@ -8,6 +8,7 @@ import java.util.Random; import java.util.Set; import net.i2p.app.ClientAppManager; +import net.i2p.app.ClientAppManagerImpl; import net.i2p.client.naming.NamingService; import net.i2p.crypto.AESEngine; import net.i2p.crypto.CryptixAESEngine; @@ -116,6 +117,7 @@ public class I2PAppContext { private final File _appDir; private volatile File _tmpDir; private final Random _tmpDirRand = new Random(); + private final ClientAppManager _appManager; // split up big lock on this to avoid deadlocks private final Object _lock1 = new Object(), _lock2 = new Object(), _lock3 = new Object(), _lock4 = new Object(), _lock5 = new Object(), _lock6 = new Object(), _lock7 = new Object(), _lock8 = new Object(), @@ -198,6 +200,7 @@ public class I2PAppContext { _overrideProps.putAll(envProps); _shutdownTasks = new ConcurrentHashSet(32); _portMapper = new PortMapper(this); + _appManager = isRouterContext() ? null : new ClientAppManagerImpl(this); /* * Directories. These are all set at instantiation and will not be changed by @@ -1007,8 +1010,11 @@ public class I2PAppContext { } /** - * The RouterAppManager in RouterContext, null always in I2PAppContext - * @return null always + * As of 0.9.30, returns non-null in I2PAppContext, null in RouterContext. + * Prior to that, returned null always. + * Overridden in RouterContext to return the RouterAppManager. + * + * @return As of 0.9.30, returns non-null in I2PAppContext, null in RouterContext * @since 0.9.11, in RouterContext since 0.9.4 */ public ClientAppManager clientAppManager() { diff --git a/core/java/src/net/i2p/app/ClientAppManagerImpl.java b/core/java/src/net/i2p/app/ClientAppManagerImpl.java new file mode 100644 index 000000000..1c7342c42 --- /dev/null +++ b/core/java/src/net/i2p/app/ClientAppManagerImpl.java @@ -0,0 +1,67 @@ +package net.i2p.app; + +import java.util.concurrent.ConcurrentHashMap; + +import net.i2p.I2PAppContext; + +/** + * A simple ClientAppManager that supports register/unregister only, + * so that client apps may find each other in AppContext. + * See RouterAppManager for the real thing in RouterContext. + * + * @since 0.9.30 + */ +public class ClientAppManagerImpl implements ClientAppManager { + + // registered name to client + protected final ConcurrentHashMap _registered; + + public ClientAppManagerImpl(I2PAppContext ctx) { + _registered = new ConcurrentHashMap(8); + } + + /** + * Does nothing. + * + * @param app non-null + * @param state non-null + * @param message may be null + * @param e may be null + */ + public void notify(ClientApp app, ClientAppState state, String message, Exception e) {} + + /** + * Register with the manager under the given name, + * so that other clients may find it. + * Only required for apps used by other apps. + * + * @param app non-null + * @return true if successful, false if duplicate name + */ + public boolean register(ClientApp app) { + return _registered.putIfAbsent(app.getName(), app) == null; + } + + /** + * Unregister with the manager. Name must be the same as that from register(). + * Only required for apps used by other apps. + * + * @param app non-null + */ + public void unregister(ClientApp app) { + _registered.remove(app.getName(), app); + } + + /** + * Get a registered app. + * Only used for apps finding other apps. + * Do not hold a static reference. + * If you only need to find a port, use the PortMapper instead. + * + * @param name non-null + * @return client app or null + */ + public ClientApp getRegisteredApp(String name) { + return _registered.get(name); + } +} diff --git a/router/java/src/net/i2p/router/startup/RouterAppManager.java b/router/java/src/net/i2p/router/startup/RouterAppManager.java index 9f8dc4077..4449b5a6f 100644 --- a/router/java/src/net/i2p/router/startup/RouterAppManager.java +++ b/router/java/src/net/i2p/router/startup/RouterAppManager.java @@ -22,21 +22,19 @@ import net.i2p.util.Log; * * @since 0.9.4 */ -public class RouterAppManager implements ClientAppManager { +public class RouterAppManager extends ClientAppManagerImpl { private final RouterContext _context; private final Log _log; // client to args // this assumes clients do not override equals() private final ConcurrentHashMap _clients; - // registered name to client - private final ConcurrentHashMap _registered; public RouterAppManager(RouterContext ctx) { + super(ctx); _context = ctx; _log = ctx.logManager().getLog(RouterAppManager.class); _clients = new ConcurrentHashMap(16); - _registered = new ConcurrentHashMap(8); ctx.addShutdownTask(new Shutdown()); } @@ -91,6 +89,7 @@ public class RouterAppManager implements ClientAppManager { * @param message may be null * @param e may be null */ + @Override public void notify(ClientApp app, ClientAppState state, String message, Exception e) { switch(state) { case UNINITIALIZED: @@ -137,6 +136,7 @@ public class RouterAppManager implements ClientAppManager { * @param app non-null * @return true if successful, false if duplicate name */ + @Override public boolean register(ClientApp app) { if (!_clients.containsKey(app)) { // Allow registration even if we didn't start it, @@ -148,32 +148,9 @@ public class RouterAppManager implements ClientAppManager { if (_log.shouldLog(Log.INFO)) _log.info("Client " + app.getDisplayName() + " REGISTERED AS " + app.getName()); // TODO if old app in there is not running and != this app, allow replacement - return _registered.putIfAbsent(app.getName(), app) == null; + return super.register(app); } - /** - * Unregister with the manager. Name must be the same as that from register(). - * Only required for apps used by other apps. - * - * @param app non-null - */ - public void unregister(ClientApp app) { - _registered.remove(app.getName(), app); - } - - /** - * Get a registered app. - * Only used for apps finding other apps. - * Do not hold a static reference. - * If you only need to find a port, use the PortMapper instead. - * - * @param name non-null - * @return client app or null - */ - public ClientApp getRegisteredApp(String name) { - return _registered.get(name); - } - /// end ClientAppManager interface /**