/*
Wotonomy: OpenStep design patterns for pure Java applications.
Copyright (C) 2000 Blacksmith, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see http://www.gnu.org
*/
package net.wotonomy.web;
import java.lang.reflect.Constructor;
import java.util.List;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import net.wotonomy.foundation.NSArray;
import net.wotonomy.foundation.NSDictionary;
import net.wotonomy.foundation.NSMutableDictionary;
import net.wotonomy.web.util.BrowserLauncher;
/**
* A pure java implementation of WOApplication.
*
*
* The application is responsible for creating and managing sessions and
* dispatching requests to the appropriate handlers.
*
*
* This implementation extends HttpServlet, so the application itself is a
* servlet and can be configured and managed as such by the servlet container.
*
* @author michael@mpowers.net
* @author $Author: cgruber $
* @version $Revision: 905 $
*/
public class WOApplication extends HttpServlet {
/**
* A tricky way to allow multiple WOApplications in the same servlet container.
*/
static private ThreadLocal threadLocal;
// static private WOApplication application;
/**
* Determines application-wide page caching. Pages may individually prevent
* caching.
*/
static private boolean cachingEnabled = false;
private static boolean autoOpenInBrowser = true;
private String name;
private WORequestHandler defaultRequestHandler;
private NSMutableDictionary requestHandlers;
private WOSessionStore sessionStore;
private WOResourceManager resourceManager;
private boolean pageRefreshOnBacktrack;
private int pageCacheSize;
private int permanentPageCacheSize;
public static final String WOApplicationWillFinishLaunchingNotification = "WOApplicationWillFinishLaunchingNotification";
public static final String WOApplicationDidFinishLaunchingNotification = "WOApplicationDidFinishLaunchingNotification";
public static final String WOGarbageCollectionPeriodKey = "WOGarbageCollectionPeriodKey";
static String _DirectActionRequestHandlerKey = "_DirectActionRequestHandlerKey";
static String _ComponentRequestHandlerKey = "_ComponentRequestHandlerKey";
static String _ResourceRequestHandlerKey = "_ResourceRequestHandlerKey";
static String WOPort = "WOPort";
static String WOSMTPHost = "WOSMTPHost";
static final String ELEMENT_CLASS = "elementClass";
public WOApplication() {
if (threadLocal == null) {
threadLocal = new ThreadLocal();
}
threadLocal.set(this);
// application = this;
resourceManager = createResourceManager();
requestHandlers = new NSMutableDictionary();
defaultRequestHandler = new WODirectActionRequestHandler();
registerRequestHandler(defaultRequestHandler, directActionRequestHandlerKey());
registerRequestHandler(new WOComponentRequestHandler(), componentRequestHandlerKey());
registerRequestHandler(new WOResourceRequestHandler(), resourceRequestHandlerKey());
sessionStore = WOSessionStore.serverSessionStore();
pageRefreshOnBacktrack = true;
pageCacheSize = 30;
permanentPageCacheSize = 30;
threadLocal.set(null);
}
/**
* Dispatches the request and updates the specified response as appropriate.
* This implementation creates a new WORequest and WOContext from the request,
* sends the response to the appropriate WORequestHandler, and then updates the
* servlet response from the resulting WOResponse.
*/
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, java.io.IOException {
threadLocal.set(this);
WORequest request = new WORequest(req, this);
WOResponse response = dispatchRequest(request);
response.generateServletResponse(resp);
}
/**
* Handles post requests by calling doGet(), since the framework handles both
* gets and posts similarly. Override to handle post requests in a different
* manner.
*/
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, java.io.IOException {
doGet(req, resp);
}
// obtaining attributes
/**
* Returns the singleton instance of this application.
*/
public static WOApplication application() {
return (WOApplication) threadLocal.get();
// return application;
}
/**
* Returns the name of the application. This implementation returns the name the
* jar file or directory from which the class was loaded, with no extensions.
*/
public String name() {
if (name == null) {
name = path();
int i;
if (name.endsWith("/")) { // path
name = name.substring(0, name.length() - 1);
} else { // jar file
i = name.lastIndexOf('.');
if (i != -1)
name = name.substring(0, i);
}
i = name.lastIndexOf('/');
if (i != -1)
name = name.substring(i + 1);
}
return name;
}
/**
* Returns the absolute path to the application on the local file system. Note
* that the application might be embedded inside of a jar file.
*/
public String path() {
return getClass().getProtectionDomain().getCodeSource().getLocation().toString();
}
/**
* Returns the path to the application on the local file system relative to the
* server's document root.
*/
public String baseURL() {
String root = getServletContext().getRealPath("/");
String result = path();
if (result.endsWith("/")) { // path
if (result.startsWith(root)) { // relative to root
result = result.substring(root.length());
}
// else leave as absolute reference
}
// jar or war file: leave as absolute reference
return result;
}
// concurrent request handling
/**
* Returns whether this application allows request to be handled concurrently.
* This implementation returns true. Subclasses may override to return false to
* force single-threaded request handling, although this is not implemented.
*/
public boolean allowsConcurrentRequestHandling() {
return true;
}
/**
* Returns whether this application allows request to be handled concurrently.
* This implementation returns true.
*/
public boolean adaptorsDispatchRequestsConcurrently() {
return true;
}
/**
* Returns whether this application allows request to be handled concurrently.
* This implementation returns true.
*/
public boolean isConcurrentRequestHandlingEnabled() {
return true;
}
// handling requests
/**
* Invoked first in the request-response cycle. Override to perform any kind of
* initialization at the start of a request. This implementation does nothing.
*/
public void awake() {
}
/**
* Invoked to start the first phase of the request-response cycle, after all
* calls to awake() have been completed.
*/
public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
aContext.session().takeValuesFromRequest(aRequest, aContext);
}
/**
* Invoked to start the second phase of the request-response cycle, after all
* calls to takeValuesFromRequest have finished.
*/
public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
return aContext.session().invokeAction(aRequest, aContext);
}
/**
* Invoked to start the third phase of the request-response cycle, after
* invokeAction() has completed and returned a WOResponse.
*/
public void appendToResponse(WOResponse aResponse, WOContext aContext) {
aContext.session().appendToResponse(aResponse, aContext);
}
/**
* Invoked last in the request-response cycle. Override to perform any kind of
* clean-up at the end of a request. This implementation does nothing.
*/
public void sleep() {
}
/**
* Dispatches the request to the appropriate handler.
*/
public WOResponse dispatchRequest(WORequest aRequest) {
return handlerForRequest(aRequest).handleRequest(aRequest);
}
// request handling
/**
* Returns the default request handler used if the requested handler isn't
* specified or cannot be found. (This defaults to the
* WODirectActionRequestHandler.)
*/
public WORequestHandler defaultRequestHandler() {
return defaultRequestHandler;
}
/**
* Sets the default request handler used if the requested handler isn't
* specified or cannot be found.
*/
public void setDefaultRequestHandler(WORequestHandler aRequestHandler) {
defaultRequestHandler = aRequestHandler;
}
/**
* Registers the specified request handler for the specified key.
*/
public void registerRequestHandler(WORequestHandler aRequestHandler, String aKey) {
requestHandlers.setObjectForKey(aRequestHandler, aKey);
}
/**
* Unregisters any existing request handler for the specified key returning the
* existing request handler, if any.
*/
public WORequestHandler removeRequestHandlerForKey(String aKey) {
WORequestHandler result = requestHandlerForKey(aKey);
requestHandlers.removeObjectForKey(aKey);
return result;
}
/**
* Returns the keys under which request handlers are registered.
*/
public NSArray registeredRequestHandlerKeys() {
return requestHandlers.allKeys();
}
/**
* Returns the request handler registered for the specified key, or null if no
* request handler is registered for that key.
*/
public WORequestHandler requestHandlerForKey(String aKey) {
return (WORequestHandler) requestHandlers.objectForKey(aKey);
}
/**
* Returns the request handler that would best service the specified request.
*/
public WORequestHandler handlerForRequest(WORequest aRequest) {
WORequestHandler result = requestHandlerForKey(aRequest.requestHandlerKey());
if (aRequest == null)
result = defaultRequestHandler();
return result;
}
// handling errors
public WOResponse handleSessionCreationErrorInContext(WOContext aContext) {
WOResponse response = new WOResponse();
response.setStatus(500); // internal server error
// TODO: add more useful information to the response
System.err.println("Failed to create session: " + aContext);
new RuntimeException().printStackTrace(); // remove me
return response;
}
public WOResponse handleSessionRestorationErrorInContext(WOContext aContext) {
WOResponse response = new WOResponse();
response.setStatus(500); // internal server error
// TODO: add more useful information to the response
System.err.println("Failed to restore session: " + aContext);
new RuntimeException().printStackTrace(); // remove me
return response;
}
public WOResponse handlePageRestorationErrorInContext(WOContext aContext) {
WOResponse response = new WOResponse();
response.setStatus(500); // internal server error
// TODO: add more useful information to the response
System.err.println("Failed to restore page: " + aContext);
new RuntimeException().printStackTrace(); // remove me
return response;
}
public WOResponse handleException(Throwable aThrowable, WOContext aContext) {
WOResponse response = new WOResponse();
response.setStatus(500); // internal server error
System.err.println("Exception occurred: " + aContext);
if (aThrowable.getMessage() != null) {
response.appendContentString(aThrowable.getMessage());
aThrowable.printStackTrace();
} else {
response.appendContentString(aThrowable.toString());
aThrowable.printStackTrace();
}
aThrowable.printStackTrace();
return response;
}
// managing pages
/**
* Sets the number of pages that will be retained in the user's session. Set to
* zero to disable page caching.
*/
public void setPageCacheSize(int aPositiveInt) {
pageCacheSize = aPositiveInt;
}
/**
* Returns the number of pages that will be retained in the user's session. The
* default page cache size is 30.
*/
public int pageCacheSize() {
return pageCacheSize;
}
/**
* Returns the number of pages that will be retained in the longer-term
* "permanent" page cache in the user's session, which is typically used for
* navigation bars in frames, etc. The default permanent page cache size is 30.
*/
public int permanentPageCacheSize() {
return permanentPageCacheSize;
}
/**
* Returns the number of pages that will be retained in the longer-term
* "permanent" page cache in the user's session, which is typically used for
* navigation bars in frames, etc. Set to zero to disable permanent page
* caching.
*/
public void setPermanentPageCacheSize(int aPositiveInt) {
permanentPageCacheSize = aPositiveInt;
}
/**
* Returns whether a "backtrack" for an existing page should simply call
* generateResponse() on the existing page instance. If false, a new page is
* created instead. The default is true.
*/
public void setPageRefreshOnBacktrackEnabled(boolean enabled) {
pageRefreshOnBacktrack = enabled;
}
/**
* Returns whether a "backtrack" for an existing page should simply call
* generateResponse() on the existing page instance. If false, a new page is
* created instead. The default is true.
*/
public boolean isPageRefreshOnBacktrackEnabled() {
return pageRefreshOnBacktrack;
}
// managing sessions
/**
* Sets the session store used by this application to persist sessions between
* request-response transactions.
*/
public void setSessionStore(WOSessionStore aSessionStore) {
sessionStore = aSessionStore;
}
/**
* Returns the session store used by this application to persist sessions
* between request-response transactions.
*/
public WOSessionStore sessionStore() {
return sessionStore;
}
/**
* Called at the end of the request-response cycle to persist the current
* session until the user's next request.
*/
public void saveSessionForContext(WOContext aContext) {
sessionStore.saveSessionForContext(aContext);
}
/**
* Called at the beginning of the request-response cycle to obtain the current
* session from the user's last request. Returns null if no such session has
* been created. This method sets the context of the session to the specified
* context.
*/
public WOSession restoreSessionWithID(String aSessionID, WOContext aContext) {
WORequest request = aContext.request();
WOSession session = sessionStore.restoreSessionWithID(aSessionID, request);
if (session != null) {
session.setContext(aContext);
session.setServletSession(request.servletRequest().getSession());
}
return session;
}
/**
* Called to create a session for a new request. This implementation looks for a
* class in the same package as the application class called "Session" and
* failing that returns a WOSession.
*/
public WOSession createSessionForRequest(WORequest aRequest) {
WOSession result = null;
try {
// using our class loader, which is hopefully dynamic.
result = (WOSession) getLocalClass("Session").newInstance();
} catch (Throwable t) {
// ignore: fall back to WOSession
// t.printStackTrace();
}
if (result == null) {
result = new WOSession();
}
result.setServletSession(aRequest.servletRequest().getSession(true));
return result;
}
/**
* Returns the page component with the specified name. A context is created with
* the specified request, along with a session if necessary.
*/
public WOComponent pageWithName(String aName, WORequest aRequest) {
return pageWithName(aName, WOContext.contextWithRequest(aRequest));
}
/**
* Called to retrieve a component for the specified context.
*/
public WOComponent pageWithName(String aName, WOContext aContext) {
if (aName == null) {
throw new IllegalArgumentException("WOApplication.pageWithName: name is null");
}
WOComponent result = null;
try {
// using our class loader, which is hopefully dynamic.
Class c = getLocalClass(aName);
if (c != null) {
// get constructor
Constructor ctor;
try {
ctor = c.getConstructor(new Class[] { WOContext.class });
} catch (NoSuchMethodException nsme) {
ctor = null;
}
// create instance of class
if (ctor != null) {
result = (WOComponent) ctor.newInstance(new Object[] { aContext });
} else // call back on default constructor (deprecated)
{
result = (WOComponent) c.newInstance();
}
}
} catch (Throwable t) {
// ignore for now
// TODO: Throw appropriate exception here
// System.err.println( "Not found: pageWithName: " + aName );
t.printStackTrace();
}
if (result != null && aContext != null) {
// this is where components get their context
result.ensureAwakeInContext(aContext);
} else if (result == null) {
System.err.println("Not found: pageWithName: " + aName);
}
return result;
}
/**
* Returns a class in the same package as the Application class, or, failing
* that, from the WOApplication package, or finally from the root of the class
* path. Returns null if not found.
*/
Class getLocalClass(String aName) {
Class result = null;
if (getClass() != WOApplication.class) {
result = loadLocalClass(getClass(), aName);
}
if (result == null) {
result = loadLocalClass(WOApplication.class, aName);
}
if (result == null) {
result = loadLocalClass(null, aName);
}
return result;
}
private static final Class loadLocalClass(Class aClass, String aName) {
ClassLoader loader;
String packageName = "";
if (aClass != null) {
loader = aClass.getClassLoader();
packageName = aClass.getName();
int index = packageName.lastIndexOf(".");
if (index > -1) {
packageName = packageName.substring(0, index + 1);
} else {
packageName = "";
}
} else {
loader = WOApplication.class.getClassLoader();
}
try {
return loader.loadClass(packageName + aName);
} catch (ClassNotFoundException e) {
return null;
}
}
// creating elements
/**
* Returns either a dynamic element or a component for the specified name.
*/
public WOElement dynamicElementWithName(String anElementName, NSDictionary anAssociationMap, WOElement aBodyElement,
List aLanguageList) {
WOElement element = null;
Class c = null;
try {
c = getLocalClass(anElementName);
if (c == null) {
System.out.println("Not found: dynamicElementWithName: " + "could not find WODynamicElement subclass: "
+ anElementName);
c = WODynamicElement.class;
}
// get constructor
Class[] params = new Class[] { String.class, NSDictionary.class, WOElement.class };
Constructor ctor = c.getConstructor(params);
// create instance of class
if (ctor != null) {
element = (WODynamicElement) ctor
.newInstance(new Object[] { anElementName, anAssociationMap, aBodyElement });
}
} catch (Throwable t) {
// ignore: not a dynamic element
// System.out.println( "Not a dynamic element: dynamicElementWithName: " + t );
// exc.printStackTrace();
}
// no dynamic element found: look for a component
if (element == null) {
WOComponent component = (WOComponent) pageWithName(anElementName, (WOContext) null);
// this seems hackish:
// I don't see another way of setting the bindings.
component.associations = anAssociationMap;
component.rootElement = aBodyElement;
element = component;
}
return element;
}
// resource handling
/**
* Called to create the application's resource manager. Override to create a
* custom resource manager.
*/
public WOResourceManager createResourceManager() {
return new WOResourceManager();
}
/**
* Returns the application's current resource manager.
*/
public WOResourceManager resourceManager() {
return resourceManager;
}
/**
* Installs a custom resource manager into the current application.
*
* @deprecated Override createResourceManager() instead.
*/
public void setResourceManager(WOResourceManager aResourceManager) {
resourceManager = aResourceManager;
}
/*
* // request handling undocumented
*
* public WOComponent pageWithName (String); public void savePage (WOComponent);
* public WOComponent restorePageForContextID (String); public WOContext context
* (); public WOSession session (); public WOSession createSession (); public
* WOSession restoreSession (); public void saveSession (WOSession);
*
* public WOResponse handleRequest (WORequest aRequest) { }
*
* // error handling undocumented
*
* WOResponse handleSessionCreationError (); WOResponse
* handleSessionRestorationError (); WOResponse handlePageRestorationError ();
* WOResponse handleException (Throwable);
*
* // running
*
* public NSRunLoop runLoop (); public void run (); public void setTimeOut
* (double); public double timeOut (); public void terminate (); public boolean
* isTerminating ();
*
* // script debugging
*
* public void traceScriptedMessages (boolean); public void traceAssignments
* (boolean); public void traceStatements (boolean); public void
* traceObjectiveCMessages (boolean); public void trace (boolean); public void
* logTakeValueForDeclarationNamed (String, String, String, String, Object);
* public void logSetValueForDeclarationNamed (String, String, String, String,
* Object);
*
* // script handling
*
* public String scriptedClassNameWithPath (String); public String
* scriptedClassNameWithPathEncoding (String, int);
*
* // statistics report
*
* public void setStatisticsStore (WOStatisticsStore); public WOStatisticsStore
* statisticsStore (); public NSDictionary statistics ();
*
* // managing adaptors
*
* public WOAdaptor adaptorWithName (String, NSDictionary); public NSArray
* adaptors ();
*
* // monitor support
*
* public boolean monitoringEnabled (); public int activeSessionsCount ();
* public void refuseNewSessions (boolean); public boolean isRefusingNewSessions
* (); public void setMinimumActiveSessionsCount (int); public int
* minimumActiveSessionsCount (); public void terminateAfterTimeInterval
* (double);
*
* // garbage collection undocumented
*
* int garbageCollectionPeriod (); void setGarbageCollectionPeriod (int);
*
* // backwards compatibility
*
* public boolean requiresWOF35RequestHandling (); public boolean
* requiresWOF35TemplateParser ();
*
* public void setPrintsHTMLParserDiagnostics (boolean); public boolean
* printsHTMLParserDiagnostics ();
*
* // configuration and defaults
*
* public static NSArray loadFrameworks (); public static void setLoadFrameworks
* (NSArray);
*/
static boolean debuggingEnabled = false;
/**
* Returns whether the application is in "debug mode".
*/
public static boolean isDebuggingEnabled() {
return debuggingEnabled;
}
/**
* Sets whether the application is in "debug mode".
*/
public static void setDebuggingEnabled(boolean enabled) {
debuggingEnabled = enabled;
}
/**
* Sets whether templates are cached. If true, templates will only be read once
* per application lifetime. Otherwise, templates will be read each time this
* class is instantiated. Defaults to false.
*/
public static void setCachingEnabled(boolean enabled) {
cachingEnabled = enabled;
}
/**
* Returns whether templates are cached. If true, templates are read once per
* application lifetime. Otherwise, templates are read each time this class is
* instantiated.
*/
public static boolean isCachingEnabled() {
return cachingEnabled;
}
// configuration
/**
* Returns the component request handler key, which is defined by the system
* property _ComponentRequestHandlerKey. The default is "wo".
*/
public static String componentRequestHandlerKey() {
return System.getProperty(_ComponentRequestHandlerKey, "wo");
}
/**
* Sets the component request handler key.
*
* @deprecated Set the system property _ComponentRequestHandlerKey.
*/
public static void setComponentRequestHandlerKey(String aKey) {
System.setProperty(_ComponentRequestHandlerKey, aKey);
}
/**
* Returns the direct action request handler key, which is defined by the system
* property _DirectActionRequestHandlerKey. The default is "wa".
*/
public static String directActionRequestHandlerKey() {
return System.getProperty(_DirectActionRequestHandlerKey, "wa");
}
/**
* Sets the direct action request handler key.
*
* @deprecated Set the system property _DirectActionRequestHandlerKey.
*/
public static void setDirectActionRequestHandlerKey(String aKey) {
System.setProperty(_DirectActionRequestHandlerKey, aKey);
}
/**
* Returns the resource request handler key, which is defined by the system
* property _ResourceRequestHandlerKey. The default is "wr".
*/
public static String resourceRequestHandlerKey() {
return System.getProperty(_ResourceRequestHandlerKey, "wr");
}
/**
* Sets the resource request handler key.
*
* @deprecated Set the system property _ResourceRequestHandlerKey.
*/
public static void setResourceRequestHandlerKey(String aKey) {
System.setProperty(_ResourceRequestHandlerKey, aKey);
}
/**
* Returns whether this application should attempt to open a web browser on the
* host machine when launched standalone. The default is true.
*/
public static boolean autoOpenInBrowser() {
return autoOpenInBrowser;
}
/**
* Sets whether this application should attempt to open a web browser on the
* host machine when launched standalone.
*/
public static void setAutoOpenInBrowser(boolean autoOpen) {
autoOpenInBrowser = autoOpen;
}
/**
* Gets the port used when run as a standalone server. Returns the value of the
* system property WOPort. By default, this is zero, which causes the
* application to automatically select an available port.
*/
public static Number port() {
return Integer.getInteger(WOPort, 0);
}
/**
* Gets the smtp server that will be used to send email. Returns the system
* property WOSMTPHost.
*/
public static String SMTPHost() {
return System.getProperty(WOSMTPHost);
}
/**
* Sets the smtp server that will be used to send email.
*
* @deprecated Set the system property WOSMTPHost.
*/
public static void setSMTPHost(String aHost) {
System.setProperty(WOSMTPHost, aHost);
}
/*
* public static boolean isDirectConnectEnabled (); public static void
* setDirectConnectEnabled (boolean); public static String cgiAdaptorURL ();
* public static void setCGIAdaptorURL (String); public static String
* applicationBaseURL (); public static void setApplicationBaseURL (String);
* public static String frameworksBaseURL (); public static void
* setFrameworksBaseURL (String); public static String recordingPath (); public
* static void setRecordingPath (String); public static NSArray
* projectSearchPath (); public static void setProjectSearchPath (NSArray);
* public static boolean isMonitorEnabled (); public static void
* setMonitorEnabled (boolean); public static String monitorHost (); public
* static String adaptor (); public String number (); // deprecated public
* static Number listenQueueSize (); public static void setListenQueueSize
* (Number); public static NSArray additionalAdaptors (); public static void
* setAdditionalAdaptors (NSArray); public static boolean
* includeCommentsInResponses (); public static void
* setIncludeCommentsInResponses (boolean); public static void setSessionTimeOut
* (Number); public static Number sessionTimeOut (); public static void
* logString (String); public static void debugString (String); public static
* void logToMonitorString (String);
*/
/**
* Main entry point for applications that do not subclass WOApplication.
*/
public static void main(String[] argv) {
main(argv, WOApplication.class);
}
/**
* Subclasses may call this method to start a self-hosted web server to serve
* themselves directly (for testing).
*/
public static void main(String[] argv, Class subclass) {
// TODO fix this later
/*try {
int port = 0;
boolean open = false;
try {
port = ((Number) subclass.getMethod("port", new Class[0]).invoke(subclass, new Object[0])).intValue();
open = ((Boolean) subclass.getMethod("autoOpenInBrowser", new Class[0]).invoke(subclass, new Object[0]))
.booleanValue();
} catch (Throwable t) {
System.err.print("Error reading configuration:");
t.printStackTrace();
}
HttpServer server = new HttpServer();
HttpListener listener = server.addListener(new InetAddrPort(port));
org.mortbay.http.HttpContext context = server.getContext("/");
ServletHandler handler = new ServletHandler();
handler.addServlet("/", subclass.getName());
context.addHandler(handler);
server.start();
port = listener.getPort();
System.out.println("Waiting for requests: http://127.0.0.1:" + port);
if (open) {
BrowserLauncher.openURL("http://127.0.0.1:" + port);
}
} catch (Throwable t) {
t.printStackTrace();
}*/
}
}
/*
* $Log$ Revision 1.2 2006/02/19 01:44:02 cgruber Add xmlrpc files Remove jclark
* and replace with dom4j and javax.xml.sax stuff Re-work dependencies and
* imports so it all compiles.
*
* Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in
* eclipse-friendly maven-enabled packages.
*
* Revision 1.30 2003/03/28 18:01:19 mpowers Now defaulting port to zero.
*
* Revision 1.29 2003/03/28 17:31:58 mpowers Implemented support for
* autoselection of free port. (thanks gmuth!)
*
* Revision 1.28 2003/03/28 17:26:17 mpowers Implemented package support:
* Applications can now live in packages. Better support for locating package
* local classes.
*
* Revision 1.27 2003/02/21 16:40:22 mpowers Now reading port and smtp host from
* system properties. Implemented WOApplication.main.
*
* Revision 1.26 2003/02/14 22:33:18 mpowers Better handling for standalone
* mode.
*
* Revision 1.25 2003/02/14 15:18:27 mpowers Now launching standalone app as a
* servlet, not a webapp. Disabled jetty's event logging.
*
* Revision 1.24 2003/02/13 22:41:04 mpowers WOApplications can now be
* self-serving. Added configuration params too.
*
* Revision 1.23 2003/01/28 19:33:51 mpowers Implemented the rest of
* WOResourceManager. Implemented support for java-style i18n. Components now
* use the resource manager to load templates.
*
* Revision 1.22 2003/01/27 15:08:00 mpowers Implemented WOResourceManager,
* using java resources for now.
*
* Revision 1.21 2003/01/24 20:13:22 mpowers Now accepting immutable
* NSDictionary in constructor, not Map.
*
* Revision 1.20 2003/01/20 17:50:11 mpowers Caught a loop condition when same
* declaration was used twice.
*
* Revision 1.19 2003/01/19 22:33:25 mpowers Fixed problems with classpath and
* dynamic class loading. Dynamic elements now pass on ensureAwakeInContext.
* Parser how handles tags.
*
* Revision 1.18 2003/01/18 23:54:50 mpowers Implemented debugging enabled.
*
* Revision 1.17 2003/01/17 20:58:18 mpowers Fixed up WOHyperlink.
*
* Revision 1.16 2003/01/17 20:34:17 mpowers Rudimentary support for resource
* requests.
*
* Revision 1.15 2003/01/17 15:31:56 mpowers Removed spurious error message.
*
* Revision 1.14 2003/01/17 14:39:00 mpowers Now calling preferred constructor:
* WOComponent(WOContext)
*
* Revision 1.13 2003/01/16 20:10:46 mpowers - components now synchronize
* bindings - support for WOComponentContent - implemented performParentAction
*
* Revision 1.12 2003/01/16 15:50:43 mpowers More robust declaration parsing.
* Subcomponents are now supported. dynamicElementWithName can now return
* subcomponents.
*
* Revision 1.11 2003/01/15 19:50:49 mpowers Fixed issues with WOSession and
* Serializable. Can now persist sessions between classloaders (hot swap of
* class impls).
*
* Revision 1.10 2003/01/13 22:24:18 mpowers Request-response cycle is working
* with session and page persistence.
*
* Revision 1.9 2003/01/10 20:17:41 mpowers Component action urls are now
* working.
*
* Revision 1.8 2003/01/10 19:16:40 mpowers Implemented support for page
* caching.
*
* Revision 1.4 2002/12/19 17:58:52 mpowers Rewrote the template parsing - no
* longer confused about "root element".
*
* Revision 1.3 2002/12/18 14:12:38 mpowers Support for differentiated request
* handlers. Support url generation for WOContext and WORequest.
*
* Revision 1.2 2002/12/17 14:57:41 mpowers Minor corrections to WORequests's
* parsing, and updated javadocs.
*
* Revision 1.1.1.1 2000/12/21 15:52:50 mpowers Contributing wotonomy.
*
* Revision 1.2 2000/12/20 16:25:49 michael Added log to all files.
*
*
*/