Files
i2p.i2p/apps/routerconsole/java/src/net/i2p/router/web/WebAppConfiguration.java

187 lines
7.7 KiB
Java
Raw Normal View History

package net.i2p.router.web;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* Add to the webapp classpath as specified in webapps.config.
* This allows us to reference classes that are not in the classpath
* specified in wrapper.config, since old installations have
* individual jars and not lib/*.jar specified in wrapper.config.
*
* A sample line in webapps.config is:
2010-03-15 14:34:25 +00:00
* webapps.appname.classpath=foo.jar,$I2P/lib/bar.jar
* Unless $I2P is specified the path will be relative to $I2P/lib for
* webapps in the installation and appDir/plugins/appname/lib for plugins.
*
* Sadly, setting Class-Path in MANIFEST.MF doesn't work for jetty wars.
* We could look there ourselves, or look for another properties file in the war,
* but let's just do it in webapps.config.
*
* No, wac.addClassPath() does not work. For more info see:
*
* http://servlets.com/archive/servlet/ReadMsg?msgId=511113&listName=jetty-support
*
* @since 0.7.12
* @author zzz
*/
public class WebAppConfiguration implements Configuration {
private static final String CLASSPATH = ".classpath";
/**
* This was the interface in Jetty 5, in Jetty 6 was configureClassLoader(),
* now it's configure()
*/
private void configureClassPath(WebAppContext wac) throws Exception {
String ctxPath = wac.getContextPath();
//System.err.println("Configure Class Path " + ctxPath);
if (ctxPath.equals("/"))
return;
String appName = ctxPath.substring(1);
/****
if (ctxPath.equals("/susimail")) {
// allow certain Jetty classes, restricted as of Jetty 7
// See http://wiki.eclipse.org/Jetty/Reference/Jetty_Classloading
//System.err.println("Allowing Jetty utils in classpath for " + appName);
//System.err.println("System classes before: " + Arrays.toString(wac.getSystemClasses()));
//System.err.println("Server classes before: " + Arrays.toString(wac.getServerClasses()));
wac.addSystemClass("org.eclipse.jetty.http.");
wac.addSystemClass("org.eclipse.jetty.io.");
wac.addSystemClass("org.eclipse.jetty.util.");
// org.eclipse.jetty.webapp.ClasspathPattern looks in-order, and
// WebAppContext doesn't provide a remove method, so we must
// convert to a list, remove the wildcard entry, add ours, then
// add the wildcard back, then reset.
List<String> classes = new ArrayList<String>(16);
classes.addAll(Arrays.asList(wac.getServerClasses()));
classes.remove("org.eclipse.jetty.");
classes.add("-org.eclipse.jetty.http.");
classes.add("-org.eclipse.jetty.io.");
classes.add("-org.eclipse.jetty.util.");
classes.add("org.eclipse.jetty.");
wac.setServerClasses(classes.toArray(new String[classes.size()]));
//System.err.println("System classes after: " + Arrays.toString(wac.getSystemClasses()));
//System.err.println("Server classes after: " + Arrays.toString(wac.getServerClasses()));
}
****/
I2PAppContext i2pContext = I2PAppContext.getGlobalContext();
File libDir = new File(i2pContext.getBaseDir(), "lib");
// FIXME this only works if war is the same name as the plugin
File pluginDir = new File(i2pContext.getConfigDir(),
Big refactor of the router console update subsystem, in preparation for implementing out-of-console updaters like i2psnark. - Add new update interfaces in net.i2p.update - All update implementations moved to routerconsole update/ - Implement an UpdateManager that registers with the RouterContext - UpdateManager handles multiple types of things to update (router, plugins, news, ...) and methods of updating (HTTP, ...) - UpdateManager maintains list of installed, downloaded, and available versions of everything - Define Updaters that can check for a new version and/or download an item - Individual Updaters register with the UpdateManager obtained from I2PAppContext, identifying the type of update item and update method they can handle. - Updaters need only core libs, no router.jar or routerconsole access required. - All checks and updates are initiated via the UpdateManager. - All status on checks and updates in-progress or completed are obtained from the UpdateManager. No more use of System properties to broadcast update state. - All update and checker tasks are intantiated on demand and threaded; no more static references left over. - Split out the Runners and Checkers from the Handlers and make the inheritance more sane. - No more permanent NewsFetcher thread; run on the SimpleScheduler queue and thread a checker task only to fetch the news. - No more static NewsFetcher instance in routerconsole. All helper methods that are still required are moved to NewsHelper. The UpdateManager implements the policy for when to check and download. All requests go through the UpdateManager. For each update type, there's several parts: - The xxxUpdateHandler implements the Updater - The xxxUpdateChecker implements the UpdateTask for checking - The xxxUpdateRunner implements the UpdateTask for downloading New and moved classes: web/ update/ ---- ------- new ConsoleUpdateManager.java new PluginUpdateChecker.java from PluginUpdateChecker PluginUpdateChecker -> PluginUpdateHandler.java PluginUpdateHandler.java -> PluginUpdateRunner new UnsignedUpdateHandler.java UnsignedUpdateHandler -> UnsignedUpdateRunner.java new UnsignedUpdateChecker from NewsFetcher UpdateHandler.java remains new UpdateHandler.java new UpdateRunner.java from UpdateHandler move NewsHandler from NewsFetcher new NewsFetcher new NewsTimerTask new DummyHandler Initial checkin. Unfinished, untested, unpolished.
2012-06-18 22:09:45 +00:00
PluginStarter.PLUGIN_DIR + ctxPath);
File dir = libDir;
String cp;
/****
if (ctxPath.equals("/susimail")) {
// Ticket #957... don't know why...
// Only really required if started manually, but we don't know that from here
cp = "jetty-util.jar";
} else ****/ if (pluginDir.exists()) {
File consoleDir = new File(pluginDir, "console");
Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
cp = props.getProperty(RouterConsoleRunner.PREFIX + appName + CLASSPATH);
dir = pluginDir;
} else {
Properties props = RouterConsoleRunner.webAppProperties(i2pContext);
cp = props.getProperty(RouterConsoleRunner.PREFIX + appName + CLASSPATH);
}
if (cp == null)
return;
StringTokenizer tok = new StringTokenizer(cp, " ,");
StringBuilder buf = new StringBuilder();
Set<URL> systemCP = getSystemClassPath();
while (tok.hasMoreTokens()) {
if (buf.length() > 0)
buf.append(',');
String elem = tok.nextToken().trim();
String path;
if (elem.startsWith("$I2P"))
2010-02-15 16:12:49 +00:00
path = i2pContext.getBaseDir().getAbsolutePath() + elem.substring(4);
else if (elem.startsWith("$PLUGIN"))
2010-02-15 16:12:49 +00:00
path = dir.getAbsolutePath() + elem.substring(7);
else
path = dir.getAbsolutePath() + '/' + elem;
// As of Jetty 6, we can't add dups to the class path, or
// else it screws up statics
// This is not a complete solution because the Windows no-wrapper classpath is set
// by the launchi2p.jar (i2p.exe) manifest and is not detected below.
// TODO: Add a classpath to the command line in i2pstandalone.xml?
File jfile = new File(path);
File jdir = jfile.getParentFile();
if (systemCP.contains(jfile.toURI().toURL()) ||
(jdir != null && systemCP.contains(jdir.toURI().toURL()))) {
//System.err.println("Not adding " + path + " to classpath for " + appName + ", already in system classpath");
// Ticket #957... don't know why...
if (!ctxPath.equals("/susimail"))
continue;
}
System.err.println("Adding " + path + " to classpath for " + appName);
buf.append(path);
}
if (buf.length() <= 0)
return;
ClassLoader cl = wac.getClassLoader();
if (cl != null && cl instanceof WebAppClassLoader) {
WebAppClassLoader wacl = (WebAppClassLoader) cl;
wacl.addClassPath(buf.toString());
} else {
// This was not working because the WebAppClassLoader already exists
// and it calls getExtraClasspath in its constructor
// Not sure why WACL already exists...
wac.setExtraClasspath(buf.toString());
}
}
/** @since 0.9 */
private static Set<URL> getSystemClassPath() {
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
URL urls[] = urlClassLoader.getURLs();
Set<URL> rv = new HashSet<URL>(32);
for (int i = 0; i < urls.length; i++) {
rv.add(urls[i]);
}
return rv;
}
/** @since Jetty 7 */
public void deconfigure(WebAppContext context) {}
/** @since Jetty 7 */
public void configure(WebAppContext context) throws Exception {
configureClassPath(context);
}
/** @since Jetty 7 */
public void cloneConfigure(WebAppContext template, WebAppContext context) {
// no state, nothing to be done
}
/** @since Jetty 7 */
public void destroy(WebAppContext context) {}
/** @since Jetty 7 */
public void preConfigure(WebAppContext context) {}
/** @since Jetty 7 */
public void postConfigure(WebAppContext context) {}
}