forked from I2P_Developers/i2p.i2p
Console: Fix stopping webapps at shutdown (ticket #2508)
RouterAppManager log tweaks
This commit is contained in:
@ -17,6 +17,8 @@ import java.util.Properties;
|
|||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
|
||||||
import net.i2p.CoreVersion;
|
import net.i2p.CoreVersion;
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.app.ClientApp;
|
import net.i2p.app.ClientApp;
|
||||||
@ -541,12 +543,24 @@ public class PluginStarter implements Runnable {
|
|||||||
* @throws Exception just about anything, caller would be wise to catch Throwable
|
* @throws Exception just about anything, caller would be wise to catch Throwable
|
||||||
*/
|
*/
|
||||||
public static boolean stopPlugin(RouterContext ctx, String appName) throws Exception {
|
public static boolean stopPlugin(RouterContext ctx, String appName) throws Exception {
|
||||||
|
Server s = RouterConsoleRunner.getConsoleServer(ctx);
|
||||||
|
return stopPlugin(ctx, s, appName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true on success
|
||||||
|
* @throws Exception just about anything, caller would be wise to catch Throwable
|
||||||
|
* @since 0.9.41
|
||||||
|
*/
|
||||||
|
protected static boolean stopPlugin(RouterContext ctx, Server s, String appName) throws Exception {
|
||||||
Log log = ctx.logManager().getLog(PluginStarter.class);
|
Log log = ctx.logManager().getLog(PluginStarter.class);
|
||||||
File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName);
|
File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName);
|
||||||
if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
|
if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
|
||||||
log.error("Cannot stop nonexistent plugin: " + appName);
|
log.error("Cannot stop nonexistent plugin: " + appName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (log.shouldLog(Log.WARN))
|
||||||
|
log.warn("Stopping plugin: " + appName);
|
||||||
|
|
||||||
// stop things in clients.config
|
// stop things in clients.config
|
||||||
File clientConfig = new File(pluginDir, "clients.config");
|
File clientConfig = new File(pluginDir, "clients.config");
|
||||||
@ -575,13 +589,16 @@ public class PluginStarter implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if(pluginWars.containsKey(appName)) {
|
if (s != null) {
|
||||||
Iterator <String> wars = pluginWars.get(appName).iterator();
|
Collection<String> wars = pluginWars.get(appName);
|
||||||
while (wars.hasNext()) {
|
if (wars != null) {
|
||||||
String warName = wars.next();
|
for (String warName : wars) {
|
||||||
WebAppStarter.stopWebApp(ctx, warName);
|
if (log.shouldInfo())
|
||||||
|
log.info("Stopping webapp " + warName + " in plugin " + appName);
|
||||||
|
WebAppStarter.stopWebApp(ctx, s, warName);
|
||||||
|
}
|
||||||
|
wars.clear();
|
||||||
}
|
}
|
||||||
pluginWars.get(appName).clear();
|
|
||||||
}
|
}
|
||||||
//}
|
//}
|
||||||
|
|
||||||
@ -593,8 +610,6 @@ public class PluginStarter implements Runnable {
|
|||||||
if (name != null && name.length() > 0)
|
if (name != null && name.length() > 0)
|
||||||
NavHelper.unregisterApp(name);
|
NavHelper.unregisterApp(name);
|
||||||
|
|
||||||
if (log.shouldLog(Log.WARN))
|
|
||||||
log.warn("Stopping plugin: " + appName);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -947,6 +962,14 @@ public class PluginStarter implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isPluginRunning(String pluginName, RouterContext ctx) {
|
public static boolean isPluginRunning(String pluginName, RouterContext ctx) {
|
||||||
|
Server s = RouterConsoleRunner.getConsoleServer(ctx);
|
||||||
|
return isPluginRunning(pluginName, ctx, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 0.9.41
|
||||||
|
*/
|
||||||
|
protected static boolean isPluginRunning(String pluginName, RouterContext ctx, Server s) {
|
||||||
Log log = ctx.logManager().getLog(PluginStarter.class);
|
Log log = ctx.logManager().getLog(PluginStarter.class);
|
||||||
|
|
||||||
boolean isJobRunning = false;
|
boolean isJobRunning = false;
|
||||||
@ -955,13 +978,16 @@ public class PluginStarter implements Runnable {
|
|||||||
// TODO have a pending indication too
|
// TODO have a pending indication too
|
||||||
isJobRunning = true;
|
isJobRunning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isWarRunning = false;
|
boolean isWarRunning = false;
|
||||||
if(pluginWars.containsKey(pluginName)) {
|
if (s != null) {
|
||||||
Iterator <String> it = pluginWars.get(pluginName).iterator();
|
Collection<String> wars = pluginWars.get(pluginName);
|
||||||
while(it.hasNext() && !isWarRunning) {
|
if (wars != null) {
|
||||||
String warName = it.next();
|
for (String warName : wars) {
|
||||||
if(WebAppStarter.isWebAppRunning(ctx, warName)) {
|
if (WebAppStarter.isWebAppRunning(s, warName)) {
|
||||||
isWarRunning = true;
|
isWarRunning = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,9 @@ package net.i2p.router.web;
|
|||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
@ -11,15 +14,18 @@ import net.i2p.util.Log;
|
|||||||
* @since 0.7.13
|
* @since 0.7.13
|
||||||
* @author zzz
|
* @author zzz
|
||||||
*/
|
*/
|
||||||
public class PluginStopper extends PluginStarter {
|
class PluginStopper extends PluginStarter {
|
||||||
|
|
||||||
public PluginStopper(RouterContext ctx) {
|
private final Server _server;
|
||||||
|
|
||||||
|
public PluginStopper(RouterContext ctx, Server server) {
|
||||||
super(ctx);
|
super(ctx);
|
||||||
|
_server = server;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
stopPlugins(_context);
|
stopPlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,18 +33,23 @@ public class PluginStopper extends PluginStarter {
|
|||||||
*
|
*
|
||||||
* this shouldn't throw anything
|
* this shouldn't throw anything
|
||||||
*/
|
*/
|
||||||
private static void stopPlugins(RouterContext ctx) {
|
private void stopPlugins() {
|
||||||
Log log = ctx.logManager().getLog(PluginStopper.class);
|
Log log = _context.logManager().getLog(PluginStopper.class);
|
||||||
List<String> pl = getPlugins();
|
List<String> pl = getPlugins();
|
||||||
Collections.reverse(pl); // reverse the order
|
Collections.reverse(pl); // reverse the order
|
||||||
for (String app : pl) {
|
for (String app : pl) {
|
||||||
if (isPluginRunning(app, ctx)) {
|
if (isPluginRunning(app, _context, _server)) {
|
||||||
try {
|
try {
|
||||||
stopPlugin(ctx, app);
|
if (log.shouldInfo())
|
||||||
|
log.info("Stopping plugin: " + app);
|
||||||
|
stopPlugin(_context, _server, app);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
if (log.shouldLog(Log.WARN))
|
if (log.shouldLog(Log.WARN))
|
||||||
log.warn("Failed to stop plugin: " + app, e);
|
log.warn("Failed to stop plugin: " + app, e);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (log.shouldInfo())
|
||||||
|
log.info("Plugin not running: " + app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,9 +239,10 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
public synchronized void shutdown(String[] args) {
|
public synchronized void shutdown(String[] args) {
|
||||||
if (_state == STOPPED)
|
if (_state == STOPPED)
|
||||||
return;
|
return;
|
||||||
|
// this unregisters us with the ClientAppManager
|
||||||
changeState(STOPPING);
|
changeState(STOPPING);
|
||||||
if (PluginStarter.pluginsEnabled(_context))
|
if (PluginStarter.pluginsEnabled(_context))
|
||||||
(new I2PAppThread(new PluginStopper(_context), "PluginStopper")).start();
|
(new I2PAppThread(new PluginStopper(_context, _server), "PluginStopper")).start();
|
||||||
stopAllWebApps();
|
stopAllWebApps();
|
||||||
try {
|
try {
|
||||||
_server.stop();
|
_server.stop();
|
||||||
@ -293,7 +294,10 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To get to Jetty
|
* To get to Jetty.
|
||||||
|
* Warning, this will NOT work during shutdown, because
|
||||||
|
* changeState(STOPPING) will unregister us first.
|
||||||
|
*
|
||||||
* @return may be null or stopped perhaps
|
* @return may be null or stopped perhaps
|
||||||
* @since 0.9.38
|
* @since 0.9.38
|
||||||
*/
|
*/
|
||||||
@ -1137,6 +1141,9 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
* @since 0.9.30
|
* @since 0.9.30
|
||||||
*/
|
*/
|
||||||
private void stopAllWebApps() {
|
private void stopAllWebApps() {
|
||||||
|
net.i2p.util.Log log = _context.logManager().getLog(RouterConsoleRunner.class);
|
||||||
|
if (log.shouldWarn())
|
||||||
|
log.warn("Stop all webapps");
|
||||||
Properties props = webAppProperties(_context);
|
Properties props = webAppProperties(_context);
|
||||||
Set<String> keys = props.stringPropertyNames();
|
Set<String> keys = props.stringPropertyNames();
|
||||||
for (String name : keys) {
|
for (String name : keys) {
|
||||||
@ -1144,10 +1151,15 @@ public class RouterConsoleRunner implements RouterApp {
|
|||||||
String app = name.substring(PREFIX.length(), name.lastIndexOf(ENABLED));
|
String app = name.substring(PREFIX.length(), name.lastIndexOf(ENABLED));
|
||||||
if (ROUTERCONSOLE.equals(app))
|
if (ROUTERCONSOLE.equals(app))
|
||||||
continue;
|
continue;
|
||||||
if (WebAppStarter.isWebAppRunning(_context, app)) {
|
if (_context.portMapper().isRegistered(app)) {
|
||||||
|
if (log.shouldWarn())
|
||||||
|
log.warn("Stopping " + app);
|
||||||
try {
|
try {
|
||||||
WebAppStarter.stopWebApp(_context, app);
|
WebAppStarter.stopWebApp(_context, _server, app);
|
||||||
} catch (Throwable t) { t.printStackTrace(); }
|
} catch (Throwable t) { t.printStackTrace(); }
|
||||||
|
} else {
|
||||||
|
if (log.shouldWarn())
|
||||||
|
log.info("Not Stoppping, isn't running " + app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,6 +151,10 @@ public class WebAppStarter {
|
|||||||
/**
|
/**
|
||||||
* Stop it and remove the context.
|
* Stop it and remove the context.
|
||||||
* Throws just about anything, caller would be wise to catch Throwable
|
* Throws just about anything, caller would be wise to catch Throwable
|
||||||
|
*
|
||||||
|
* Warning, this will NOT work during shutdown, because
|
||||||
|
* the console is already unregistered.
|
||||||
|
*
|
||||||
* @since public since 0.9.33, was package private
|
* @since public since 0.9.33, was package private
|
||||||
*/
|
*/
|
||||||
public static void stopWebApp(RouterContext ctx, String appName) {
|
public static void stopWebApp(RouterContext ctx, String appName) {
|
||||||
@ -171,10 +175,36 @@ public class WebAppStarter {
|
|||||||
} catch (IllegalStateException ise) {}
|
} catch (IllegalStateException ise) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop it and remove the context.
|
||||||
|
* Throws just about anything, caller would be wise to catch Throwable
|
||||||
|
* @since 0.9.41
|
||||||
|
*/
|
||||||
|
static void stopWebApp(RouterContext ctx, Server s, String appName) {
|
||||||
|
ContextHandlerCollection server = getConsoleServer(s);
|
||||||
|
if (server == null)
|
||||||
|
return;
|
||||||
|
ContextHandler wac = getWebApp(server, appName);
|
||||||
|
if (wac == null)
|
||||||
|
return;
|
||||||
|
ctx.portMapper().unregister(appName);
|
||||||
|
try {
|
||||||
|
// not graceful is default in Jetty 6?
|
||||||
|
wac.stop();
|
||||||
|
} catch (Exception ie) {}
|
||||||
|
try {
|
||||||
|
server.removeHandler(wac);
|
||||||
|
server.mapContexts();
|
||||||
|
} catch (IllegalStateException ise) {}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* As of 0.9.34, the appName will be registered with the PortMapper,
|
* As of 0.9.34, the appName will be registered with the PortMapper,
|
||||||
* and PortMapper.isRegistered() will be more efficient than this.
|
* and PortMapper.isRegistered() will be more efficient than this.
|
||||||
*
|
*
|
||||||
|
* Warning, this will NOT work during shutdown, because
|
||||||
|
* the console is already unregistered.
|
||||||
|
*
|
||||||
* @since public since 0.9.33; was package private
|
* @since public since 0.9.33; was package private
|
||||||
*/
|
*/
|
||||||
public static boolean isWebAppRunning(I2PAppContext ctx, String appName) {
|
public static boolean isWebAppRunning(I2PAppContext ctx, String appName) {
|
||||||
@ -184,11 +214,43 @@ public class WebAppStarter {
|
|||||||
return wac.isStarted();
|
return wac.isStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since Jetty 6 */
|
/**
|
||||||
|
* @since 0.9.41
|
||||||
|
*/
|
||||||
|
static boolean isWebAppRunning(Server s, String appName) {
|
||||||
|
ContextHandler wac = getWebApp(s, appName);
|
||||||
|
if (wac == null)
|
||||||
|
return false;
|
||||||
|
return wac.isStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warning, this will NOT work during shutdown, because
|
||||||
|
* the console is already unregistered.
|
||||||
|
*
|
||||||
|
* @since Jetty 6
|
||||||
|
*/
|
||||||
static ContextHandler getWebApp(I2PAppContext ctx, String appName) {
|
static ContextHandler getWebApp(I2PAppContext ctx, String appName) {
|
||||||
ContextHandlerCollection server = getConsoleServer(ctx);
|
ContextHandlerCollection server = getConsoleServer(ctx);
|
||||||
if (server == null)
|
if (server == null)
|
||||||
return null;
|
return null;
|
||||||
|
return getWebApp(server, appName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 0.9.41
|
||||||
|
*/
|
||||||
|
static ContextHandler getWebApp(Server s, String appName) {
|
||||||
|
ContextHandlerCollection server = getConsoleServer(s);
|
||||||
|
if (server == null)
|
||||||
|
return null;
|
||||||
|
return getWebApp(server, appName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 0.9.41
|
||||||
|
*/
|
||||||
|
private static ContextHandler getWebApp(ContextHandlerCollection server, String appName) {
|
||||||
Handler handlers[] = server.getHandlers();
|
Handler handlers[] = server.getHandlers();
|
||||||
if (handlers == null)
|
if (handlers == null)
|
||||||
return null;
|
return null;
|
||||||
@ -205,12 +267,23 @@ public class WebAppStarter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* See comments in ConfigClientsHandler
|
* See comments in ConfigClientsHandler
|
||||||
|
*
|
||||||
|
* Warning, this will NOT work during shutdown, because
|
||||||
|
* the console is already unregistered.
|
||||||
|
*
|
||||||
* @since public since 0.9.33, was package private
|
* @since public since 0.9.33, was package private
|
||||||
*/
|
*/
|
||||||
public static ContextHandlerCollection getConsoleServer(I2PAppContext ctx) {
|
public static ContextHandlerCollection getConsoleServer(I2PAppContext ctx) {
|
||||||
Server s = RouterConsoleRunner.getConsoleServer(ctx);
|
Server s = RouterConsoleRunner.getConsoleServer(ctx);
|
||||||
if (s == null)
|
if (s == null)
|
||||||
return null;
|
return null;
|
||||||
|
return getConsoleServer(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 0.9.41
|
||||||
|
*/
|
||||||
|
private static ContextHandlerCollection getConsoleServer(Server s) {
|
||||||
Handler h = s.getChildHandlerByClass(ContextHandlerCollection.class);
|
Handler h = s.getChildHandlerByClass(ContextHandlerCollection.class);
|
||||||
if (h == null)
|
if (h == null)
|
||||||
return null;
|
return null;
|
||||||
|
18
history.txt
18
history.txt
@ -1,3 +1,21 @@
|
|||||||
|
2019-06-15 zzz
|
||||||
|
* Console: Fix stopping webapps at shutdown (ticket #2508)
|
||||||
|
|
||||||
|
2019-06-09 zzz
|
||||||
|
* Eepsite Help page: Add links to Arabic, Hungarian, Indonesian.
|
||||||
|
fix link to Italian
|
||||||
|
* SusiMail: Add Farsi translation
|
||||||
|
* Tests: Fix some bashisms, add more files to bashisms check
|
||||||
|
* UPnP: Set lease duration of 3 hours, always refresh the lease
|
||||||
|
|
||||||
|
2019-06-08 zzz
|
||||||
|
* NetDB:
|
||||||
|
- Fix Deliv. Status msg sent direct to tunnel
|
||||||
|
- Faster startup for non-Android
|
||||||
|
|
||||||
|
2019-06-07 zzz
|
||||||
|
* NetDB: Fix NPE on failed decrypt of enc. ls2
|
||||||
|
|
||||||
2019-06-06 zzz
|
2019-06-06 zzz
|
||||||
* CPUID/NBI:
|
* CPUID/NBI:
|
||||||
- Add Skylake support (ticket #1869)
|
- Add Skylake support (ticket #1869)
|
||||||
|
@ -18,7 +18,7 @@ public class RouterVersion {
|
|||||||
/** deprecated */
|
/** deprecated */
|
||||||
public final static String ID = "Monotone";
|
public final static String ID = "Monotone";
|
||||||
public final static String VERSION = CoreVersion.VERSION;
|
public final static String VERSION = CoreVersion.VERSION;
|
||||||
public final static long BUILD = 10;
|
public final static long BUILD = 11;
|
||||||
|
|
||||||
/** for example "-test" */
|
/** for example "-test" */
|
||||||
public final static String EXTRA = "";
|
public final static String EXTRA = "";
|
||||||
|
@ -129,7 +129,10 @@ public class RouterAppManager extends ClientAppManagerImpl {
|
|||||||
case STOPPING:
|
case STOPPING:
|
||||||
case STOPPED:
|
case STOPPED:
|
||||||
_clients.remove(app);
|
_clients.remove(app);
|
||||||
_registered.remove(app.getName(), app);
|
boolean removed = _registered.remove(app.getName(), app);
|
||||||
|
if (removed && _log.shouldInfo()) {
|
||||||
|
_log.info("Client " + app.getDisplayName() + " UNREGISTERED AS " + app.getName());
|
||||||
|
}
|
||||||
if (message == null)
|
if (message == null)
|
||||||
message = "";
|
message = "";
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
@ -140,7 +143,10 @@ public class RouterAppManager extends ClientAppManagerImpl {
|
|||||||
case CRASHED:
|
case CRASHED:
|
||||||
case START_FAILED:
|
case START_FAILED:
|
||||||
_clients.remove(app);
|
_clients.remove(app);
|
||||||
_registered.remove(app.getName(), app);
|
boolean removed2 = _registered.remove(app.getName(), app);
|
||||||
|
if (removed2 && _log.shouldInfo()) {
|
||||||
|
_log.info("Client " + app.getDisplayName() + " UNREGISTERED AS " + app.getName());
|
||||||
|
}
|
||||||
if (message == null)
|
if (message == null)
|
||||||
message = "";
|
message = "";
|
||||||
_log.log(Log.CRIT, "Client " + app.getDisplayName() + ' ' + state +
|
_log.log(Log.CRIT, "Client " + app.getDisplayName() + ' ' + state +
|
||||||
@ -172,6 +178,22 @@ public class RouterAppManager extends ClientAppManagerImpl {
|
|||||||
return super.register(app);
|
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
|
||||||
|
* @since 0.9.41 overridden for logging only
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void unregister(ClientApp app) {
|
||||||
|
if (_log.shouldInfo()) {
|
||||||
|
if (getRegisteredApp(app.getName()) != null)
|
||||||
|
_log.info("Client " + app.getDisplayName() + " UNREGISTERED AS " + app.getName());
|
||||||
|
}
|
||||||
|
super.unregister(app);
|
||||||
|
}
|
||||||
|
|
||||||
/// end ClientAppManager interface
|
/// end ClientAppManager interface
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user