Java tutorial
/* * Adito * * Copyright (C) 2003-2006 3SP LTD. All Rights Reserved * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package com.adito.server; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.net.Authenticator; import java.net.Inet4Address; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.NetworkInterface; import java.net.Socket; import java.net.SocketException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; import java.util.TreeMap; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import javax.net.ssl.TrustManager; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.UIManager; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.mortbay.http.HttpContext; import org.mortbay.http.NCSARequestLog; import org.mortbay.http.ResourceCache; import org.mortbay.http.SocketListener; import org.mortbay.http.handler.MsieSslHandler; import org.mortbay.jetty.Server; import org.mortbay.jetty.servlet.ServletHandler; import org.mortbay.jetty.servlet.ServletHttpRequest; import org.mortbay.jetty.servlet.ServletHttpResponse; import org.mortbay.jetty.servlet.SessionManager; import org.mortbay.util.LifeCycleEvent; import org.mortbay.util.LifeCycleListener; import org.mortbay.util.Password; import org.tanukisoftware.wrapper.WrapperListener; import org.tanukisoftware.wrapper.WrapperManager; import com.adito.boot.BootProgressMonitor; import com.adito.boot.Branding; import com.adito.boot.BrowserLauncher; import com.adito.boot.Context; import com.adito.boot.ContextConfig; import com.adito.boot.ContextHolder; import com.adito.boot.ContextKey; import com.adito.boot.ContextListener; import com.adito.boot.DefaultPropertyDefinition; import com.adito.boot.KeyStoreManager; import com.adito.boot.LogBootProgressMonitor; import com.adito.boot.PropertyClass; import com.adito.boot.PropertyClassManager; import com.adito.boot.PropertyDefinition; import com.adito.boot.PropertyList; import com.adito.boot.PropertyPreferences; import com.adito.boot.RequestHandler; import com.adito.boot.RequestHandlerRequest; import com.adito.boot.RequestHandlerResponse; import com.adito.boot.StopContextListenerThread; import com.adito.boot.SystemProperties; import com.adito.boot.Util; import com.adito.boot.VersionInfo; import com.adito.boot.XMLPropertyDefinition; import com.adito.boot.VersionInfo.Version; import com.adito.server.jetty.CustomHttpContext; import com.adito.server.jetty.CustomJsseListener; import com.adito.server.jetty.CustomWebApplicationContext; import com.adito.server.jetty.HTTPRedirectHandler; /** * <p> * Provides an entry point and a default environment for starting the * Adito service. * * <p> * Adito is primarily a standard Java web application. However, it * requires a few additional services from the container that it is running in. * This environment is called the {@link com.adito.boot.Context} (see this * interfaces Javadoc for more information about this environment) and this * class implements that interface. * * <p> * This class currently provides an implementation that uses Jetty for the * servlet / JSP container. * * <p> * The <i>Context Properties</b> are stored using the Java Preferences API so * will likely end up in the Windows register on Win32 platforms or XML files * everywhere else. * * @see com.adito.boot.Context */ public class Main implements WrapperListener, Context { // Private statics private static File DB_DIR = new File("db"); private static File CONF_DIR = new File("conf"); private static File TMP_DIR = new File("tmp"); private static File LOG_DIR = new File("logs"); private static File appDir = null; static Log log; static Preferences PREF; static ClassLoader bootLoader; // Private instance variables private Server server; private long startupStarted; private HashMap<URL, ResourceCache> resourceCaches; private String hostAddress; private static boolean useWrapper = false; private boolean install; private boolean gui; private Throwable startupException; // a list of listeners holding the http and https socket listeners. private List<SocketListener> listeners; private CustomWebApplicationContext webappContext; private CustomHttpContext httpContext; private String jettyLog; private int defaultPort; private int actualPort; private boolean useDevConfig; private String hostname; private ServerLock serverLock; private Thread mainThread; private Thread insecureThread; private ThreadGroup threadGroup; private TreeMap<String, PropertyDefinition> contextPropertyDefinitions; private List<ContextListener> contextListeners; private boolean shuttingDown; private ContextConfig contextConfiguration; private BootProgressMonitor bootProgressMonitor; private boolean logToConsole; private boolean restarting; private Server insecureServer; private ServletHandler servletHandler; public static void setBootLoader(ClassLoader bootLoader) { Main.bootLoader = bootLoader; } /** * Entry point * * @param args * @throws Throwable */ public static void main(String[] args) throws Throwable { // This is a hack to allow the Install4J installer to get the java // runtime that will be used if (args.length > 0 && args[0].equals("--jvmdir")) { System.out.println(SystemProperties.get("java.home")); System.exit(0); } useWrapper = System.getProperty("wrapper.key") != null; final Main main = new Main(); ContextHolder.setContext(main); if (useWrapper) { WrapperManager.start(main, args); } else { Integer returnCode = main.start(args); if (returnCode != null) { if (main.gui) { if (main.startupException == null) { main.startupException = new Exception("An exit code of " + returnCode + " was returned."); } try { if (SystemProperties.get("os.name").toLowerCase().startsWith("windows")) { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } } catch (Exception e) { } String mesg = main.startupException.getMessage() == null ? "No message supplied." : main.startupException.getMessage(); StringBuffer buf = new StringBuffer(); int l = 0; char ch = ' '; for (int i = 0; i < mesg.length(); i++) { ch = mesg.charAt(i); if (l > 50 && ch == ' ') { buf.append("\n"); l = 0; } else { if (ch == '\n') { l = 0; } else { l++; } buf.append(ch); } } mesg = buf.toString(); final String fMesg = mesg; SwingUtilities.invokeAndWait(new Runnable() { public void run() { JOptionPane.showMessageDialog(null, fMesg, "Startup Error", JOptionPane.ERROR_MESSAGE); } }); } System.exit(returnCode.intValue()); } else { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { if (!main.shuttingDown) { main.stop(0); } } }); } } } /* * (non-Javadoc) * * @see org.tanukisoftware.wrapper.WrapperListener#start(java.lang.String[]) */ public Integer start(String[] args) { startupStarted = System.currentTimeMillis(); // Inform the wrapper the startup process may take a while if (useWrapper) { WrapperManager.signalStarting(60000); } // Parse the command line Integer returnCode = parseCommandLine(args); if (returnCode != null) { if (returnCode.intValue() == 999) { return null; } return returnCode; } // Create the boot progress monitor if (gui) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { } bootProgressMonitor = new SwingBootProgressMonitor(); } else { bootProgressMonitor = new LogBootProgressMonitor(); } // resourceCaches = new HashMap<URL, ResourceCache>(); contextListeners = new ArrayList<ContextListener>(); loadSystemProperties(); initialiseLogging(); /* * Migrate preferences. */ File newPrefDir = new File(ContextHolder.getContext().getConfDirectory(), "prefs"); PREF = PropertyPreferences.SYSTEM_ROOT; try { if (!newPrefDir.exists() && Preferences.systemRoot().node("/com").nodeExists("adito")) { Preferences from = Preferences.systemRoot().node("/com/adito"); log.warn("Migrating preferences"); try { copyNode(from.node("core"), PREF.node("core")); from.node("core").removeNode(); copyNode(from.node("plugin"), PREF.node("plugin")); from.node("plugin").removeNode(); copyNode(from.node("extensions"), PREF.node("extensions")); from.node("extensions").removeNode(); copyNode(from.node("dbupgrader"), PREF.node("dbupgrader")); from.node("dbupgrader").removeNode(); } catch (Exception e) { log.error("Failed to migrate preferences.", e); } try { from.flush(); } catch (BackingStoreException bse) { log.error("Failed to flush old preferences"); } try { PREF.flush(); } catch (BackingStoreException bse) { log.error("Failed to flush new preferences"); } if (log.isInfoEnabled()) { log.info("Flushing preferences"); } } } catch (BackingStoreException bse) { log.error("Failed to migrate preferences.", bse); } // Inform the wrapper the startup process is going ok if (useWrapper) { WrapperManager.signalStarting(60000); } try { clearTemp(); try { hostname = Inet4Address.getLocalHost().getCanonicalHostName(); hostAddress = Inet4Address.getLocalHost().getHostAddress(); } catch (Exception ex) { // This should be fatal, we now rely on the hostname being // available throw new Exception("The host name or address on which this service is running could not " + "be determined. Check you network configuration. One possible cause is " + "a misconfigured 'hosts' file (e.g. on UNIX-like systems this would be " + "/etc/hosts, on Windows XP it would be " + "C:\\Windows\\System32\\Drivers\\Etc\\Hosts)."); } PropertyClassManager.getInstance() .registerPropertyClass(contextConfiguration = new ContextConfig(getClass().getClassLoader())); // Display some information about the system we are running on displaySystemInfo(); // Load the context property definitions loadContextProperties(); // Inform the wrapper the startup process is going ok if (useWrapper) { WrapperManager.signalStarting(60000); } // Configure any HTTP / HTTPS / SOCKS proxy servers configureProxyServers(); PropertyList l = contextConfiguration.retrievePropertyList(new ContextKey("webServer.bindAddress")); getBootProgressMonitor().updateMessage("Creating server lock"); getBootProgressMonitor().updateProgress(6); serverLock = new ServerLock((String) l.get(0)); if (serverLock.isLocked()) { if (!isSetupMode()) { if (serverLock.isSetup()) { throw new Exception("The installation wizard is currently running. " + "Please shut this down by pointing your browser " + "to http://" + getHostname() + ":" + serverLock.getPort() + "/showShutdown.do before attempting to start the server again."); } else { throw new Exception("The server is already running."); } } else { if (!serverLock.isSetup()) { throw new Exception("The server is currently already running. " + "Please shut this down by pointing your browser " + "to https://" + getHostname() + ":" + serverLock.getPort() + "/showShutdown.do before attempting to start the server again."); } else { throw new Exception("The installation wizard is running.."); } } } // Inform the wrapper the startup process is going ok if (useWrapper) { WrapperManager.signalStarting(60000); } Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { serverLock.stop(); } }); // registerKeyStores(); // threadGroup = new ThreadGroup("MainThreadGroup"); if (install) { setupMode(); } else { normalMode(); startHttpServer(); } } catch (Throwable t) { startupException = t; log.error("Failed to start the server. " + t.getMessage(), t); return new Integer(1); } return null; } /* * (non-Javadoc) * * @see com.adito.boot.Context#getConfig() */ public PropertyClass getConfig() { return contextConfiguration; } /* * (non-Javadoc) * * @see org.tanukisoftware.wrapper.WrapperListener#controlEvent(int) */ public void controlEvent(int evt) { if (evt == WrapperManager.WRAPPER_CTRL_C_EVENT) { if (log.isInfoEnabled()) log.info("Got CTRL+C event"); WrapperManager.stop(0); } else if (evt == WrapperManager.WRAPPER_CTRL_CLOSE_EVENT) { if (log.isInfoEnabled()) log.info("Got windows close event, ignoring."); } else if (evt == WrapperManager.WRAPPER_CTRL_LOGOFF_EVENT) { if (log.isInfoEnabled()) log.info("Got windows logoff event, ignoring."); } else if (evt == WrapperManager.WRAPPER_CTRL_SHUTDOWN_EVENT) { if (log.isInfoEnabled()) log.info("Got shutdown event"); WrapperManager.stop(0); } else { if (log.isInfoEnabled()) log.info("Got unknown control event " + evt + ", ignoring."); } } /* * (non-Javadoc) * * @see org.tanukisoftware.wrapper.WrapperListener#stop(int) */ public int stop(int exitCode) { if (log != null) { if (log.isInfoEnabled()) { if (restarting) log.info("Restarting the server."); else log.info("Shutting down the server."); } } if (useWrapper) { WrapperManager.signalStopping(20000); } // TODO This really screws up wrapper on windows - no idea why if (server != null && server.isStarted()) { try { server.stop(false); } catch (InterruptedException e) { if (log != null) { if (log.isInfoEnabled()) log.info("Failed to stop server.", e); } } } // Inform all context listeners of what is happening for (ContextListener l : contextListeners) { new StopContextListenerThread(l).waitForStop(); } // if (log.isInfoEnabled()) { log.info("Flushing preferences"); } try { ContextHolder.getContext().getPreferences().flush(); } catch (BackingStoreException bse) { log.error("Failed to flush context preferences.", bse); } try { Preferences.systemRoot().flush(); } catch (IllegalStateException ise) { } catch (BackingStoreException bse) { log.error("Failed to flush system preferences"); } return exitCode; } void loadContextProperties() throws IOException, JDOMException { getBootProgressMonitor().updateMessage("Loading context properties"); getBootProgressMonitor().updateProgress(4); for (Enumeration<URL> e = getClass().getClassLoader() .getResources("META-INF/contextConfig-definitions.xml"); e.hasMoreElements();) { URL u = e.nextElement(); log.info("Loading context property definitions from " + u); SAXBuilder build = new SAXBuilder(); Element root = build.build(u).getRootElement(); if (!root.getName().equals("definitions")) { throw new JDOMException("Root element in " + u + " should be <definitions>"); } for (Iterator i = root.getChildren().iterator(); i.hasNext();) { Element c = (Element) i.next(); if (c.getName().equals("definition")) { DefaultPropertyDefinition def = new XMLPropertyDefinition(c); contextConfiguration.registerPropertyDefinition(def); } else { throw new JDOMException( "Expect root element of <definitions> with child elements of <definition>. Got <" + c.getName() + ">."); } } } } void copyNode(Preferences from, Preferences to) throws BackingStoreException { String[] keys = from.keys(); for (int i = 0; i < keys.length; i++) { to.put(keys[i], from.get(keys[i], "")); } String childNodes[] = from.childrenNames(); for (int i = 0; i < childNodes.length; i++) { Preferences cn = from.node(childNodes[i]); Preferences tn = to.node(childNodes[i]); copyNode(cn, tn); } } /* * (non-Javadoc) * * @see com.adito.boot.Context#isSetupMode() */ public boolean isSetupMode() { return install; } /* * (non-Javadoc) * * @see com.adito.boot.Context#isRestartAvailableMode() */ public boolean isRestartAvailableMode() { return (useDevConfig || useWrapper) && !isSetupMode(); } /* * (non-Javadoc) * * @see com.adito.boot.Context#shutdown(boolean) */ public void shutdown(boolean restart) { shuttingDown = true; restarting = restart; if (useWrapper) { if (restart) { WrapperManager.restart(); } else { WrapperManager.stop(0); } } else { stop(0); System.exit(0); } } /* * (non-Javadoc) * * @see com.adito.boot.Context#getVersion() */ public Version getVersion() { return VersionInfo.getVersion(); } /* * (non-Javadoc) * * @see com.adito.boot.Context#getConfDirectory() */ public File getConfDirectory() { return CONF_DIR; } /* * (non-Javadoc) * * @see com.adito.boot.Context#getTempDirectory() */ public File getTempDirectory() { return TMP_DIR; } /* * (non-Javadoc) * * @see com.adito.boot.Context#getLogDirectory() */ public File getLogDirectory() { return LOG_DIR; } /* * (non-Javadoc) * * @see com.adito.boot.Context#getApplicationDirectory() */ public File getApplicationDirectory() { return appDir == null ? new File(getTempDirectory(), "extensions") : appDir; } /* * (non-Javadoc) * * @see com.adito.boot.Context#getDBDirectory() */ public File getDBDirectory() { return DB_DIR; } /* * (non-Javadoc) * * @see com.adito.boot.Context#getMainThread() */ public Thread getMainThread() { return mainThread; } /* * (non-Javadoc) * * @see com.adito.boot.Context#setResourceAlias(java.lang.String, * java.lang.String) */ public void setResourceAlias(String uri, String location) { webappContext.setResourceAlias(uri, location); } /* * (non-Javadoc) * * @see com.adito.boot.Context#addResourceBase(java.net.URL) */ public void addResourceBase(URL base) { if (log.isInfoEnabled()) log.info("Adding new resource base " + base.toExternalForm()); ResourceCache cache = new ResourceCache(); cache.setMimeMap(webappContext.getMimeMap()); cache.setEncodingMap(webappContext.getEncodingMap()); cache.setResourceBase(base.toExternalForm()); try { cache.start(); webappContext.addResourceCache(cache); if (httpContext != null) { httpContext.addResourceCache(cache); } resourceCaches.put(base, cache); } catch (Exception e) { log.error("Failed to add new resource base " + base.toExternalForm() + ".", e); } } /* * (non-Javadoc) * * @see com.adito.boot.Context#addResourceBase(java.net.URL) */ public void removeResourceBase(URL base) { if (log.isInfoEnabled()) log.info("Removing resource base " + base.toExternalForm()); ResourceCache cache = (ResourceCache) resourceCaches.get(base); webappContext.removeResourceCache(cache); if (httpContext != null) { httpContext.removeResourceCache(cache); } } /* * (non-Javadoc) * * @see com.adito.boot.Context#getHostname() */ public String getHostname() { return hostname; } /* * (non-Javadoc) * * @see com.adito.boot.Context#getPort() */ public int getPort() { return actualPort; } /* * (non-Javadoc) * * @see com.adito.boot.Context#addContextLoaderURL(java.net.URL) */ public void addContextLoaderURL(URL url) { doAddContextLoaderURL(url); } /* * (non-Javadoc) * * @see com.adito.boot.Context#registerRequestHandler(com.adito.boot.RequestHandler) */ public void registerRequestHandler(RequestHandler requestHandler) { registerRequestHandler(requestHandler, HandlerProtocol.HTTPS_PROTOCOL); } /* * (non-Javadoc) * * @see com.adito.boot.Context#deregisterRequestHandler(com.adito.boot.RequestHandler) */ public void deregisterRequestHandler(RequestHandler requestHandler) { if (httpContext != null) { httpContext.deregisterRequestHandler(requestHandler); } HTTPRedirectHandler.registerHandler(requestHandler); } private void registerKeyStores() throws Exception { getBootProgressMonitor().updateMessage("Registering key stores"); getBootProgressMonitor().updateProgress(7); String defaultKeyStorePassword = contextConfiguration .retrieveProperty(new ContextKey("webServer.keystore.sslCertificate.password")); KeyStoreManager.registerKeyStore(KeyStoreManager.DEFAULT_KEY_STORE, "keystore", true, defaultKeyStorePassword, KeyStoreManager.getKeyStoreType( contextConfiguration.retrieveProperty(new ContextKey("webServer.keyStoreType")))); KeyStoreManager.registerKeyStore(KeyStoreManager.SERVER_AUTHENTICATION_CERTIFICATES_KEY_STORE, "keystore", true, "adito", KeyStoreManager.TYPE_JKS); KeyStoreManager.registerKeyStore(KeyStoreManager.TRUSTED_SERVER_CERTIFICATES_KEY_STORE, "keystore", true, "adito", KeyStoreManager.TYPE_JKS); } private void clearTemp() { String currVer = PREF.get("lastTempClear", ""); if (currVer.equals("") || !currVer.equals(getVersion().toString()) || "true".equalsIgnoreCase(SystemProperties.get("adito.clearTemp"))) { getBootProgressMonitor().updateMessage("Clearing temporary files"); getBootProgressMonitor().updateProgress(3); if (log.isInfoEnabled()) log.info("Clearing temporary directory"); /* We have to leave the server.run and server.pid files alone as these are * used by external components to determine service state */ File[] files = getTempDirectory().listFiles(); if (files != null) { for (File file : files) { if (!file.getName().equals(ServerLock.LOCK_NAME) && !file.getName().equals(Branding.SERVICE_NAME + ".pid")) { Util.delTree(file); } } } else { if (!getTempDirectory().mkdirs()) { log.error("CRITICAL. Failed to create the temporary directory " + getTempDirectory() + "."); } } } PREF.put("lastTempClear", getVersion().toString()); } private void initialiseLogging() { URL resource = bootLoader.getResource("log4j.properties"); getBootProgressMonitor().updateMessage("Intialising logging"); getBootProgressMonitor().updateProgress(2); LOG_DIR.mkdirs(); InputStream in = null; try { if (resource == null) { throw new IOException("Could not locate log4j.properties"); } in = resource.openStream(); Properties p = new Properties(); p.load(in); p.setProperty("log4j.rootCategory", p.getProperty("log4j.rootCategory", "WARN,logfile") + (logToConsole ? ",stdout" : "")); Class.forName("org.apache.log4j.PropertyConfigurator", true, bootLoader) .getMethod("configure", new Class[] { Properties.class }).invoke(null, new Object[] { p }); } catch (Exception e) { } finally { Util.closeStream(in); } log = LogFactory.getLog(Main.class); } private void startHttpServer() throws Exception { int port = contextConfiguration.retrievePropertyInt(new ContextKey("webServer.httpRedirectPort")); if (port <= 0) { if (log.isInfoEnabled()) log.info("HTTP redirect port " + port + " is invalid"); return; } String bind = contextConfiguration.retrieveProperty(new ContextKey("webServer.bindAddress")); PropertyList l = new PropertyList(bind.equals("") ? "0.0.0.0" : bind); insecureServer = new Server(); for (Iterator<String> i = l.iterator(); i.hasNext();) { String address = i.next(); if (log.isInfoEnabled()) log.info("Adding listener on " + address + ":" + port); SocketListener listener = new SocketListener(); listener.setHost(address); listener.setPort(port); listener.setMinThreads( contextConfiguration.retrievePropertyInt(new ContextKey("webServer.minThreads"))); listener.setMaxThreads( contextConfiguration.retrievePropertyInt(new ContextKey("webServer.maxThreads"))); listener.setMaxIdleTimeMs(0); listener.setLowResourcePersistTimeMs(2000); listener.setAcceptQueueSize(0); listener.setPoolName("P2"); insecureServer.addListener(listener); } // Create the webapp HttpContext context = new HttpContext(); context.setContextPath("/"); context.setResourceBase("./dummy/"); context.addHandler(new HTTPRedirectHandler()); insecureServer.addContext(context); // Configure the server insecureServer.setRequestsPerGC(2000); insecureThread = new Thread(threadGroup, "InsecureWebServer") { public void run() { // Start the server try { insecureServer.start(); } catch (Exception e) { log.warn("Failed to start HTTP Jetty. " + e.getMessage(), e); } } }; if (log.isInfoEnabled()) log.info("Starting HTTP redirect server"); insecureThread.start(); } private void normalMode() throws Exception { getBootProgressMonitor().updateMessage("Creating server"); getBootProgressMonitor().updateProgress(8); if (log.isInfoEnabled()) log.info("Starting Jetty Web Server"); server = createServer(); // SunJsseListener listener = new SunJsseListener(); String keystorePassword = contextConfiguration .retrieveProperty(new ContextKey("webServer.keystore.sslCertificate.password")); if (keystorePassword.equals("")) { throw new Exception( "Private key / certificate password has not been set. Please run the Installation Wizard."); } actualPort = defaultPort == -1 ? contextConfiguration.retrievePropertyInt(new ContextKey("webServer.port")) : defaultPort; String bind = contextConfiguration.retrieveProperty(new ContextKey("webServer.bindAddress")); listeners = new ArrayList<SocketListener>(); PropertyList l = new PropertyList(bind.equals("") ? "0.0.0.0" : bind); for (Iterator<String> i = l.iterator(); i.hasNext();) { String address = i.next(); if (log.isInfoEnabled()) log.info("Adding listener on " + address + ":" + actualPort); if (!serverLock.isStarted()) { serverLock.start(actualPort); } SocketListener listener = null; if (contextConfiguration.retrieveProperty(new ContextKey("webServer.protocol")).equals("http")) { listener = new SocketListener(); log.warn("The server is configured to listen for plain HTTP connections."); } else { listener = new CustomJsseListener(keystorePassword); MsieSslHandler sslHandler = new MsieSslHandler(); sslHandler.setUserAgentSubString("MSIE 5"); listener.setHttpHandler(sslHandler); } listener.setPort(actualPort); listener.setMinThreads( contextConfiguration.retrievePropertyInt(new ContextKey("webServer.minThreads"))); listener.setMaxThreads( contextConfiguration.retrievePropertyInt(new ContextKey("webServer.maxThreads"))); listener.setMaxIdleTimeMs( contextConfiguration.retrievePropertyInt(new ContextKey("webServer.maxIdleTimeMs"))); listener.setHost(address); listener.setBufferSize( contextConfiguration.retrievePropertyInt(new ContextKey("webServer.bufferSize"))); listener.setBufferReserve( contextConfiguration.retrievePropertyInt(new ContextKey("webServer.bufferReserve"))); listener.setTcpNoDelay( contextConfiguration.retrievePropertyBoolean(new ContextKey("webServer.tcpNoDelay"))); listener.setThreadsPriority( contextConfiguration.retrievePropertyInt(new ContextKey("webServer.threadPriority"))); listeners.add(listener); listener.setLowResourcePersistTimeMs( contextConfiguration.retrievePropertyInt(new ContextKey("webServer.lowResourcePersistTimeMs"))); listener.setPoolName("main"); server.addListener(listener); } // Add the context getBootProgressMonitor().updateMessage("Creating web application"); getBootProgressMonitor().updateProgress(9); httpContext = new CustomHttpContext(server, "/", useDevConfig, bootLoader); httpContext.setRedirectNullPath(false); server.addContext(httpContext); // Dunny servlet handler for faking HttpServletRequest, // HttpServletResponse servletHandler = new ServletHandler(); servletHandler.initialize(httpContext); servletHandler.start(); // Add the webapp webappContext = new CustomWebApplicationContext(useDevConfig, bootLoader); addLifecycleListener(webappContext); server.addContext(webappContext); webappContext.setRedirectNullPath(false); // Configure the server server.setRequestsPerGC( contextConfiguration.retrievePropertyInt(new ContextKey("webServer.requestsPerGC"))); server.setTrace(false); // Set the request log if (contextConfiguration.retrievePropertyBoolean(new ContextKey("webServer.requestLog"))) { NCSARequestLog requestLog = new NCSARequestLog(jettyLog); requestLog.setRetainDays(90); requestLog.setAppend(true); requestLog.setExtended(false); requestLog.setBuffered(false); requestLog.setLogTimeZone("GMT"); server.setRequestLog(requestLog); } // Inform the wrapper the startup process is going ok if (useWrapper) { WrapperManager.signalStarting(60000); } mainThread = new Thread(threadGroup, "WebServer") { public void run() { // Start the server try { server.start(); if (useDevConfig) { log.warn("Server startup took " + ((System.currentTimeMillis() - startupStarted) / 1000) + " seconds"); } getBootProgressMonitor().updateMessage("Server is now running"); getBootProgressMonitor().updateProgress(100); Thread.sleep(2000); } catch (Exception e) { log.error("Failed to start Jetty. " + e.getMessage(), e); if (useWrapper) { WrapperManager.stop(1); } else { System.exit(1); } } finally { getBootProgressMonitor().dispose(); } } }; mainThread.start(); } /* * (non-Javadoc) * * @see com.adito.boot.Context#addWebApp(java.lang.String, * java.lang.String) */ public void addWebApp(String path, String warFile) throws Exception { log.info("Adding webapp '" + path + "' using path / war '" + warFile + "'"); HttpContext context = server.addWebApplication(path, warFile); context.start(); } private void setupMode() throws Exception { // Ensure that https redirect is not turned on in jetty System.setProperty("jetty.force.HTTPSRedirect", "false"); getBootProgressMonitor().updateMessage("Creating server"); getBootProgressMonitor().updateProgress(8); actualPort = defaultPort == -1 ? 28080 : defaultPort; serverLock.start(actualPort); server = createServer(); SocketListener socketListener = new SocketListener(); socketListener.setPort(actualPort); socketListener.setMinThreads(10); socketListener.setMaxThreads(200); socketListener.setMaxIdleTimeMs(0); socketListener.setLowResourcePersistTimeMs(2000); socketListener.setAcceptQueueSize(0); socketListener.setPoolName("P1"); server.addListener(socketListener); // // Add the context // HttpContext context = new CustomHttpContext(server, "/", // useDevConfig); // server.addContext(context); // Create the webapp getBootProgressMonitor().updateMessage("Creating web application"); getBootProgressMonitor().updateProgress(9); webappContext = new CustomWebApplicationContext(useDevConfig, bootLoader); webappContext.setRedirectNullPath(false); addLifecycleListener(webappContext); server.addContext(webappContext); // Configure the server server.setRequestsPerGC(2000); String realHostname = hostname == null ? InetAddress.getLocalHost().getHostName() : hostname; /* * If the 'Active DNS' feature is enabled, the DNS server may return the * wild-card name. This will probably fail. As a work-around, if the * hostname looks like a wildcard, then it is simply changed to * 'localhost'. */ if (realHostname.startsWith("*.")) { realHostname = "localhost"; } // final String fRealHostname = realHostname; final int realPort = defaultPort == -1 ? 28080 : defaultPort; // Inform the wrapper the startup process is going ok if (useWrapper) { WrapperManager.signalStarting(60000); } mainThread = new Thread(threadGroup, "WebServer") { public void run() { // Start the server try { server.start(); if (!useWrapper && !"true".equals(SystemProperties.get("adito.noBrowserLaunch"))) { try { BrowserLauncher.openURL("http://" + fRealHostname + ":" + realPort); System.out.println("A browser has been opened and pointed to http://" + fRealHostname + ":" + realPort + ". "); } catch (Exception ex) { System.out.println( "Point your browser to http://" + fRealHostname + ":" + realPort + ". "); } } else { System.out.println("Point your browser to http://" + fRealHostname + ":" + realPort + ". "); } System.out.println( "\nPress CTRL+C or use the 'Shutdown' option from the web interface to leave the installation wizard."); getBootProgressMonitor().updateMessage("Server is now running"); getBootProgressMonitor().updateProgress(100); Thread.sleep(2000); } catch (Exception e) { log.error("Failed to start Jetty. " + e.getMessage(), e); if (useWrapper) { WrapperManager.stop(1); } else { System.exit(1); } } finally { getBootProgressMonitor().dispose(); } } }; System.out.print("Starting installation wizard"); mainThread.start(); /* * Wait for up to 5 minutes for the server to become available we need * to wait this long because precompilation can take a while! */ int waitFor = 60 * 5; boolean running = false; if (!"true".equals(SystemProperties.get("adito.disableStartupCheck", "false"))) { int i = 0; for (; i < waitFor && !running; i++) { try { System.out.print("."); Socket s = new Socket(realHostname, realPort); s.close(); running = true; } catch (Exception ex) { try { Thread.sleep(1000); } catch (Exception ex2) { } } } System.out.println(); } else { running = true; } if (!running) { System.out.println("Failed to start installation wizard. Check the logs for more detail."); if (useWrapper) { WrapperManager.stop(1); } else { System.exit(1); } } } private void configureProxyServers() throws Exception { getBootProgressMonitor().updateMessage("Configuring proxy servers"); getBootProgressMonitor().updateProgress(5); String httpProxyHost = contextConfiguration.retrieveProperty(new ContextKey("proxies.http.proxyHost")); if (!httpProxyHost.equals("")) { if (log.isInfoEnabled()) log.info("Configuring outgoing HTTP connections to use a proxy server."); System.setProperty("http.proxyHost", httpProxyHost); System.setProperty("com.maverick.ssl.https.HTTPProxyHostname", httpProxyHost); String httpProxyPort = contextConfiguration.retrieveProperty(new ContextKey("proxies.http.proxyPort")); String httpProxyUsername = contextConfiguration .retrieveProperty(new ContextKey("proxies.http.proxyUser")); String httpProxyPassword = contextConfiguration .retrieveProperty(new ContextKey("proxies.http.proxyPassword")); System.setProperty("http.proxyPort", httpProxyPort); System.setProperty("com.maverick.ssl.https.HTTPProxyPort", httpProxyPort); if (!httpProxyUsername.trim().equals("")) System.setProperty("com.maverick.ssl.https.HTTPProxyUsername", httpProxyUsername.trim()); if (!httpProxyPassword.trim().equals("")) System.setProperty("com.maverick.ssl.https.HTTPProxyPassword", httpProxyPassword.trim()); System.setProperty("com.maverick.ssl.https.HTTPProxySecure", "false"); PropertyList list = contextConfiguration .retrievePropertyList(new ContextKey("proxies.http.nonProxyHosts")); StringBuffer hosts = new StringBuffer(); for (Iterator i = list.iterator(); i.hasNext();) { if (hosts.length() != 0) { hosts.append("|"); } hosts.append(i.next()); } System.setProperty("http.nonProxyHosts", hosts.toString()); System.setProperty("com.maverick.ssl.https.HTTPProxyNonProxyHosts", hosts.toString()); } String socksProxyHost = contextConfiguration.retrieveProperty(new ContextKey("proxies.socksProxyHost")); if (!socksProxyHost.equals("")) { if (log.isInfoEnabled()) log.info("Configuring outgoing TCP/IP connections to use a SOCKS proxy server."); System.setProperty("socksProxyHost", httpProxyHost); System.setProperty("socksProxyPort", contextConfiguration.retrieveProperty(new ContextKey("proxies.socksProxyPort"))); } if (!socksProxyHost.equals("") || !httpProxyHost.equals("")) { Authenticator.setDefault(new ProxyAuthenticator()); } } private Server createServer() throws MalformedURLException { Server server = new Server(); if (contextConfiguration.retrievePropertyBoolean(new ContextKey("webServer.stats"))) { new StatsLogger(server, contextConfiguration.retrievePropertyInt(new ContextKey("webServer.statsUpdate"))); } return server; } private void addLifecycleListener(final CustomWebApplicationContext context) { context.addEventListener(new LifeCycleListener() { public void lifeCycleFailure(LifeCycleEvent arg0) { } public void lifeCycleStarted(LifeCycleEvent arg0) { getBootProgressMonitor().updateMessage("Server is now running"); getBootProgressMonitor().updateProgress(100); try { Thread.sleep(500); } catch (InterruptedException e) { } } public void lifeCycleStarting(LifeCycleEvent arg0) { } public void lifeCycleStopped(LifeCycleEvent arg0) { } public void lifeCycleStopping(LifeCycleEvent arg0) { } }); } private void displaySystemInfo() throws SocketException { // if (useDevConfig) { log.warn("Development environment enabled. Do not use this on a production server."); } if (log.isInfoEnabled()) { log.info("Version is " + ContextHolder.getContext().getVersion()); log.info("Java version is " + SystemProperties.get("java.version")); log.info("Server is installed on " + hostname + "/" + hostAddress); log.info("Configuration: " + CONF_DIR.getAbsolutePath()); } if (SystemProperties.get("java.vm.name", "").indexOf("GNU") > -1 || SystemProperties.get("java.vm.name", "").indexOf("libgcj") > -1) { System.out.println("********** WARNING **********"); System.out.println("The system has detected that the Java runtime is GNU/GCJ"); System.out.println("Adito does not work correctly with this Java runtime"); System.out.println("you should reconfigure with a different runtime"); System.out.println("*****************************"); log.warn("********** WARNING **********"); log.warn("The system has detected that the Java runtime is GNU/GCJ"); log.warn("Adito may not work correctly with this Java runtime"); log.warn("you should reconfigure with a different runtime"); log.warn("*****************************"); } Enumeration e = NetworkInterface.getNetworkInterfaces(); while (e.hasMoreElements()) { NetworkInterface netface = (NetworkInterface) e.nextElement(); if (log.isInfoEnabled()) log.info("Net interface: " + netface.getName()); Enumeration e2 = netface.getInetAddresses(); while (e2.hasMoreElements()) { InetAddress ip = (InetAddress) e2.nextElement(); if (log.isInfoEnabled()) log.info("IP address: " + ip.toString()); } } if (log.isInfoEnabled()) log.info("System properties follow:"); Properties sysProps = System.getProperties(); for (Iterator i = sysProps.entrySet().iterator(); i.hasNext();) { Map.Entry entry = (Map.Entry) i.next(); int idx = 0; String val = (String) entry.getValue(); while (true) { if (entry.getKey().equals("java.class.path")) { StringTokenizer t = new StringTokenizer(entry.getValue().toString(), SystemProperties.get("path.separator", ",")); while (t.hasMoreTokens()) { String s = t.nextToken(); if (log.isInfoEnabled()) log.info("java.class.path=" + s); } break; } else { if ((val.length() - idx) > 256) { if (log.isInfoEnabled()) log.info(" " + entry.getKey() + "=" + val.substring(idx, idx + 256)); idx += 256; } else { if (log.isInfoEnabled()) log.info(" " + entry.getKey() + "=" + val.substring(idx)); break; } } } } } private void loadSystemProperties() { getBootProgressMonitor().updateMessage("Loading system properties"); getBootProgressMonitor().updateProgress(1); /* * Read in system properties from a resource, more a debugging aid than * anything else */ InputStream in = null; try { File f = new File(CONF_DIR, "system.properties"); in = new FileInputStream(f); Properties p = new Properties(); p.load(in); for (Enumeration e = p.keys(); e.hasMoreElements();) { String k = (String) e.nextElement(); System.getProperties().setProperty(k, p.getProperty(k).trim()); } } catch (IOException e) { // Dont care } finally { if (in != null) { try { in.close(); } catch (IOException ioe) { } } } /** * Set the prefix if any. */ SystemProperties.setPrefix(System.getProperty("boot.propertyPrefix")); /** * Are we in development mode? */ useDevConfig = "true".equalsIgnoreCase(SystemProperties.get("adito.useDevConfig")); if (!"".equals(SystemProperties.get("adito.extensions", ""))) { appDir = new File(SystemProperties.get("adito.extensions")); } // System.setProperty("org.mortbay.jetty.servlet.SessionCookie", SystemProperties.get("adito.cookie", "JSESSIONID")); System.setProperty("org.mortbay.jetty.servlet.SessionURL", SystemProperties.get("adito.cookie", "JSESSIONID").toLowerCase()); } private Integer parseCommandLine(String[] args) { defaultPort = -1; logToConsole = false; jettyLog = "logs/yyyy_mm_dd.request.log"; boolean fullReset = false; String os = System.getProperty("os.name").toLowerCase(); gui = "true".equals(System.getProperty("adito.useDevConfig")) && os.startsWith("windows"); try { for (int i = 0; i < args.length; i++) { if (args[i].equals("--manager")) { System.err.println( "The database manager can no longer be started via the server command line. Run it directly from hsqldb.jar ensuring you have the webapp classes included in your class path."); return new Integer(1); } else if (args[i].equals("--setup")) { System.err.println("WARNING: --setup is deprecated, please use --install"); install = true; } else if (args[i].equals("--install")) { install = true; } else if (args[i].equals("--logToConsole")) { logToConsole = true; } else if (args[i].equals("--gui")) { if (os.startsWith("windows")) { gui = true; } else if (os.equals("linux") || os.equals("solaris") || os.endsWith("aix")) { String displaySysProp = SystemProperties.get("adito.display", ""); String display = null; try { display = displaySysProp.equals("") ? System.getenv("DISPLAY") : displaySysProp; } catch (Throwable t) { } gui = display != null && display.length() > 0; } } else if (args[i].startsWith("--db")) { DB_DIR = new File(args[i].substring(5)); if (DB_DIR.exists() && !DB_DIR.isDirectory()) { throw new Exception( "--db option specifies an existing file, must either not exist or be a directory"); } } else if (args[i].startsWith("--applications")) { appDir = new File(args[i].substring(15)); if (appDir.exists() && !appDir.isDirectory()) { throw new Exception( "--db option specifies an existing file, must either not exist or be a directory"); } } else if (args[i].startsWith("--temp")) { TMP_DIR = new File(args[i].substring(7)); if (TMP_DIR.exists() && !TMP_DIR.isDirectory()) { throw new Exception( "--temp option specifies an existing file, must either not exist or be a directory"); } } else if (args[i].startsWith("--conf")) { CONF_DIR = new File(args[i].substring(7)); if (!CONF_DIR.exists() || !CONF_DIR.isDirectory()) { throw new Exception("--conf option does not specify a valid directory"); } } else if (args[i].startsWith("--port")) { defaultPort = Integer.parseInt(args[i].substring(7)); } else if (args[i].startsWith("--jettyLog")) { jettyLog = args[i].substring(11); } else if (args[i].equals("--full-reset")) { fullReset = true; } else if (args[i].startsWith("start")) { // For compatibility with the install4j launcher } else { System.err.println("Starts / configures the server.\n"); System.err.println("Usage: adito [OPTION]..."); System.err.println("\nThe server may be started in setup or normal mode. When setup.\n"); System.err.println("mode is enabled a plain http server will be started on port 28080\n"); System.err.println("allowing you configure using a browser.\n\n"); System.out.println("Options:\n"); System.out.println(" --install Start the server in installation mode."); System.out.println(" --full-reset Deletes *all* configuration data and resets"); System.out.println(" the server to its initial state. Use with"); System.out.println(" greate caution."); System.out.println(" --db=DIR Set the directory where the configuration"); System.out.println(" database is stored."); System.out.println(" --conf=DIR Set the directory where the configuration"); System.out.println(" files are stored."); System.out.println(" --temp=DIR Set the directory where the temporary"); System.out.println(" files are stored."); System.out.println(" --port=NUMBER The port on which the server will start."); System.out.println(" Note that this applies to both setup and"); System.out.println(" normal mode and will overide whatever port"); System.out.println(" been configured."); System.out.println(" --jettyLog=LOG The location of the Jetty NCSA request log."); System.out.println("\nInvalid option: " + args[i] + ".\n"); return new Integer(2); } } // Create the temporary directory if (!TMP_DIR.exists()) { if (!TMP_DIR.mkdirs()) { throw new Exception("Could not create temporary directory " + TMP_DIR.getAbsolutePath() + "."); } } } catch (Exception e) { System.err.println(e.getMessage()); return new Integer(2); } // Perform a full reset if (fullReset) { if (fullReset()) { System.err.println("Configuration has been fully reset"); return new Integer(0); } else { System.err.println("Aborted full reset."); return new Integer(1); } } // Another way for external processes to force starting installation // wizard if (new File(TMP_DIR, "setup.run").exists()) { install = true; } return null; } /* * Perform a full reset */ private boolean fullReset() { if (gui) { if (JOptionPane.showConfirmDialog(null, "The embedded configuration database will be\n" + "completely deleted and re-created the next\ntime you run the server. Are you absolutely\n" + "sure you wish to do this?", "Full Reset", JOptionPane.WARNING_MESSAGE, JOptionPane.YES_NO_OPTION) != JOptionPane.OK_OPTION) { return false; } } else { System.out.println("The embedded configuration database will be"); System.out.println("completely deleted and re-created the next"); System.out.println("time you run the server. Are you absolutely"); System.out.println("sure you wish to do this?"); System.out.println(); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); while (true) { System.out.print("(Y)es or (N)o: "); String s; try { s = br.readLine(); if (s == null) { return false; } if (s.toLowerCase().equals("y") || s.toLowerCase().equals("yes")) { break; } if (s.toLowerCase().equals("n") || s.toLowerCase().equals("no")) { return false; } System.out.println( "\nPlease answer 'y' or 'yes' to perform the reset, or 'n' or 'no' to abort the reset."); } catch (IOException e) { return false; } } } // Start the reset System.out.println("Resetting all configuration"); File[] f = getDBDirectory().listFiles(); if (f != null) { for (int i = 0; i < f.length; i++) { if (!f[i].getName().equals("CVS") && !f[i].equals(".cvsignore")) { System.out.println(" Deleting " + f[i].getPath()); if (!f[i].delete()) { System.out.println(" Failed to remove"); } } } } return true; } /* * (non-Javadoc) * * @see com.adito.boot.Context#deobfuscatePassword(java.lang.String) */ public String deobfuscatePassword(String val) { try { return Password.deobfuscate(val); } catch (Exception e) { return ""; } } /* * (non-Javadoc) * * @see com.adito.boot.Context#obfuscatePassword(java.lang.String) */ public String obfuscatePassword(String val) { return Password.obfuscate(val); } /* * (non-Javadoc) * * @see com.adito.boot.Context#setTrustManager(javax.net.ssl.TrustManager) */ public void setTrustManager(TrustManager trustManager, boolean require) { if (listeners == null || listeners.size() == 0) { log.warn("Not setting trust managers there are no SSL listeners configured."); } else { if (log.isInfoEnabled()) log.info("Set trust managers"); for (Iterator i = listeners.iterator(); i.hasNext();) { SocketListener l = (SocketListener) i.next(); if (l instanceof CustomJsseListener) { ((CustomJsseListener) l).setNeedClientAuth(trustManager != null); ((CustomJsseListener) l).setTrustManager(trustManager, require); } } } } /* * (non-Javadoc) * * @see com.adito.boot.Context#addContextListener(com.adito.boot.ContextListener) */ public void addContextListener(ContextListener contextListener) { contextListeners.add(contextListener); } /* * (non-Javadoc) * * @see com.adito.boot.Context#removeContextListener(com.adito.boot.ContextListener) */ public void removeContextListener(ContextListener contextListener) { contextListeners.remove(contextListener); } /* * (non-Javadoc) * * @see com.adito.boot.Context#getPreferences() */ public Preferences getPreferences() { return PREF; } /* * (non-Javadoc) * * @see com.adito.boot.Context#getContextLoaderClassPath() */ public URL[] getContextLoaderClassPath() { List<URL> urlList = new ArrayList<URL>(); ClassLoader webappContextClassLoader = webappContext.getClassLoader(); while (webappContextClassLoader != null) { if (webappContextClassLoader != null && webappContextClassLoader instanceof URLClassLoader) { urlList.addAll(Arrays.asList(((URLClassLoader) webappContextClassLoader).getURLs())); } webappContextClassLoader = webappContextClassLoader.getParent(); } URL[] urls = (URL[]) urlList.toArray(new URL[urlList.size()]); return urls; } /* * (non-Javadoc) * * @see com.adito.boot.Context#getContextLoader() */ public ClassLoader getContextLoader() { return webappContext.getClassLoader(); } public void removeResourceAlias(String uri) { webappContext.removeResourceAlias(uri); } /* * (non-Javadoc) * * @see com.adito.boot.Context#getResourceBases() */ public Collection<URL> getResourceBases() { return resourceCaches.keySet(); } /* * (non-Javadoc) * * @see com.adito.boot.Context#getBootProgressMonitor() */ public BootProgressMonitor getBootProgressMonitor() { return bootProgressMonitor; } public void registerRequestHandler(RequestHandler requestHandler, HandlerProtocol protocol) { if (httpContext != null) { if (protocol == HandlerProtocol.HTTPS_PROTOCOL || protocol == HandlerProtocol.BOTH_PROTOCOLS) httpContext.registerRequestHandler(requestHandler); } if (protocol == HandlerProtocol.HTTP_PROTOCOL || protocol == HandlerProtocol.BOTH_PROTOCOLS) { HTTPRedirectHandler.registerHandler(requestHandler); } } public HttpServletRequest createServletRequest(RequestHandlerRequest request) { if (request instanceof com.adito.server.jetty.RequestAdapter) { ServletHttpRequest req = new ServletHttpRequest(servletHandler, request.getPath(), ((com.adito.server.jetty.RequestAdapter) request).getHttpRequest()); return req; } else throw new IllegalArgumentException("Request must be RequestAdapter"); } public HttpServletResponse createServletResponse(RequestHandlerResponse response, HttpServletRequest request) { if (response instanceof com.adito.server.jetty.ResponseAdapter) { ServletHttpResponse res = new ServletHttpResponse((ServletHttpRequest) request, ((com.adito.server.jetty.ResponseAdapter) response).getHttpResponse()); ((ServletHttpRequest) request).getSession(true); return res; } else throw new IllegalArgumentException("Response must be ResponseAdapter"); } private void doAddContextLoaderURL(URL u) { try { Class sysclass = URLClassLoader.class; Method method = sysclass.getDeclaredMethod("addURL", new Class[] { URL.class }); method.setAccessible(true); method.invoke(webappContext.getClassLoader(), new Object[] { u }); if (log.isInfoEnabled()) log.info(u.toExternalForm() + " added to context classloader"); } catch (Exception e) { log.error("Failed to add to classpath.", e); } } /* * (non-Javadoc) * * @see com.adito.boot.Context#access(javax.servlet.http.HttpSession) */ public void access(HttpSession session) { ((SessionManager.Session) session).access(); } }