2010-02-06 18:40:55 +00:00
|
|
|
package net.i2p.router.web;
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.IOException;
|
2012-03-14 12:04:20 +00:00
|
|
|
import java.util.HashMap;
|
2010-05-13 17:04:16 +00:00
|
|
|
import java.util.Map;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
2010-02-06 18:40:55 +00:00
|
|
|
|
2012-10-13 13:06:22 +00:00
|
|
|
import net.i2p.router.RouterContext;
|
2010-05-13 17:04:16 +00:00
|
|
|
import net.i2p.util.FileUtil;
|
2010-07-06 15:22:48 +00:00
|
|
|
import net.i2p.util.SecureDirectory;
|
2010-02-06 18:40:55 +00:00
|
|
|
|
2012-11-21 20:49:18 +00:00
|
|
|
import org.eclipse.jetty.server.Handler;
|
|
|
|
import org.eclipse.jetty.server.Server;
|
|
|
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
|
|
|
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
|
|
|
import org.eclipse.jetty.webapp.WebAppContext;
|
2010-02-06 18:40:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2010-03-15 14:34:25 +00:00
|
|
|
* Add, start or stop a webapp.
|
|
|
|
* Add to the webapp classpath if specified in webapps.config.
|
2010-02-06 18:40:55 +00:00
|
|
|
*
|
|
|
|
* Sadly, setting Class-Path in MANIFEST.MF doesn't work for jetty wars.
|
2010-03-15 14:34:25 +00:00
|
|
|
* See WebAppConfiguration for more information.
|
2010-02-06 18:40:55 +00:00
|
|
|
* but let's just do it in webapps.config.
|
|
|
|
*
|
2010-03-15 14:34:25 +00:00
|
|
|
* No, wac.addClassPath() does not work. For more info see:
|
2010-02-06 18:40:55 +00:00
|
|
|
*
|
|
|
|
* http://servlets.com/archive/servlet/ReadMsg?msgId=511113&listName=jetty-support
|
|
|
|
*
|
|
|
|
* @since 0.7.12
|
|
|
|
* @author zzz
|
|
|
|
*/
|
|
|
|
public class WebAppStarter {
|
|
|
|
|
2012-03-14 12:04:20 +00:00
|
|
|
private static final Map<String, Long> warModTimes = new ConcurrentHashMap();
|
|
|
|
static final Map INIT_PARAMS = new HashMap(4);
|
|
|
|
//static private Log _log;
|
2011-06-10 14:17:45 +00:00
|
|
|
|
|
|
|
static {
|
2012-03-14 12:04:20 +00:00
|
|
|
//_log = ContextHelper.getContext(null).logManager().getLog(WebAppStarter.class); ;
|
|
|
|
// see DefaultServlet javadocs
|
|
|
|
String pfx = "org.mortbay.jetty.servlet.Default.";
|
|
|
|
INIT_PARAMS.put(pfx + "cacheControl", "max-age=86400");
|
|
|
|
INIT_PARAMS.put(pfx + "dirAllowed", "false");
|
2011-06-10 14:17:45 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:04:16 +00:00
|
|
|
|
2010-02-06 18:40:55 +00:00
|
|
|
/**
|
|
|
|
* adds and starts
|
2010-02-11 21:41:54 +00:00
|
|
|
* @throws just about anything, caller would be wise to catch Throwable
|
2010-02-06 18:40:55 +00:00
|
|
|
*/
|
2012-10-13 13:06:22 +00:00
|
|
|
static void startWebApp(RouterContext ctx, ContextHandlerCollection server,
|
2011-12-23 00:56:48 +00:00
|
|
|
String appName, String warPath) throws Exception {
|
2010-07-06 15:22:48 +00:00
|
|
|
File tmpdir = new SecureDirectory(ctx.getTempDir(), "jetty-work-" + appName + ctx.random().nextInt());
|
2011-12-23 00:56:48 +00:00
|
|
|
WebAppContext wac = addWebApp(ctx, server, appName, warPath, tmpdir);
|
2012-03-14 12:04:20 +00:00
|
|
|
//_log.debug("Loading war from: " + warPath);
|
2012-11-21 20:49:18 +00:00
|
|
|
LocaleWebAppHandler.setInitParams(wac, INIT_PARAMS);
|
2010-02-06 18:40:55 +00:00
|
|
|
wac.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* add but don't start
|
2010-03-29 21:20:48 +00:00
|
|
|
* This is used only by RouterConsoleRunner, which adds all the webapps first
|
|
|
|
* and then starts all at once.
|
2010-02-06 18:40:55 +00:00
|
|
|
*/
|
2012-10-13 13:06:22 +00:00
|
|
|
static WebAppContext addWebApp(RouterContext ctx, ContextHandlerCollection server,
|
2011-12-23 00:56:48 +00:00
|
|
|
String appName, String warPath, File tmpdir) throws IOException {
|
2010-02-06 18:40:55 +00:00
|
|
|
|
2010-03-29 21:20:48 +00:00
|
|
|
// Jetty will happily load one context on top of another without stopping
|
|
|
|
// the first one, so we remove any previous one here
|
|
|
|
try {
|
2011-12-23 00:56:48 +00:00
|
|
|
stopWebApp(appName);
|
2010-03-29 21:20:48 +00:00
|
|
|
} catch (Throwable t) {}
|
|
|
|
|
2010-05-13 17:04:16 +00:00
|
|
|
// To avoid ZipErrors from JarURLConnetion caching,
|
|
|
|
// (used by Jetty JarResource and JarFileResource)
|
|
|
|
// copy the war to a new directory if it is newer than the one we loaded originally.
|
|
|
|
// Yes, URLConnection has a setDefaultUseCaches() method, but it's hard to get to
|
|
|
|
// because it's non-static and the class is abstract, and we don't really want to
|
|
|
|
// set the default to false for everything.
|
|
|
|
long newmod = (new File(warPath)).lastModified();
|
|
|
|
if (newmod <= 0)
|
|
|
|
throw new IOException("Web app " + warPath + " does not exist");
|
|
|
|
Long oldmod = warModTimes.get(warPath);
|
|
|
|
if (oldmod == null) {
|
|
|
|
warModTimes.put(warPath, new Long(newmod));
|
|
|
|
} else if (oldmod.longValue() < newmod) {
|
|
|
|
// copy war to temporary directory
|
2010-07-06 15:22:48 +00:00
|
|
|
File warTmpDir = new SecureDirectory(ctx.getTempDir(), "war-copy-" + appName + ctx.random().nextInt());
|
2010-05-13 17:04:16 +00:00
|
|
|
warTmpDir.mkdir();
|
|
|
|
String tmpPath = (new File(warTmpDir, appName + ".war")).getAbsolutePath();
|
|
|
|
if (!FileUtil.copy(warPath, tmpPath, true))
|
|
|
|
throw new IOException("Web app failed copy from " + warPath + " to " + tmpPath);
|
|
|
|
warPath = tmpPath;
|
|
|
|
}
|
|
|
|
|
2011-12-23 00:56:48 +00:00
|
|
|
WebAppContext wac = new WebAppContext(warPath, "/"+ appName);
|
2010-02-06 18:40:55 +00:00
|
|
|
tmpdir.mkdir();
|
|
|
|
wac.setTempDirectory(tmpdir);
|
2012-03-17 21:52:17 +00:00
|
|
|
// all the JSPs are precompiled, no need to extract
|
|
|
|
wac.setExtractWAR(false);
|
2010-02-06 18:40:55 +00:00
|
|
|
|
|
|
|
// this does the passwords...
|
2012-10-13 13:06:22 +00:00
|
|
|
RouterConsoleRunner.initialize(ctx, wac);
|
2010-02-06 18:40:55 +00:00
|
|
|
|
|
|
|
// see WebAppConfiguration for info
|
2011-12-23 00:56:48 +00:00
|
|
|
String[] classNames = wac.getConfigurationClasses();
|
2010-02-06 18:40:55 +00:00
|
|
|
String[] newClassNames = new String[classNames.length + 1];
|
|
|
|
for (int j = 0; j < classNames.length; j++)
|
|
|
|
newClassNames[j] = classNames[j];
|
|
|
|
newClassNames[classNames.length] = WebAppConfiguration.class.getName();
|
2011-12-23 00:56:48 +00:00
|
|
|
wac.setConfigurationClasses(newClassNames);
|
|
|
|
server.addHandler(wac);
|
|
|
|
server.mapContexts();
|
2010-02-06 18:40:55 +00:00
|
|
|
return wac;
|
|
|
|
}
|
2010-02-08 22:19:59 +00:00
|
|
|
|
|
|
|
/**
|
2010-03-29 21:20:48 +00:00
|
|
|
* stop it and remove the context
|
2010-02-11 21:41:54 +00:00
|
|
|
* @throws just about anything, caller would be wise to catch Throwable
|
2010-02-08 22:19:59 +00:00
|
|
|
*/
|
2011-12-23 00:56:48 +00:00
|
|
|
static void stopWebApp(String appName) {
|
|
|
|
ContextHandler wac = getWebApp(appName);
|
|
|
|
if (wac == null)
|
|
|
|
return;
|
2010-02-08 22:19:59 +00:00
|
|
|
try {
|
2011-12-23 00:56:48 +00:00
|
|
|
// not graceful is default in Jetty 6?
|
|
|
|
wac.stop();
|
|
|
|
} catch (Exception ie) {}
|
|
|
|
ContextHandlerCollection server = getConsoleServer();
|
|
|
|
if (server == null)
|
|
|
|
return;
|
2010-03-29 21:20:48 +00:00
|
|
|
try {
|
2011-12-23 00:56:48 +00:00
|
|
|
server.removeHandler(wac);
|
|
|
|
server.mapContexts();
|
2010-03-29 21:20:48 +00:00
|
|
|
} catch (IllegalStateException ise) {}
|
2010-02-08 22:19:59 +00:00
|
|
|
}
|
|
|
|
|
2010-04-16 03:58:48 +00:00
|
|
|
static boolean isWebAppRunning(String appName) {
|
2011-12-23 00:56:48 +00:00
|
|
|
ContextHandler wac = getWebApp(appName);
|
|
|
|
if (wac == null)
|
2010-04-23 16:28:14 +00:00
|
|
|
return false;
|
2010-04-16 03:58:48 +00:00
|
|
|
return wac.isStarted();
|
|
|
|
}
|
|
|
|
|
2011-12-23 00:56:48 +00:00
|
|
|
/** @since Jetty 6 */
|
|
|
|
static ContextHandler getWebApp(String appName) {
|
|
|
|
ContextHandlerCollection server = getConsoleServer();
|
|
|
|
if (server == null)
|
|
|
|
return null;
|
|
|
|
Handler handlers[] = server.getHandlers();
|
|
|
|
if (handlers == null)
|
|
|
|
return null;
|
|
|
|
String path = '/'+ appName;
|
|
|
|
for (int i = 0; i < handlers.length; i++) {
|
2012-11-22 23:14:08 +00:00
|
|
|
if (!(handlers[i] instanceof ContextHandler))
|
|
|
|
continue;
|
2011-12-23 00:56:48 +00:00
|
|
|
ContextHandler ch = (ContextHandler) handlers[i];
|
2011-12-23 15:36:44 +00:00
|
|
|
if (path.equals(ch.getContextPath()))
|
2011-12-23 00:56:48 +00:00
|
|
|
return ch;
|
2010-02-18 16:33:47 +00:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2011-12-23 00:56:48 +00:00
|
|
|
|
|
|
|
/** see comments in ConfigClientsHandler */
|
|
|
|
static ContextHandlerCollection getConsoleServer() {
|
|
|
|
Server s = RouterConsoleRunner.getConsoleServer();
|
|
|
|
if (s == null)
|
|
|
|
return null;
|
|
|
|
Handler h = s.getChildHandlerByClass(ContextHandlerCollection.class);
|
|
|
|
if (h == null)
|
|
|
|
return null;
|
|
|
|
return (ContextHandlerCollection) h;
|
|
|
|
}
|
2010-02-06 18:40:55 +00:00
|
|
|
}
|