| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
| WOApplication |
|
| 1.5396825396825398;1.54 |
| 1 | /* |
|
| 2 | Wotonomy: OpenStep design patterns for pure Java applications. |
|
| 3 | Copyright (C) 2000 Blacksmith, Inc. |
|
| 4 | ||
| 5 | This library is free software; you can redistribute it and/or |
|
| 6 | modify it under the terms of the GNU Lesser General Public |
|
| 7 | License as published by the Free Software Foundation; either |
|
| 8 | version 2.1 of the License, or (at your option) any later version. |
|
| 9 | ||
| 10 | This library is distributed in the hope that it will be useful, |
|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
| 13 | Lesser General Public License for more details. |
|
| 14 | ||
| 15 | You should have received a copy of the GNU Lesser General Public |
|
| 16 | License along with this library; if not, see http://www.gnu.org |
|
| 17 | */ |
|
| 18 | ||
| 19 | package net.wotonomy.web; |
|
| 20 | ||
| 21 | import java.lang.reflect.Constructor; |
|
| 22 | import java.util.List; |
|
| 23 | ||
| 24 | import javax.servlet.ServletException; |
|
| 25 | import javax.servlet.http.HttpServlet; |
|
| 26 | import javax.servlet.http.HttpServletRequest; |
|
| 27 | import javax.servlet.http.HttpServletResponse; |
|
| 28 | ||
| 29 | import net.wotonomy.foundation.NSArray; |
|
| 30 | import net.wotonomy.foundation.NSDictionary; |
|
| 31 | import net.wotonomy.foundation.NSMutableDictionary; |
|
| 32 | import net.wotonomy.web.util.BrowserLauncher; |
|
| 33 | ||
| 34 | import org.mortbay.http.HttpListener; |
|
| 35 | import org.mortbay.http.HttpServer; |
|
| 36 | import org.mortbay.jetty.servlet.ServletHandler; |
|
| 37 | import org.mortbay.util.InetAddrPort; |
|
| 38 | ||
| 39 | /** |
|
| 40 | * A pure java implementation of WOApplication. <br><br> |
|
| 41 | * |
|
| 42 | * The application is responsible for creating and managing sessions |
|
| 43 | * and dispatching requests to the appropriate handlers. <br><br> |
|
| 44 | * |
|
| 45 | * This implementation extends HttpServlet, so the application itself |
|
| 46 | * is a servlet and can be configured and managed as such by the servlet |
|
| 47 | * container. |
|
| 48 | * |
|
| 49 | * @author michael@mpowers.net |
|
| 50 | * @author $Author: cgruber $ |
|
| 51 | * @version $Revision: 905 $ |
|
| 52 | */ |
|
| 53 | 0 | public class WOApplication |
| 54 | extends HttpServlet |
|
| 55 | { |
|
| 56 | /** |
|
| 57 | * A tricky way to allow multiple WOApplications |
|
| 58 | * in the same servlet container. |
|
| 59 | */ |
|
| 60 | static private ThreadLocal threadLocal; |
|
| 61 | //static private WOApplication application; |
|
| 62 | ||
| 63 | /** |
|
| 64 | * Determines application-wide page caching. |
|
| 65 | * Pages may individually prevent caching. |
|
| 66 | */ |
|
| 67 | 0 | static private boolean cachingEnabled = false; |
| 68 | 0 | private static boolean autoOpenInBrowser = true; |
| 69 | ||
| 70 | private String name; |
|
| 71 | private WORequestHandler defaultRequestHandler; |
|
| 72 | private NSMutableDictionary requestHandlers; |
|
| 73 | private WOSessionStore sessionStore; |
|
| 74 | private WOResourceManager resourceManager; |
|
| 75 | private boolean pageRefreshOnBacktrack; |
|
| 76 | private int pageCacheSize; |
|
| 77 | private int permanentPageCacheSize; |
|
| 78 | ||
| 79 | public static final String WOApplicationWillFinishLaunchingNotification |
|
| 80 | = "WOApplicationWillFinishLaunchingNotification"; |
|
| 81 | public static final String WOApplicationDidFinishLaunchingNotification |
|
| 82 | = "WOApplicationDidFinishLaunchingNotification"; |
|
| 83 | public static final String WOGarbageCollectionPeriodKey |
|
| 84 | = "WOGarbageCollectionPeriodKey"; |
|
| 85 | ||
| 86 | 0 | static String _DirectActionRequestHandlerKey = "_DirectActionRequestHandlerKey"; |
| 87 | 0 | static String _ComponentRequestHandlerKey = "_ComponentRequestHandlerKey"; |
| 88 | 0 | static String _ResourceRequestHandlerKey = "_ResourceRequestHandlerKey"; |
| 89 | 0 | static String WOPort = "WOPort"; |
| 90 | 0 | static String WOSMTPHost = "WOSMTPHost"; |
| 91 | static final String ELEMENT_CLASS = "elementClass"; |
|
| 92 | ||
| 93 | 0 | public WOApplication () |
| 94 | 0 | { |
| 95 | 0 | if ( threadLocal == null ) |
| 96 | { |
|
| 97 | 0 | threadLocal = new ThreadLocal(); |
| 98 | } |
|
| 99 | 0 | threadLocal.set( this ); |
| 100 | ||
| 101 | //application = this; |
|
| 102 | 0 | resourceManager = createResourceManager(); |
| 103 | 0 | requestHandlers = new NSMutableDictionary(); |
| 104 | 0 | defaultRequestHandler = new WODirectActionRequestHandler(); |
| 105 | 0 | registerRequestHandler( defaultRequestHandler, directActionRequestHandlerKey() ); |
| 106 | 0 | registerRequestHandler( new WOComponentRequestHandler(), componentRequestHandlerKey() ); |
| 107 | 0 | registerRequestHandler( new WOResourceRequestHandler(), resourceRequestHandlerKey() ); |
| 108 | 0 | sessionStore = WOSessionStore.serverSessionStore(); |
| 109 | ||
| 110 | 0 | pageRefreshOnBacktrack = true; |
| 111 | 0 | pageCacheSize = 30; |
| 112 | 0 | permanentPageCacheSize = 30; |
| 113 | ||
| 114 | 0 | threadLocal.set( null ); |
| 115 | 0 | } |
| 116 | ||
| 117 | /** |
|
| 118 | * Dispatches the request and updates the specified response |
|
| 119 | * as appropriate. This implementation creates a new WORequest |
|
| 120 | * and WOContext from the request, sends the response to the |
|
| 121 | * appropriate WORequestHandler, and then updates the servlet |
|
| 122 | * response from the resulting WOResponse. |
|
| 123 | */ |
|
| 124 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) |
|
| 125 | throws ServletException, java.io.IOException |
|
| 126 | { |
|
| 127 | 0 | threadLocal.set( this ); |
| 128 | ||
| 129 | 0 | WORequest request = new WORequest( req, this ); |
| 130 | 0 | WOResponse response = dispatchRequest( request ); |
| 131 | 0 | response.generateServletResponse( resp ); |
| 132 | 0 | } |
| 133 | ||
| 134 | /** |
|
| 135 | * Handles post requests by calling doGet(), since the framework |
|
| 136 | * handles both gets and posts similarly. Override to handle |
|
| 137 | * post requests in a different manner. |
|
| 138 | */ |
|
| 139 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) |
|
| 140 | throws ServletException, java.io.IOException |
|
| 141 | { |
|
| 142 | 0 | doGet( req, resp ); |
| 143 | 0 | } |
| 144 | ||
| 145 | // obtaining attributes |
|
| 146 | ||
| 147 | /** |
|
| 148 | * Returns the singleton instance of this application. |
|
| 149 | */ |
|
| 150 | public static WOApplication application() |
|
| 151 | { |
|
| 152 | 0 | return (WOApplication) threadLocal.get(); |
| 153 | //return application; |
|
| 154 | } |
|
| 155 | ||
| 156 | /** |
|
| 157 | * Returns the name of the application. This implementation returns |
|
| 158 | * the name the jar file or directory from which the class was loaded, |
|
| 159 | * with no extensions. |
|
| 160 | */ |
|
| 161 | public String name() |
|
| 162 | { |
|
| 163 | 0 | if ( name == null ) |
| 164 | { |
|
| 165 | 0 | name = path(); |
| 166 | int i; |
|
| 167 | 0 | if ( name.endsWith( "/" ) ) |
| 168 | { // path |
|
| 169 | 0 | name = name.substring( 0, name.length() - 1 ); |
| 170 | 0 | } |
| 171 | else |
|
| 172 | { // jar file |
|
| 173 | 0 | i = name.lastIndexOf( '.' ); |
| 174 | 0 | if ( i != -1 ) name = name.substring( 0, i ); |
| 175 | } |
|
| 176 | 0 | i = name.lastIndexOf( '/' ); |
| 177 | 0 | if ( i != -1 ) name = name.substring( i+1 ); |
| 178 | } |
|
| 179 | 0 | return name; |
| 180 | } |
|
| 181 | ||
| 182 | /** |
|
| 183 | * Returns the absolute path to the application on the local file system. |
|
| 184 | * Note that the application might be embedded inside of a jar file. |
|
| 185 | */ |
|
| 186 | public String path () |
|
| 187 | { |
|
| 188 | 0 | return getClass().getProtectionDomain().getCodeSource().getLocation().toString(); |
| 189 | } |
|
| 190 | ||
| 191 | /** |
|
| 192 | * Returns the path to the application on the local file system |
|
| 193 | * relative to the server's document root. |
|
| 194 | */ |
|
| 195 | public String baseURL () |
|
| 196 | { |
|
| 197 | 0 | String root = getServletContext().getRealPath( "/" ); |
| 198 | 0 | String result = path(); |
| 199 | 0 | if ( result.endsWith("/") ) |
| 200 | { // path |
|
| 201 | 0 | if ( result.startsWith( root ) ) |
| 202 | { // relative to root |
|
| 203 | 0 | result = result.substring( root.length() ); |
| 204 | } |
|
| 205 | // else leave as absolute reference |
|
| 206 | } |
|
| 207 | // jar or war file: leave as absolute reference |
|
| 208 | 0 | return result; |
| 209 | } |
|
| 210 | ||
| 211 | // concurrent request handling |
|
| 212 | ||
| 213 | /** |
|
| 214 | * Returns whether this application allows request |
|
| 215 | * to be handled concurrently. |
|
| 216 | * This implementation returns true. |
|
| 217 | * Subclasses may override to return false to force |
|
| 218 | * single-threaded request handling, although this |
|
| 219 | * is not implemented. |
|
| 220 | */ |
|
| 221 | public boolean allowsConcurrentRequestHandling () |
|
| 222 | { |
|
| 223 | 0 | return true; |
| 224 | } |
|
| 225 | ||
| 226 | /** |
|
| 227 | * Returns whether this application allows request |
|
| 228 | * to be handled concurrently. |
|
| 229 | * This implementation returns true. |
|
| 230 | */ |
|
| 231 | public boolean adaptorsDispatchRequestsConcurrently () |
|
| 232 | { |
|
| 233 | 0 | return true; |
| 234 | } |
|
| 235 | ||
| 236 | /** |
|
| 237 | * Returns whether this application allows request |
|
| 238 | * to be handled concurrently. |
|
| 239 | * This implementation returns true. |
|
| 240 | */ |
|
| 241 | public boolean isConcurrentRequestHandlingEnabled () |
|
| 242 | { |
|
| 243 | 0 | return true; |
| 244 | } |
|
| 245 | ||
| 246 | // handling requests |
|
| 247 | ||
| 248 | /** |
|
| 249 | * Invoked first in the request-response cycle. |
|
| 250 | * Override to perform any kind of initialization at the |
|
| 251 | * start of a request. This implementation does nothing. |
|
| 252 | */ |
|
| 253 | public void awake () |
|
| 254 | { |
|
| 255 | ||
| 256 | 0 | } |
| 257 | ||
| 258 | /** |
|
| 259 | * Invoked to start the first phase of the request-response cycle, |
|
| 260 | * after all calls to awake() have been completed. |
|
| 261 | */ |
|
| 262 | public void takeValuesFromRequest (WORequest aRequest, WOContext aContext) |
|
| 263 | { |
|
| 264 | 0 | aContext.session().takeValuesFromRequest( aRequest, aContext ); |
| 265 | 0 | } |
| 266 | ||
| 267 | /** |
|
| 268 | * Invoked to start the second phase of the request-response cycle, |
|
| 269 | * after all calls to takeValuesFromRequest have finished. |
|
| 270 | */ |
|
| 271 | public WOActionResults invokeAction (WORequest aRequest, WOContext aContext) |
|
| 272 | { |
|
| 273 | 0 | return aContext.session().invokeAction( aRequest, aContext ); |
| 274 | } |
|
| 275 | ||
| 276 | /** |
|
| 277 | * Invoked to start the third phase of the request-response cycle, |
|
| 278 | * after invokeAction() has completed and returned a WOResponse. |
|
| 279 | */ |
|
| 280 | public void appendToResponse (WOResponse aResponse, WOContext aContext) |
|
| 281 | { |
|
| 282 | 0 | aContext.session().appendToResponse( aResponse, aContext ); |
| 283 | 0 | } |
| 284 | ||
| 285 | /** |
|
| 286 | * Invoked last in the request-response cycle. |
|
| 287 | * Override to perform any kind of clean-up at the |
|
| 288 | * end of a request. This implementation does nothing. |
|
| 289 | */ |
|
| 290 | public void sleep () |
|
| 291 | { |
|
| 292 | ||
| 293 | 0 | } |
| 294 | ||
| 295 | /** |
|
| 296 | * Dispatches the request to the appropriate handler. |
|
| 297 | */ |
|
| 298 | public WOResponse dispatchRequest (WORequest aRequest) |
|
| 299 | { |
|
| 300 | 0 | return handlerForRequest( aRequest ).handleRequest( aRequest ); |
| 301 | } |
|
| 302 | ||
| 303 | // request handling |
|
| 304 | ||
| 305 | /** |
|
| 306 | * Returns the default request handler used if the requested |
|
| 307 | * handler isn't specified or cannot be found. (This defaults |
|
| 308 | * to the WODirectActionRequestHandler.) |
|
| 309 | */ |
|
| 310 | public WORequestHandler defaultRequestHandler () |
|
| 311 | { |
|
| 312 | 0 | return defaultRequestHandler; |
| 313 | } |
|
| 314 | ||
| 315 | /** |
|
| 316 | * Sets the default request handler used if the requested |
|
| 317 | * handler isn't specified or cannot be found. |
|
| 318 | */ |
|
| 319 | public void setDefaultRequestHandler (WORequestHandler aRequestHandler) |
|
| 320 | { |
|
| 321 | 0 | defaultRequestHandler = aRequestHandler; |
| 322 | 0 | } |
| 323 | ||
| 324 | /** |
|
| 325 | * Registers the specified request handler for the specified key. |
|
| 326 | */ |
|
| 327 | public void registerRequestHandler (WORequestHandler aRequestHandler, String aKey) |
|
| 328 | { |
|
| 329 | 0 | requestHandlers.setObjectForKey( aRequestHandler, aKey ); |
| 330 | 0 | } |
| 331 | ||
| 332 | /** |
|
| 333 | * Unregisters any existing request handler for the specified key |
|
| 334 | * returning the existing request handler, if any. |
|
| 335 | */ |
|
| 336 | public WORequestHandler removeRequestHandlerForKey (String aKey) |
|
| 337 | { |
|
| 338 | 0 | WORequestHandler result = requestHandlerForKey( aKey ); |
| 339 | 0 | requestHandlers.removeObjectForKey( aKey ); |
| 340 | 0 | return result; |
| 341 | } |
|
| 342 | ||
| 343 | /** |
|
| 344 | * Returns the keys under which request handlers are registered. |
|
| 345 | */ |
|
| 346 | public NSArray registeredRequestHandlerKeys () |
|
| 347 | { |
|
| 348 | 0 | return requestHandlers.allKeys(); |
| 349 | } |
|
| 350 | ||
| 351 | /** |
|
| 352 | * Returns the request handler registered for the specified key, |
|
| 353 | * or null if no request handler is registered for that key. |
|
| 354 | */ |
|
| 355 | public WORequestHandler requestHandlerForKey (String aKey) |
|
| 356 | { |
|
| 357 | 0 | return (WORequestHandler) requestHandlers.objectForKey( aKey ); |
| 358 | } |
|
| 359 | ||
| 360 | /** |
|
| 361 | * Returns the request handler that would best service the specified request. |
|
| 362 | */ |
|
| 363 | public WORequestHandler handlerForRequest (WORequest aRequest) |
|
| 364 | { |
|
| 365 | 0 | WORequestHandler result = requestHandlerForKey( aRequest.requestHandlerKey() ); |
| 366 | 0 | if ( aRequest == null ) result = defaultRequestHandler(); |
| 367 | 0 | return result; |
| 368 | } |
|
| 369 | ||
| 370 | // handling errors |
|
| 371 | ||
| 372 | public WOResponse handleSessionCreationErrorInContext( WOContext aContext ) |
|
| 373 | { |
|
| 374 | 0 | WOResponse response = new WOResponse(); |
| 375 | 0 | response.setStatus( 500 ); // internal server error |
| 376 | //TODO: add more useful information to the response |
|
| 377 | 0 | System.err.println( "Failed to create session: " + aContext ); |
| 378 | 0 | new RuntimeException().printStackTrace(); // remove me |
| 379 | 0 | return response; |
| 380 | } |
|
| 381 | ||
| 382 | public WOResponse handleSessionRestorationErrorInContext( WOContext aContext ) |
|
| 383 | { |
|
| 384 | 0 | WOResponse response = new WOResponse(); |
| 385 | 0 | response.setStatus( 500 ); // internal server error |
| 386 | //TODO: add more useful information to the response |
|
| 387 | 0 | System.err.println( "Failed to restore session: " + aContext ); |
| 388 | 0 | new RuntimeException().printStackTrace(); // remove me |
| 389 | 0 | return response; |
| 390 | } |
|
| 391 | ||
| 392 | public WOResponse handlePageRestorationErrorInContext( WOContext aContext ) |
|
| 393 | { |
|
| 394 | 0 | WOResponse response = new WOResponse(); |
| 395 | 0 | response.setStatus( 500 ); // internal server error |
| 396 | //TODO: add more useful information to the response |
|
| 397 | 0 | System.err.println( "Failed to restore page: " + aContext ); |
| 398 | 0 | new RuntimeException().printStackTrace(); // remove me |
| 399 | 0 | return response; |
| 400 | } |
|
| 401 | ||
| 402 | public WOResponse handleException( Throwable aThrowable, WOContext aContext ) |
|
| 403 | { |
|
| 404 | 0 | WOResponse response = new WOResponse(); |
| 405 | 0 | response.setStatus( 500 ); // internal server error |
| 406 | 0 | System.err.println( "Exception occurred: " + aContext ); |
| 407 | 0 | if ( aThrowable.getMessage() != null ) |
| 408 | { |
|
| 409 | 0 | response.appendContentString( aThrowable.getMessage() ); |
| 410 | 0 | aThrowable.printStackTrace(); |
| 411 | 0 | } |
| 412 | else |
|
| 413 | { |
|
| 414 | 0 | response.appendContentString( aThrowable.toString() ); |
| 415 | 0 | aThrowable.printStackTrace(); |
| 416 | } |
|
| 417 | 0 | aThrowable.printStackTrace(); |
| 418 | 0 | return response; |
| 419 | } |
|
| 420 | ||
| 421 | // managing pages |
|
| 422 | ||
| 423 | /** |
|
| 424 | * Sets the number of pages that will be retained |
|
| 425 | * in the user's session. Set to zero to disable page caching. |
|
| 426 | */ |
|
| 427 | public void setPageCacheSize (int aPositiveInt) |
|
| 428 | { |
|
| 429 | 0 | pageCacheSize = aPositiveInt; |
| 430 | 0 | } |
| 431 | ||
| 432 | /** |
|
| 433 | * Returns the number of pages that will be retained |
|
| 434 | * in the user's session. The default page cache size is 30. |
|
| 435 | */ |
|
| 436 | public int pageCacheSize () |
|
| 437 | { |
|
| 438 | 0 | return pageCacheSize; |
| 439 | } |
|
| 440 | ||
| 441 | /** |
|
| 442 | * Returns the number of pages that will be retained in the |
|
| 443 | * longer-term "permanent" page cache in the user's session, |
|
| 444 | * which is typically used for navigation bars in frames, etc. |
|
| 445 | * The default permanent page cache size is 30. |
|
| 446 | */ |
|
| 447 | public int permanentPageCacheSize () |
|
| 448 | { |
|
| 449 | 0 | return permanentPageCacheSize; |
| 450 | } |
|
| 451 | ||
| 452 | /** |
|
| 453 | * Returns the number of pages that will be retained in the |
|
| 454 | * longer-term "permanent" page cache in the user's session, |
|
| 455 | * which is typically used for navigation bars in frames, etc. |
|
| 456 | * Set to zero to disable permanent page caching. |
|
| 457 | */ |
|
| 458 | public void setPermanentPageCacheSize (int aPositiveInt) |
|
| 459 | { |
|
| 460 | 0 | permanentPageCacheSize = aPositiveInt; |
| 461 | 0 | } |
| 462 | ||
| 463 | /** |
|
| 464 | * Returns whether a "backtrack" for an existing page should |
|
| 465 | * simply call generateResponse() on the existing page instance. |
|
| 466 | * If false, a new page is created instead. The default is true. |
|
| 467 | */ |
|
| 468 | public void setPageRefreshOnBacktrackEnabled (boolean enabled) |
|
| 469 | { |
|
| 470 | 0 | pageRefreshOnBacktrack = enabled; |
| 471 | 0 | } |
| 472 | ||
| 473 | /** |
|
| 474 | * Returns whether a "backtrack" for an existing page should |
|
| 475 | * simply call generateResponse() on the existing page instance. |
|
| 476 | * If false, a new page is created instead. The default is true. |
|
| 477 | */ |
|
| 478 | public boolean isPageRefreshOnBacktrackEnabled () |
|
| 479 | { |
|
| 480 | 0 | return pageRefreshOnBacktrack; |
| 481 | } |
|
| 482 | ||
| 483 | // managing sessions |
|
| 484 | ||
| 485 | /** |
|
| 486 | * Sets the session store used by this application to persist |
|
| 487 | * sessions between request-response transactions. |
|
| 488 | */ |
|
| 489 | public void setSessionStore(WOSessionStore aSessionStore) |
|
| 490 | { |
|
| 491 | 0 | sessionStore = aSessionStore; |
| 492 | 0 | } |
| 493 | ||
| 494 | /** |
|
| 495 | * Returns the session store used by this application to persist |
|
| 496 | * sessions between request-response transactions. |
|
| 497 | */ |
|
| 498 | public WOSessionStore sessionStore() |
|
| 499 | { |
|
| 500 | 0 | return sessionStore; |
| 501 | } |
|
| 502 | ||
| 503 | /** |
|
| 504 | * Called at the end of the request-response cycle |
|
| 505 | * to persist the current session until the user's next request. |
|
| 506 | */ |
|
| 507 | public void saveSessionForContext(WOContext aContext) |
|
| 508 | { |
|
| 509 | 0 | sessionStore.saveSessionForContext( aContext ); |
| 510 | 0 | } |
| 511 | ||
| 512 | /** |
|
| 513 | * Called at the beginning of the request-response cycle |
|
| 514 | * to obtain the current session from the user's last request. |
|
| 515 | * Returns null if no such session has been created. |
|
| 516 | * This method sets the context of the session to the specified context. |
|
| 517 | */ |
|
| 518 | public WOSession restoreSessionWithID(String aSessionID, WOContext aContext) |
|
| 519 | { |
|
| 520 | 0 | WORequest request = aContext.request(); |
| 521 | 0 | WOSession session = sessionStore.restoreSessionWithID( aSessionID, request ); |
| 522 | 0 | if ( session != null ) |
| 523 | { |
|
| 524 | 0 | session.setContext( aContext ); |
| 525 | 0 | session.setServletSession( request.servletRequest().getSession() ); |
| 526 | } |
|
| 527 | 0 | return session; |
| 528 | } |
|
| 529 | ||
| 530 | /** |
|
| 531 | * Called to create a session for a new request. This implementation |
|
| 532 | * looks for a class in the same package as the application class |
|
| 533 | * called "Session" and failing that returns a WOSession. |
|
| 534 | */ |
|
| 535 | public WOSession createSessionForRequest(WORequest aRequest) |
|
| 536 | { |
|
| 537 | 0 | WOSession result = null; |
| 538 | try |
|
| 539 | { |
|
| 540 | // using our class loader, which is hopefully dynamic. |
|
| 541 | 0 | result = (WOSession) getLocalClass( "Session" ).newInstance(); |
| 542 | } |
|
| 543 | 0 | catch ( Throwable t ) |
| 544 | { |
|
| 545 | // ignore: fall back to WOSession |
|
| 546 | //t.printStackTrace(); |
|
| 547 | 0 | } |
| 548 | ||
| 549 | 0 | if ( result == null ) |
| 550 | { |
|
| 551 | 0 | result = new WOSession(); |
| 552 | } |
|
| 553 | ||
| 554 | 0 | result.setServletSession( aRequest.servletRequest().getSession( true ) ); |
| 555 | 0 | return result; |
| 556 | } |
|
| 557 | ||
| 558 | /** |
|
| 559 | * Returns the page component with the specified name. |
|
| 560 | * A context is created with the specified request, |
|
| 561 | * along with a session if necessary. |
|
| 562 | */ |
|
| 563 | public WOComponent pageWithName (String aName, WORequest aRequest) |
|
| 564 | { |
|
| 565 | 0 | return pageWithName( aName, WOContext.contextWithRequest( aRequest ) ); |
| 566 | } |
|
| 567 | ||
| 568 | /** |
|
| 569 | * Called to retrieve a component for the specified context. |
|
| 570 | */ |
|
| 571 | public WOComponent pageWithName (String aName, WOContext aContext) |
|
| 572 | { |
|
| 573 | 0 | if ( aName == null ) |
| 574 | { |
|
| 575 | 0 | throw new IllegalArgumentException( |
| 576 | 0 | "WOApplication.pageWithName: name is null" ); |
| 577 | } |
|
| 578 | ||
| 579 | 0 | WOComponent result = null; |
| 580 | try |
|
| 581 | { |
|
| 582 | // using our class loader, which is hopefully dynamic. |
|
| 583 | 0 | Class c = getLocalClass( aName ); |
| 584 | ||
| 585 | 0 | if ( c != null ) |
| 586 | { |
|
| 587 | // get constructor |
|
| 588 | Constructor ctor; |
|
| 589 | try |
|
| 590 | { |
|
| 591 | 0 | ctor = c.getConstructor( new Class[] { WOContext.class } ); |
| 592 | } |
|
| 593 | 0 | catch ( NoSuchMethodException nsme ) |
| 594 | { |
|
| 595 | 0 | ctor = null; |
| 596 | 0 | } |
| 597 | ||
| 598 | // create instance of class |
|
| 599 | 0 | if ( ctor != null ) |
| 600 | { |
|
| 601 | 0 | result = (WOComponent) ctor.newInstance( new Object[] { aContext } ); |
| 602 | 0 | } |
| 603 | else // call back on default constructor (deprecated) |
|
| 604 | { |
|
| 605 | 0 | result = (WOComponent) c.newInstance(); |
| 606 | } |
|
| 607 | } |
|
| 608 | } |
|
| 609 | 0 | catch ( Throwable t ) |
| 610 | { |
|
| 611 | // ignore for now |
|
| 612 | //TODO: Throw appropriate exception here |
|
| 613 | //System.err.println( "Not found: pageWithName: " + aName ); |
|
| 614 | 0 | t.printStackTrace(); |
| 615 | 0 | } |
| 616 | ||
| 617 | 0 | if ( result != null && aContext != null ) |
| 618 | { |
|
| 619 | // this is where components get their context |
|
| 620 | 0 | result.ensureAwakeInContext( aContext ); |
| 621 | 0 | } |
| 622 | else |
|
| 623 | 0 | if ( result == null ) |
| 624 | { |
|
| 625 | 0 | System.err.println( "Not found: pageWithName: " + aName ); |
| 626 | } |
|
| 627 | ||
| 628 | 0 | return result; |
| 629 | } |
|
| 630 | ||
| 631 | /** |
|
| 632 | * Returns a class in the same package as the Application class, |
|
| 633 | * or, failing that, from the WOApplication package, or finally |
|
| 634 | * from the root of the class path. Returns null if not found. |
|
| 635 | */ |
|
| 636 | Class getLocalClass( String aName ) |
|
| 637 | { |
|
| 638 | 0 | Class result = null; |
| 639 | 0 | if ( getClass() != WOApplication.class ) |
| 640 | { |
|
| 641 | 0 | result = loadLocalClass( getClass(), aName ); |
| 642 | } |
|
| 643 | 0 | if ( result == null ) |
| 644 | { |
|
| 645 | 0 | result = loadLocalClass( WOApplication.class, aName ); |
| 646 | } |
|
| 647 | 0 | if ( result == null ) |
| 648 | { |
|
| 649 | 0 | result = loadLocalClass( null, aName ); |
| 650 | } |
|
| 651 | 0 | return result; |
| 652 | } |
|
| 653 | ||
| 654 | private static final Class loadLocalClass( Class aClass, String aName ) |
|
| 655 | { |
|
| 656 | ClassLoader loader; |
|
| 657 | 0 | String packageName = ""; |
| 658 | 0 | if ( aClass != null ) |
| 659 | { |
|
| 660 | 0 | loader = aClass.getClassLoader(); |
| 661 | 0 | packageName = aClass.getName(); |
| 662 | 0 | int index = packageName.lastIndexOf( "." ); |
| 663 | 0 | if ( index > -1 ) |
| 664 | { |
|
| 665 | 0 | packageName = packageName.substring( 0, index+1 ); |
| 666 | 0 | } |
| 667 | else |
|
| 668 | { |
|
| 669 | 0 | packageName = ""; |
| 670 | } |
|
| 671 | 0 | } |
| 672 | else |
|
| 673 | { |
|
| 674 | 0 | loader = WOApplication.class.getClassLoader(); |
| 675 | } |
|
| 676 | ||
| 677 | try |
|
| 678 | { |
|
| 679 | 0 | return loader.loadClass( packageName + aName ); |
| 680 | } |
|
| 681 | 0 | catch ( ClassNotFoundException e ) |
| 682 | { |
|
| 683 | 0 | return null; |
| 684 | } |
|
| 685 | } |
|
| 686 | ||
| 687 | // creating elements |
|
| 688 | ||
| 689 | /** |
|
| 690 | * Returns either a dynamic element or a component |
|
| 691 | * for the specified name. |
|
| 692 | */ |
|
| 693 | public WOElement dynamicElementWithName( |
|
| 694 | String anElementName, NSDictionary anAssociationMap, |
|
| 695 | WOElement aBodyElement, List aLanguageList) |
|
| 696 | { |
|
| 697 | 0 | WOElement element = null; |
| 698 | 0 | Class c = null; |
| 699 | try |
|
| 700 | { |
|
| 701 | 0 | c = getLocalClass( anElementName ); |
| 702 | 0 | if ( c == null ) |
| 703 | { |
|
| 704 | 0 | System.out.println( "Not found: dynamicElementWithName: " + |
| 705 | 0 | "could not find WODynamicElement subclass: " + anElementName ); |
| 706 | 0 | c = WODynamicElement.class; |
| 707 | } |
|
| 708 | ||
| 709 | // get constructor |
|
| 710 | 0 | Class[] params = new Class[] |
| 711 | 0 | { String.class, NSDictionary.class, WOElement.class }; |
| 712 | 0 | Constructor ctor = c.getConstructor( params ); |
| 713 | ||
| 714 | // create instance of class |
|
| 715 | 0 | if ( ctor != null ) |
| 716 | { |
|
| 717 | 0 | element = (WODynamicElement) ctor.newInstance( |
| 718 | 0 | new Object[] { anElementName, anAssociationMap, aBodyElement } ); |
| 719 | } |
|
| 720 | } |
|
| 721 | 0 | catch ( Throwable t ) |
| 722 | { |
|
| 723 | // ignore: not a dynamic element |
|
| 724 | //System.out.println( "Not a dynamic element: dynamicElementWithName: " + t ); |
|
| 725 | //exc.printStackTrace(); |
|
| 726 | 0 | } |
| 727 | ||
| 728 | // no dynamic element found: look for a component |
|
| 729 | 0 | if ( element == null ) |
| 730 | { |
|
| 731 | 0 | WOComponent component = (WOComponent) pageWithName( anElementName, (WOContext) null ); |
| 732 | ||
| 733 | // this seems hackish: |
|
| 734 | // I don't see another way of setting the bindings. |
|
| 735 | 0 | component.associations = anAssociationMap; |
| 736 | 0 | component.rootElement = aBodyElement; |
| 737 | ||
| 738 | 0 | element = component; |
| 739 | } |
|
| 740 | ||
| 741 | 0 | return element; |
| 742 | } |
|
| 743 | ||
| 744 | // resource handling |
|
| 745 | ||
| 746 | /** |
|
| 747 | * Called to create the application's resource manager. |
|
| 748 | * Override to create a custom resource manager. |
|
| 749 | */ |
|
| 750 | public WOResourceManager createResourceManager() |
|
| 751 | { |
|
| 752 | 0 | return new WOResourceManager(); |
| 753 | } |
|
| 754 | ||
| 755 | /** |
|
| 756 | * Returns the application's current resource manager. |
|
| 757 | */ |
|
| 758 | public WOResourceManager resourceManager() |
|
| 759 | { |
|
| 760 | 0 | return resourceManager; |
| 761 | } |
|
| 762 | ||
| 763 | /** |
|
| 764 | * Installs a custom resource manager into the current application. |
|
| 765 | * @deprecated Override createResourceManager() instead. |
|
| 766 | */ |
|
| 767 | public void setResourceManager(WOResourceManager aResourceManager) |
|
| 768 | { |
|
| 769 | 0 | resourceManager = aResourceManager; |
| 770 | 0 | } |
| 771 | ||
| 772 | /* |
|
| 773 | // request handling undocumented |
|
| 774 | ||
| 775 | public WOComponent pageWithName (String); |
|
| 776 | public void savePage (WOComponent); |
|
| 777 | public WOComponent restorePageForContextID (String); |
|
| 778 | public WOContext context (); |
|
| 779 | public WOSession session (); |
|
| 780 | public WOSession createSession (); |
|
| 781 | public WOSession restoreSession (); |
|
| 782 | public void saveSession (WOSession); |
|
| 783 | ||
| 784 | public WOResponse handleRequest (WORequest aRequest) |
|
| 785 | { |
|
| 786 | } |
|
| 787 | ||
| 788 | // error handling undocumented |
|
| 789 | |
|
| 790 | WOResponse handleSessionCreationError (); |
|
| 791 | WOResponse handleSessionRestorationError (); |
|
| 792 | WOResponse handlePageRestorationError (); |
|
| 793 | WOResponse handleException (Throwable); |
|
| 794 | ||
| 795 | // running |
|
| 796 | |
|
| 797 | public NSRunLoop runLoop (); |
|
| 798 | public void run (); |
|
| 799 | public void setTimeOut (double); |
|
| 800 | public double timeOut (); |
|
| 801 | public void terminate (); |
|
| 802 | public boolean isTerminating (); |
|
| 803 | |
|
| 804 | // script debugging |
|
| 805 | |
|
| 806 | public void traceScriptedMessages (boolean); |
|
| 807 | public void traceAssignments (boolean); |
|
| 808 | public void traceStatements (boolean); |
|
| 809 | public void traceObjectiveCMessages (boolean); |
|
| 810 | public void trace (boolean); |
|
| 811 | public void logTakeValueForDeclarationNamed (String, String, String, String, Object); |
|
| 812 | public void logSetValueForDeclarationNamed (String, String, String, String, Object); |
|
| 813 | |
|
| 814 | // script handling |
|
| 815 | |
|
| 816 | public String scriptedClassNameWithPath (String); |
|
| 817 | public String scriptedClassNameWithPathEncoding (String, int); |
|
| 818 | ||
| 819 | // statistics report |
|
| 820 | |
|
| 821 | public void setStatisticsStore (WOStatisticsStore); |
|
| 822 | public WOStatisticsStore statisticsStore (); |
|
| 823 | public NSDictionary statistics (); |
|
| 824 | |
|
| 825 | // managing adaptors |
|
| 826 | |
|
| 827 | public WOAdaptor adaptorWithName (String, NSDictionary); |
|
| 828 | public NSArray adaptors (); |
|
| 829 | |
|
| 830 | // monitor support |
|
| 831 | |
|
| 832 | public boolean monitoringEnabled (); |
|
| 833 | public int activeSessionsCount (); |
|
| 834 | public void refuseNewSessions (boolean); |
|
| 835 | public boolean isRefusingNewSessions (); |
|
| 836 | public void setMinimumActiveSessionsCount (int); |
|
| 837 | public int minimumActiveSessionsCount (); |
|
| 838 | public void terminateAfterTimeInterval (double); |
|
| 839 | ||
| 840 | // garbage collection undocumented |
|
| 841 | ||
| 842 | int garbageCollectionPeriod (); |
|
| 843 | void setGarbageCollectionPeriod (int); |
|
| 844 | |
|
| 845 | // backwards compatibility |
|
| 846 | ||
| 847 | public boolean requiresWOF35RequestHandling (); |
|
| 848 | public boolean requiresWOF35TemplateParser (); |
|
| 849 | ||
| 850 | public void setPrintsHTMLParserDiagnostics (boolean); |
|
| 851 | public boolean printsHTMLParserDiagnostics (); |
|
| 852 | |
|
| 853 | // configuration and defaults |
|
| 854 | ||
| 855 | public static NSArray loadFrameworks (); |
|
| 856 | public static void setLoadFrameworks (NSArray); |
|
| 857 | */ |
|
| 858 | 0 | static boolean debuggingEnabled = false; |
| 859 | /** |
|
| 860 | * Returns whether the application is in "debug mode". |
|
| 861 | */ |
|
| 862 | public static boolean isDebuggingEnabled() |
|
| 863 | { |
|
| 864 | 0 | return debuggingEnabled; |
| 865 | } |
|
| 866 | ||
| 867 | /** |
|
| 868 | * Sets whether the application is in "debug mode". |
|
| 869 | */ |
|
| 870 | public static void setDebuggingEnabled( boolean enabled ) |
|
| 871 | { |
|
| 872 | 0 | debuggingEnabled = enabled; |
| 873 | 0 | } |
| 874 | ||
| 875 | /** |
|
| 876 | * Sets whether templates are cached. If true, templates will |
|
| 877 | * only be read once per application lifetime. Otherwise, templates |
|
| 878 | * will be read each time this class is instantiated. Defaults to false. |
|
| 879 | */ |
|
| 880 | public static void setCachingEnabled (boolean enabled) |
|
| 881 | { |
|
| 882 | 0 | cachingEnabled = enabled; |
| 883 | 0 | } |
| 884 | ||
| 885 | /** |
|
| 886 | * Returns whether templates are cached. If true, templates are |
|
| 887 | * read once per application lifetime. Otherwise, templates are |
|
| 888 | * read each time this class is instantiated. |
|
| 889 | */ |
|
| 890 | public static boolean isCachingEnabled () |
|
| 891 | { |
|
| 892 | 0 | return cachingEnabled; |
| 893 | } |
|
| 894 | ||
| 895 | // configuration |
|
| 896 | ||
| 897 | /** |
|
| 898 | * Returns the component request handler key, |
|
| 899 | * which is defined by the system property _ComponentRequestHandlerKey. |
|
| 900 | * The default is "wo". |
|
| 901 | */ |
|
| 902 | public static String componentRequestHandlerKey() |
|
| 903 | { |
|
| 904 | 0 | return System.getProperty( _ComponentRequestHandlerKey, "wo" ); |
| 905 | } |
|
| 906 | ||
| 907 | /** |
|
| 908 | * Sets the component request handler key. |
|
| 909 | * @deprecated Set the system property _ComponentRequestHandlerKey. |
|
| 910 | */ |
|
| 911 | public static void setComponentRequestHandlerKey(String aKey) |
|
| 912 | { |
|
| 913 | 0 | System.setProperty( _ComponentRequestHandlerKey, aKey ); |
| 914 | 0 | } |
| 915 | ||
| 916 | /** |
|
| 917 | * Returns the direct action request handler key, |
|
| 918 | * which is defined by the system property _DirectActionRequestHandlerKey. |
|
| 919 | * The default is "wa". |
|
| 920 | */ |
|
| 921 | public static String directActionRequestHandlerKey() |
|
| 922 | { |
|
| 923 | 0 | return System.getProperty( _DirectActionRequestHandlerKey, "wa" ); |
| 924 | } |
|
| 925 | ||
| 926 | /** |
|
| 927 | * Sets the direct action request handler key. |
|
| 928 | * @deprecated Set the system property _DirectActionRequestHandlerKey. |
|
| 929 | */ |
|
| 930 | public static void setDirectActionRequestHandlerKey(String aKey) |
|
| 931 | { |
|
| 932 | 0 | System.setProperty( _DirectActionRequestHandlerKey, aKey ); |
| 933 | 0 | } |
| 934 | ||
| 935 | /** |
|
| 936 | * Returns the resource request handler key, |
|
| 937 | * which is defined by the system property _ResourceRequestHandlerKey. |
|
| 938 | * The default is "wr". |
|
| 939 | */ |
|
| 940 | public static String resourceRequestHandlerKey() |
|
| 941 | { |
|
| 942 | 0 | return System.getProperty( _ResourceRequestHandlerKey, "wr" ); |
| 943 | } |
|
| 944 | ||
| 945 | /** |
|
| 946 | * Sets the resource request handler key. |
|
| 947 | * @deprecated Set the system property _ResourceRequestHandlerKey. |
|
| 948 | */ |
|
| 949 | public static void setResourceRequestHandlerKey(String aKey) |
|
| 950 | { |
|
| 951 | 0 | System.setProperty( _ResourceRequestHandlerKey, aKey ); |
| 952 | 0 | } |
| 953 | ||
| 954 | /** |
|
| 955 | * Returns whether this application should attempt to open |
|
| 956 | * a web browser on the host machine when launched standalone. |
|
| 957 | * The default is true. |
|
| 958 | */ |
|
| 959 | public static boolean autoOpenInBrowser() |
|
| 960 | { |
|
| 961 | 0 | return autoOpenInBrowser; |
| 962 | } |
|
| 963 | ||
| 964 | /** |
|
| 965 | * Sets whether this application should attempt to open |
|
| 966 | * a web browser on the host machine when launched standalone. |
|
| 967 | */ |
|
| 968 | public static void setAutoOpenInBrowser(boolean autoOpen) |
|
| 969 | { |
|
| 970 | 0 | autoOpenInBrowser = autoOpen; |
| 971 | 0 | } |
| 972 | ||
| 973 | /** |
|
| 974 | * Gets the port used when run as a standalone server. |
|
| 975 | * Returns the value of the system property WOPort. |
|
| 976 | * By default, this is zero, which causes the application |
|
| 977 | * to automatically select an available port. |
|
| 978 | */ |
|
| 979 | public static Number port () |
|
| 980 | { |
|
| 981 | 0 | return Integer.getInteger( WOPort, 0 ); |
| 982 | } |
|
| 983 | ||
| 984 | /** |
|
| 985 | * Gets the smtp server that will be used to send email. |
|
| 986 | * Returns the system property WOSMTPHost. |
|
| 987 | */ |
|
| 988 | public static String SMTPHost() |
|
| 989 | { |
|
| 990 | 0 | return System.getProperty( WOSMTPHost ); |
| 991 | } |
|
| 992 | ||
| 993 | /** |
|
| 994 | * Sets the smtp server that will be used to send email. |
|
| 995 | * @deprecated Set the system property WOSMTPHost. |
|
| 996 | */ |
|
| 997 | public static void setSMTPHost( String aHost ) |
|
| 998 | { |
|
| 999 | 0 | System.setProperty( WOSMTPHost, aHost ); |
| 1000 | 0 | } |
| 1001 | /* |
|
| 1002 | public static boolean isDirectConnectEnabled (); |
|
| 1003 | public static void setDirectConnectEnabled (boolean); |
|
| 1004 | public static String cgiAdaptorURL (); |
|
| 1005 | public static void setCGIAdaptorURL (String); |
|
| 1006 | public static String applicationBaseURL (); |
|
| 1007 | public static void setApplicationBaseURL (String); |
|
| 1008 | public static String frameworksBaseURL (); |
|
| 1009 | public static void setFrameworksBaseURL (String); |
|
| 1010 | public static String recordingPath (); |
|
| 1011 | public static void setRecordingPath (String); |
|
| 1012 | public static NSArray projectSearchPath (); |
|
| 1013 | public static void setProjectSearchPath (NSArray); |
|
| 1014 | public static boolean isMonitorEnabled (); |
|
| 1015 | public static void setMonitorEnabled (boolean); |
|
| 1016 | public static String monitorHost (); |
|
| 1017 | public static String adaptor (); |
|
| 1018 | public String number (); // deprecated |
|
| 1019 | public static Number listenQueueSize (); |
|
| 1020 | public static void setListenQueueSize (Number); |
|
| 1021 | public static NSArray additionalAdaptors (); |
|
| 1022 | public static void setAdditionalAdaptors (NSArray); |
|
| 1023 | public static boolean includeCommentsInResponses (); |
|
| 1024 | public static void setIncludeCommentsInResponses (boolean); |
|
| 1025 | public static void setSessionTimeOut (Number); |
|
| 1026 | public static Number sessionTimeOut (); |
|
| 1027 | public static void logString (String); |
|
| 1028 | public static void debugString (String); |
|
| 1029 | public static void logToMonitorString (String); |
|
| 1030 | */ |
|
| 1031 | ||
| 1032 | /** |
|
| 1033 | * Main entry point for applications that do not subclass WOApplication. |
|
| 1034 | */ |
|
| 1035 | public static void main( String[] argv ) |
|
| 1036 | { |
|
| 1037 | 0 | main( argv, WOApplication.class ); |
| 1038 | 0 | } |
| 1039 | ||
| 1040 | /** |
|
| 1041 | * Subclasses may call this method to start a self-hosted |
|
| 1042 | * web server to serve themselves directly (for testing). |
|
| 1043 | */ |
|
| 1044 | public static void main( String[] argv, Class subclass ) |
|
| 1045 | { |
|
| 1046 | try |
|
| 1047 | { |
|
| 1048 | 0 | int port = 0; |
| 1049 | 0 | boolean open = false; |
| 1050 | try |
|
| 1051 | { |
|
| 1052 | 0 | port = ((Number)subclass.getMethod( "port", |
| 1053 | 0 | new Class[0]).invoke(subclass,new Object[0])).intValue(); |
| 1054 | 0 | open = ((Boolean)subclass.getMethod( "autoOpenInBrowser", |
| 1055 | 0 | new Class[0]).invoke(subclass,new Object[0])).booleanValue(); |
| 1056 | } |
|
| 1057 | 0 | catch ( Throwable t ) |
| 1058 | { |
|
| 1059 | 0 | System.err.print("Error reading configuration:" ); |
| 1060 | 0 | t.printStackTrace(); |
| 1061 | 0 | } |
| 1062 | ||
| 1063 | 0 | HttpServer server = new HttpServer(); |
| 1064 | 0 | HttpListener listener = server.addListener(new InetAddrPort(port)); |
| 1065 | 0 | org.mortbay.http.HttpContext context = server.getContext("/"); |
| 1066 | 0 | ServletHandler handler = new ServletHandler(); |
| 1067 | 0 | handler.addServlet("/",subclass.getName()); |
| 1068 | 0 | context.addHandler(handler); |
| 1069 | 0 | server.start(); |
| 1070 | 0 | port = listener.getPort(); |
| 1071 | 0 | System.out.println("Waiting for requests: http://127.0.0.1:" + port); |
| 1072 | 0 | if ( open ) |
| 1073 | { |
|
| 1074 | 0 | BrowserLauncher.openURL( "http://127.0.0.1:" + port ); |
| 1075 | } |
|
| 1076 | } |
|
| 1077 | 0 | catch ( Throwable t ) |
| 1078 | { |
|
| 1079 | 0 | t.printStackTrace(); |
| 1080 | 0 | } |
| 1081 | 0 | } |
| 1082 | } |
|
| 1083 | ||
| 1084 | /* |
|
| 1085 | * $Log$ |
|
| 1086 | * Revision 1.2 2006/02/19 01:44:02 cgruber |
|
| 1087 | * Add xmlrpc files |
|
| 1088 | * Remove jclark and replace with dom4j and javax.xml.sax stuff |
|
| 1089 | * Re-work dependencies and imports so it all compiles. |
|
| 1090 | * |
|
| 1091 | * Revision 1.1 2006/02/16 13:22:22 cgruber |
|
| 1092 | * Check in all sources in eclipse-friendly maven-enabled packages. |
|
| 1093 | * |
|
| 1094 | * Revision 1.30 2003/03/28 18:01:19 mpowers |
|
| 1095 | * Now defaulting port to zero. |
|
| 1096 | * |
|
| 1097 | * Revision 1.29 2003/03/28 17:31:58 mpowers |
|
| 1098 | * Implemented support for autoselection of free port. (thanks gmuth!) |
|
| 1099 | * |
|
| 1100 | * Revision 1.28 2003/03/28 17:26:17 mpowers |
|
| 1101 | * Implemented package support: Applications can now live in packages. |
|
| 1102 | * Better support for locating package local classes. |
|
| 1103 | * |
|
| 1104 | * Revision 1.27 2003/02/21 16:40:22 mpowers |
|
| 1105 | * Now reading port and smtp host from system properties. |
|
| 1106 | * Implemented WOApplication.main. |
|
| 1107 | * |
|
| 1108 | * Revision 1.26 2003/02/14 22:33:18 mpowers |
|
| 1109 | * Better handling for standalone mode. |
|
| 1110 | * |
|
| 1111 | * Revision 1.25 2003/02/14 15:18:27 mpowers |
|
| 1112 | * Now launching standalone app as a servlet, not a webapp. |
|
| 1113 | * Disabled jetty's event logging. |
|
| 1114 | * |
|
| 1115 | * Revision 1.24 2003/02/13 22:41:04 mpowers |
|
| 1116 | * WOApplications can now be self-serving. Added configuration params too. |
|
| 1117 | * |
|
| 1118 | * Revision 1.23 2003/01/28 19:33:51 mpowers |
|
| 1119 | * Implemented the rest of WOResourceManager. |
|
| 1120 | * Implemented support for java-style i18n. |
|
| 1121 | * Components now use the resource manager to load templates. |
|
| 1122 | * |
|
| 1123 | * Revision 1.22 2003/01/27 15:08:00 mpowers |
|
| 1124 | * Implemented WOResourceManager, using java resources for now. |
|
| 1125 | * |
|
| 1126 | * Revision 1.21 2003/01/24 20:13:22 mpowers |
|
| 1127 | * Now accepting immutable NSDictionary in constructor, not Map. |
|
| 1128 | * |
|
| 1129 | * Revision 1.20 2003/01/20 17:50:11 mpowers |
|
| 1130 | * Caught a loop condition when same declaration was used twice. |
|
| 1131 | * |
|
| 1132 | * Revision 1.19 2003/01/19 22:33:25 mpowers |
|
| 1133 | * Fixed problems with classpath and dynamic class loading. |
|
| 1134 | * Dynamic elements now pass on ensureAwakeInContext. |
|
| 1135 | * Parser how handles <standalone/> tags. |
|
| 1136 | * |
|
| 1137 | * Revision 1.18 2003/01/18 23:54:50 mpowers |
|
| 1138 | * Implemented debugging enabled. |
|
| 1139 | * |
|
| 1140 | * Revision 1.17 2003/01/17 20:58:18 mpowers |
|
| 1141 | * Fixed up WOHyperlink. |
|
| 1142 | * |
|
| 1143 | * Revision 1.16 2003/01/17 20:34:17 mpowers |
|
| 1144 | * Rudimentary support for resource requests. |
|
| 1145 | * |
|
| 1146 | * Revision 1.15 2003/01/17 15:31:56 mpowers |
|
| 1147 | * Removed spurious error message. |
|
| 1148 | * |
|
| 1149 | * Revision 1.14 2003/01/17 14:39:00 mpowers |
|
| 1150 | * Now calling preferred constructor: WOComponent(WOContext) |
|
| 1151 | * |
|
| 1152 | * Revision 1.13 2003/01/16 20:10:46 mpowers |
|
| 1153 | * - components now synchronize bindings |
|
| 1154 | * - support for WOComponentContent |
|
| 1155 | * - implemented performParentAction |
|
| 1156 | * |
|
| 1157 | * Revision 1.12 2003/01/16 15:50:43 mpowers |
|
| 1158 | * More robust declaration parsing. |
|
| 1159 | * Subcomponents are now supported. |
|
| 1160 | * dynamicElementWithName can now return subcomponents. |
|
| 1161 | * |
|
| 1162 | * Revision 1.11 2003/01/15 19:50:49 mpowers |
|
| 1163 | * Fixed issues with WOSession and Serializable. |
|
| 1164 | * Can now persist sessions between classloaders (hot swap of class impls). |
|
| 1165 | * |
|
| 1166 | * Revision 1.10 2003/01/13 22:24:18 mpowers |
|
| 1167 | * Request-response cycle is working with session and page persistence. |
|
| 1168 | * |
|
| 1169 | * Revision 1.9 2003/01/10 20:17:41 mpowers |
|
| 1170 | * Component action urls are now working. |
|
| 1171 | * |
|
| 1172 | * Revision 1.8 2003/01/10 19:16:40 mpowers |
|
| 1173 | * Implemented support for page caching. |
|
| 1174 | * |
|
| 1175 | * Revision 1.4 2002/12/19 17:58:52 mpowers |
|
| 1176 | * Rewrote the template parsing - no longer confused about "root element". |
|
| 1177 | * |
|
| 1178 | * Revision 1.3 2002/12/18 14:12:38 mpowers |
|
| 1179 | * Support for differentiated request handlers. |
|
| 1180 | * Support url generation for WOContext and WORequest. |
|
| 1181 | * |
|
| 1182 | * Revision 1.2 2002/12/17 14:57:41 mpowers |
|
| 1183 | * Minor corrections to WORequests's parsing, and updated javadocs. |
|
| 1184 | * |
|
| 1185 | * Revision 1.1.1.1 2000/12/21 15:52:50 mpowers |
|
| 1186 | * Contributing wotonomy. |
|
| 1187 | * |
|
| 1188 | * Revision 1.2 2000/12/20 16:25:49 michael |
|
| 1189 | * Added log to all files. |
|
| 1190 | * |
|
| 1191 | * |
|
| 1192 | */ |
|
| 1193 |