KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lutris > appserver > server > StandardApplication


1 /*
2  * Enhydra Java Application Server Project
3  *
4  * The contents of this file are subject to the Enhydra Public License
5  * Version 1.1 (the "License"); you may not use this file except in
6  * compliance with the License. You may obtain a copy of the License on
7  * the Enhydra web site ( http://www.enhydra.org/ ).
8  *
9  * Software distributed under the License is distributed on an "AS IS"
10  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
11  * the License for the specific terms governing rights and limitations
12  * under the License.
13  *
14  * The Initial Developer of the Enhydra Application Server is Lutris
15  * Technologies, Inc. The Enhydra Application Server and portions created
16  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
17  * All Rights Reserved.
18  *
19  * Contributor(s):
20  *
21  * $Id: StandardApplication.java,v 1.1 2005/07/13 11:09:06 slobodan Exp $
22  *
23  *
24  *
25  */

26 package com.lutris.appserver.server;
27
28 import java.io.IOException JavaDoc;
29 import java.lang.reflect.Constructor JavaDoc;
30 import java.lang.reflect.Method JavaDoc;
31 import java.util.Enumeration JavaDoc;
32 import java.util.Hashtable JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.ListIterator JavaDoc;
36 import java.util.StringTokenizer JavaDoc;
37
38 import javax.management.Attribute JavaDoc;
39 import javax.management.AttributeChangeNotification JavaDoc;
40 import javax.management.AttributeList JavaDoc;
41 import javax.management.AttributeNotFoundException JavaDoc;
42 import javax.management.DynamicMBean JavaDoc;
43 import javax.management.InvalidAttributeValueException JavaDoc;
44 import javax.management.MBeanAttributeInfo JavaDoc;
45 import javax.management.MBeanConstructorInfo JavaDoc;
46 import javax.management.MBeanException JavaDoc;
47 import javax.management.MBeanInfo JavaDoc;
48 import javax.management.MBeanNotificationInfo JavaDoc;
49 import javax.management.MBeanOperationInfo JavaDoc;
50 import javax.management.MBeanParameterInfo JavaDoc;
51 import javax.management.MBeanServer JavaDoc;
52 import javax.management.MBeanServerFactory JavaDoc;
53 import javax.management.Notification JavaDoc;
54 import javax.management.NotificationBroadcasterSupport JavaDoc;
55 import javax.management.ObjectName JavaDoc;
56 import javax.management.ReflectionException JavaDoc;
57 import javax.management.RuntimeOperationsException JavaDoc;
58 import javax.servlet.Servlet JavaDoc;
59 import javax.servlet.ServletContext JavaDoc;
60 import javax.servlet.ServletException JavaDoc;
61 import javax.servlet.http.HttpServletRequest JavaDoc;
62 import javax.servlet.http.HttpServletResponse JavaDoc;
63
64 import org.enhydra.util.ConfigFileInterface;
65 import org.enhydra.util.DOTable;
66 import org.enhydra.util.Utils;
67 import org.enhydra.util.EafConfigMBean;
68 import org.enhydra.util.jivan.JivanFactory;
69 import org.enhydra.xml.xmlc.XMLCFactory;
70 import org.enhydra.xml.xmlc.XMLCStdFactory;
71 import org.enhydra.xml.xmlc.deferredparsing.DocumentLoaderImpl;
72 import org.enhydra.xml.xmlc.deferredparsing.XMLCDeferredParsingFactory;
73
74 import com.lutris.appserver.server.httpPresentation.ClientPageRedirectException;
75 import com.lutris.appserver.server.httpPresentation.HttpPresentationComms;
76 import com.lutris.appserver.server.httpPresentation.HttpPresentationException;
77 import com.lutris.appserver.server.httpPresentation.HttpPresentationManager;
78 import com.lutris.appserver.server.session.MemoryPersistence;
79 import com.lutris.appserver.server.session.Session;
80 import com.lutris.appserver.server.session.SessionException;
81 import com.lutris.appserver.server.session.SessionManager;
82 import com.lutris.appserver.server.sessionEnhydra.StandardSessionManager;
83 import com.lutris.appserver.server.sql.DatabaseManager;
84 import com.lutris.classloader.MultiClassLoader;
85 import com.lutris.logging.EnhydraXMLCLogger;
86 import com.lutris.logging.LogChannel;
87 import com.lutris.logging.Logger;
88 import com.lutris.util.Config;
89 import com.lutris.util.KeywordValueException;
90
91 /**
92  * Default application implementation. This class provides standard start/stop
93  * services. This can be used as a base class to derive Application objects.
94  *
95  * @version $Revision: 1.1 $
96  * @author Mark Diekhans
97  */

98 public abstract class StandardApplication
99     implements Application {
100   /*
101    * Category of logger that logs on System.out.
102    */

103   private static final String JavaDoc sysConLoggerName = "SysOut";
104   private static final String JavaDoc STANDARD_DATABASE_MANAGER_CLASS_NAME =
105       "com.lutris.appserver.server.sql.StandardDatabaseManager";
106   /**
107    * Determines if a cookie with the session id is sent to the client.
108    */

109   protected boolean sendCookieForNewSession = true;
110   /**
111    * The name of the application; defaults to the unqualified
112    * class name.
113    */

114   protected String JavaDoc appName = null;
115   /**
116    * Current state of the application. Only modified by the derived
117    * application.
118    */

119   protected int state = STOPPED;
120   /**
121    * Session manager for all application sessions. A session manager
122    * manages the creation, deletion and assocation of sessions with
123    * a user.
124    */

125   protected SessionManager sessionManager;
126   /**
127    * Presentation manager instance for application. The presentation
128    * manager handles incomming http requests.
129    */

130   protected HttpPresentationManager presentationManager;
131   /**
132    * Database manager instance for application. The database manager
133    * manages logical database and is responsible for allocating
134    * connection, create transactions, etc.
135    */

136   protected DatabaseManager databaseManager;
137   /**
138    * This applications config object. Every application has a configuration
139    * object that is created from the application configuration file.
140    *
141    * @see Config
142    */

143   protected Config config;
144   /**
145    * Default URL used for application if defined in Config file. This
146    * is used to redirect the user to the preferred start page if a
147    * URL equal to the root of this application is given. By setting
148    * this to index.html, it behaves in the same way as a http server.
149    */

150   protected String JavaDoc defaultUrl;
151   /**
152    * The log channel for this application to write to.
153    */

154   protected LogChannel logChannel;
155   protected Logger logger;
156   /**
157    * The logger that logs on System.out.
158    */

159   protected static LogChannel loggerSys;
160   /**
161    * Application Data accessable through Jolt Fields.
162    */

163   protected ApplicationData data = new ApplicationData();
164   /**
165    * XMLC Factory.
166    */

167   protected XMLCFactory xmlcFactory;
168   
169   /**
170    * Jivan Factory.
171    */

172   protected JivanFactory jivanFactory;
173   
174   
175   protected MBeanServer JavaDoc server = null;
176   protected ApplicationConfigMBean appConfigMBean;
177   protected DatabaseManagerMBean databaseManagerMBean;
178   protected PresentationManagerMBean presentationManagerMBean;
179   protected SessionManagerMBean sessionManagerMBean;
180   protected DatabaseMBean databaseMBean;
181   protected TableMBean tableMBean;
182   protected ContextMBean contextMBean;
183   
184   /** DACHA & TUFA
185    * Variable which determine should we keep
186    * SessionManager in memory.
187    */

188   private boolean isMemoryPersistence = false;
189
190   /**
191    * A constructor with no arguments is required.
192    */

193   public StandardApplication() {}
194
195   /**
196    * Get the application state.
197    * N.B. Purposely not syncronized for speed.
198    *
199    * @return
200    * The application's state code.
201    */

202   public int getState() {
203     return state;
204   }
205
206   /**
207    * Tells the application if a cookie is used to bind new sessions
208    * to a client. If no cookie is set, session ID's must be
209    * communicated by means of URL rewriting.
210    * @param flag indicates whether to send a cookie or not.
211    */

212   public void setCookieForNewSession(boolean flag) {
213     sendCookieForNewSession = flag;
214   }
215
216   /**
217    * Get the application's config object.
218    *
219    * @return
220    * The application's config object.
221    */

222   public Config getConfig() {
223     return config;
224   }
225
226   /**
227    * Set the application name.
228    *
229    * @param name The new name for the application.
230    */

231   public void setName(String JavaDoc applName) {
232     appName = applName;
233   }
234
235   /**
236    * Get the application symbolic name. This is normally the
237    * package name of this application class. <P>
238    * N.B. Purposely not syncronized for speed.
239    *
240    * @return
241    * The symbolic name.
242    */

243   public String JavaDoc getName() {
244     return appName;
245   }
246
247   /**
248    * Set the <CODE>LogChannel</CODE> associated with this application.
249    *
250    * @param The <CODE>LogChannel</CODE> to write to.
251    */

252   public void setLogChannel(LogChannel chan) {
253     logChannel = chan;
254   }
255
256   /**
257    * Get the <CODE>LogChannel</CODE> associated with this application.
258    *
259    * @return The log channel or <CODE>null</CODE> if this application
260    * does not have one.
261    */

262   public LogChannel getLogChannel() {
263     return logChannel;
264   }
265
266   /**
267    * Start the application. The default method sets the state to
268    * <CODE>RUNNING</CODE>.
269    *
270    * @param appConfig
271    * Application configuration object.
272    * @exception ApplicationException
273    * If an error occurs starting the application.
274    */

275   public synchronized void startup(Config appConfig) throws
276       ApplicationException {
277     if (state == RUNNING) {
278       return; // Handle multiple threads doing a startup.
279
}
280     printCopyrightHeader();
281     /**
282      * Read config object.
283      */

284     Config sessionConfig, databaseConfig = null;
285     try {
286       if (appConfig.containsKey("Application")) {
287         defaultUrl = appConfig.getString("Application.DefaultUrl");
288       }
289       sessionConfig = (Config) appConfig.getSection("SessionManager");
290       //DACHA 12.05.2003
291
// databaseConfig = (Config)appConfig.getSection("DatabaseManager");
292
}
293     catch (KeywordValueException except) {
294       throw new ApplicationException(except);
295     }
296     //DACHA 12.05.2003 do not throw exception if databaseConfig is null
297
try {
298       databaseConfig = (Config) appConfig.getSection("DatabaseManager");
299       if (databaseConfig != null && appName != null) {
300         databaseConfig.set("DatabaseManager.AppName", (Object JavaDoc) appName);
301       }
302     } catch (KeywordValueException except) {
303       logChannel.write(Logger.DEBUG,
304                        "Application configured without DatabaseManager.");
305     }
306     
307     /**
308      * Create session manager...
309      */

310     sessionManager = createSessionManager(sessionConfig);
311     
312     /**
313      * Create database manager if required...
314      */

315     boolean hasDatabaseConfig = databaseConfig != null;
316     
317     if (hasDatabaseConfig) {
318       databaseManager = createDatabaseManager(databaseConfig);
319     }
320     
321     /**
322      * Remember config object...
323      */

324     config = appConfig;
325     
326     /**
327      * register Application Coinfiguration MBean
328      */

329     registerApplicationMBean();
330     registerSessionManagerMBean();
331     registerPresentationManagerMBean();
332     registerContextMBean();
333     
334     if (hasDatabaseConfig) {
335         registerDatabaseManagerMBean();
336         registerTableMBeans();
337         String JavaDoc [] dbNames = databaseManager.getLogicalDatabaseNames();
338         for (int i=0;i<dbNames.length;i++){
339             registerDatabaseMBean(dbNames[i]);
340         }
341     }
342     
343     state = RUNNING;
344   }
345
346   public void printCopyrightHeader() {
347     /**
348      * Print out a copyright notice. In most cases this will
349      * fulfill a third party's copyright obligations when using Enhydra.
350      */

351    }
352
353   /**
354    * Continue the startup up process with the application is in the
355    * <CODE>INCOMPLETE</CODE> state. The default method generates an
356    * error, as the application should never be in the <CODE>INCOMPLETE</CODE>
357    * state if it doesn't implment this method.
358    *
359    * @param appConfig
360    * The same <CODE>appConfig</CODE> object that was passed to
361    * <CODE>startup</CODE>.
362    * @exception ApplicationException
363    * If an error occurs restarting the application.
364    */

365   public synchronized void restartup(Config appConfig) throws
366       ApplicationException {
367     throw new ApplicationException("no support for INCOMPLETE state");
368   }
369
370   /**
371    * Shutdown the application. The default method sets the state to
372    * <CODE>STOPPED</CODE>.
373    */

374   public synchronized void shutdown() {
375     if (state == STOPPED) {
376       return; // Handle multiple threads doing a shutdown.
377
}
378     
379     // Unregister previously registered application MBeans
380
try{
381         unRegisterApplicationMBean();
382         unRegisterSessionManagerMBean();
383         unRegisterPresentationManagerMBean();
384         unRegisterDatabaseManagerMBean();
385         unRegisterContextMBean();
386         
387         if (databaseManager!=null) {
388             unRegisterTableMBeans();
389             unRegisterDatabaseManagerMBean();
390             String JavaDoc [] dbNames = databaseManager.getLogicalDatabaseNames();
391             for (int i=0;i<dbNames.length;i++){
392                 unRegisterDatabaseMBean(dbNames[i]);
393             }
394         }
395         
396     }catch (Exception JavaDoc e) {
397          logChannel.write(Logger.DEBUG, e.toString());
398     }
399     
400     if (sessionManager != null) {
401       sessionManager.shutdown();
402       sessionManager = null;
403     }
404     if (databaseManager != null) {
405       databaseManager.shutdown();
406       databaseManager = null;
407     }
408     
409     state = STOPPED;
410   }
411
412   
413   /**
414    * Shutdown the application. The default method sets the state to
415    * <CODE>STOPPED</CODE>.
416    */

417   public synchronized void shutdownWithoutMBeanUnRegistration() {
418     if (state == STOPPED) {
419       return; // Handle multiple threads doing a shutdown.
420
}
421     
422     if (sessionManager != null) {
423       sessionManager.shutdown();
424       sessionManager = null;
425     }
426     if (databaseManager != null) {
427       databaseManager.shutdown();
428       databaseManager = null;
429     }
430     
431     state = STOPPED;
432   }
433
434   /**
435    * Create the session manager to be used by this application. By
436    * default this will return the <EM>Lutris</EM> standard session manager.
437    * This method can be overwritten to create a custom session
438    * manager.
439    *
440    * @param sessionMgrConfig
441    * Configuration object containing "SessionManager" keys.
442    * This can be <CODE>null</CODE> to use defaults.
443    * @exception ApplicationException
444    * If an error occurs in creating a session manager.
445    * @return
446    * The session manager.
447    */

448   protected SessionManager createSessionManager(Config sessionMgrConfig) throws
449       ApplicationException {
450     if (sessionMgrConfig == null) {
451       sessionMgrConfig = new Config();
452     }
453     try {
454       /*DACHA & TUFA
455        * Config file specified should we keep
456        * SessionManager in memory.
457        */

458       String JavaDoc sessionMgr;
459       if (sessionMgrConfig.containsKey("Class")) {
460         sessionMgr = sessionMgrConfig.getString("Class");
461       }
462       else {
463         sessionMgr =
464             "com.lutris.appserver.server.sessionEnhydra.StandardSessionManager";
465       }
466       Class JavaDoc sessionMgrClass = Class.forName(sessionMgr);
467       Class JavaDoc[] constructorParameterTypes = new Class JavaDoc[3];
468       constructorParameterTypes[0] = Class.forName(
469           "com.lutris.appserver.server.Application");
470       constructorParameterTypes[1] = Class.forName("com.lutris.util.Config");
471       constructorParameterTypes[2] = Class.forName(
472           "com.lutris.logging.LogChannel");
473       Constructor JavaDoc sessionMgrConstructor = sessionMgrClass.getConstructor(
474           constructorParameterTypes);
475       if (sessionMgrConfig.containsKey("MemoryPersistence")) {
476         String JavaDoc mp = sessionMgrConfig.getString("MemoryPersistence");
477         if (mp.equals("true")) {
478           isMemoryPersistence = true;
479         }
480       }
481       SessionManager sm = null;
482       if (this.appName != null) {
483         sm = MemoryPersistence.getSessionManager(this.appName);
484       }
485       if (isMemoryPersistence && (sm != null)) {
486         return sm;
487       }
488       else {
489         // v. strahinja, 26 sep 2002 return new StandardSessionManager(this, sessionMgrConfig, logChannel);
490
Object JavaDoc[] parameters = new Object JavaDoc[3];
491         parameters[0] = this;
492         parameters[1] = sessionMgrConfig;
493         parameters[2] = logChannel;
494         SessionManager sessionManager = (SessionManager) sessionMgrConstructor.
495             newInstance(parameters);
496         return sessionManager;
497       }
498     }
499     catch (Exception JavaDoc except) {
500       throw new ApplicationException(except);
501     }
502   }
503
504   /**
505    * Create the database manager to be used by this application. By
506    * default this will return the <EM>Lutris</EM>
507    * <CODE>StandardDatabaseManager</CODE>.
508    * This method can be overwritten to create a custom session
509    * manager.
510    *
511    * @param databaseMgrConfig
512    * Configuration object containing "DatabaseManager" keys.
513    * @exception ApplicationException
514    * If an error occurs in creating a database manager.
515    */

516   protected DatabaseManager createDatabaseManager(Config databaseMgrConfig) throws
517       ApplicationException {
518     try {
519      String JavaDoc databaseMgr;
520      if (databaseMgrConfig.containsKey("Class")) {
521         databaseMgr = databaseMgrConfig.getString("Class");
522       }
523       else {
524         databaseMgr =
525             STANDARD_DATABASE_MANAGER_CLASS_NAME;
526       }
527       Class JavaDoc standardDbManagerClass = Class.forName(databaseMgr);
528       Class JavaDoc[] ArgClassArray = new Class JavaDoc[] {
529           Config.class
530       };
531       Object JavaDoc[] ArgObject = new Object JavaDoc[] {
532           databaseMgrConfig
533       };
534       Constructor JavaDoc standardDbManager = standardDbManagerClass.
535           getDeclaredConstructor(ArgClassArray);
536       return (DatabaseManager) (standardDbManager.newInstance(ArgObject));
537     }
538     catch (Exception JavaDoc except) {
539       throw new ApplicationException(except);
540     }
541   }
542
543   /**
544    * Create a new session for application. By default this will create
545    * the <EM>Lutris</EM> <CODE>StandardSession</CODE>.
546    * This method can be overwritten to create a custom session.
547    *
548    * @param comms
549    * Object containing request, response and redirect objects.
550    * <I>Warning: comms.session and comms.sessionData will be null.
551    * they are filled in after this method returns.</I>
552    * @return
553    * The session.
554    * @exception ApplicationException
555    * If an error occurs in creating the session.
556    */

557   protected Session createSession(HttpPresentationComms comms) throws
558       ApplicationException {
559     try {
560       return sessionManager.createSession(comms);
561     }
562     catch (Exception JavaDoc exception) {
563       throw new ApplicationException(exception);
564     }
565   }
566
567   /**
568    * Default method used by <CODE>requestPreprocessor</CODE>
569    * to ensure that a session exists and initialize the
570    * <CODE>session</CODE> and <CODE>sessionData</CODE> fields
571    * in the <CODE>HttpPresentationComms</CODE> object.
572    * New sessions are only created on requests to presentation
573    * objects, not requests for other types of files (such as gifs).
574    * This avoids allocating multiple sessions when a browser makes
575    * multiple requests for HREFs. If the session already exist, it
576    * is alwasy set in <CODE>comms</CODE><P>
577    *
578    * This normally looks up the session using a session key from
579    * a cookie.
580    *
581    * @param comms
582    * Object containing request, response and redirect objects.
583    * @exception ApplicationException
584    * If an error occurs setting up the session.
585    */

586   protected void ensureSession(HttpPresentationComms comms) throws
587       ApplicationException {
588     try {
589       if (presentationManager.isPresentationRequest(comms.request)) {
590         // FIX - verify OK
591
comms.session = StandardAppUtil.getRequestSession(comms);
592       }
593       if (comms.session != null &&
594           sessionManager.sessionExists(comms.session.getSessionKey())) {
595         /*
596          * InitializeNewSession() sets up comms.sessionData, so
597          * that it may be used if an application defines it's own
598          * version of that method (after calling the super method,
599          * it has a normal comms object to work with).
600          * Therefore, if we did not call initializeNewSession(),
601          * we have to initialize comms.sessionData here.
602          */

603         comms.sessionData = comms.session.getSessionData();
604       }
605       else {
606         if (presentationManager.isPresentationRequest(comms.request)) {
607           initializeNewSession(comms);
608         }
609       }
610     }
611     catch (HttpPresentationException except) {
612       throw new ApplicationException(except);
613     }
614     catch (SessionException except) {
615       throw new ApplicationException(except);
616     }
617   }
618
619   /**
620    * Calls application session manager's <i>passivateSession</i> method
621    * for the session associated with this request.
622    *
623    * @param comms
624    * Object containing request, response and redirect objects.
625    * @exception ApplicationException
626    * If the session manager was unable to "passivate" the session.
627    * @see com.lutris.appserver.server.session.SessionManager.passivateSession
628    */

629   public void requestPostProcessor(HttpPresentationComms comms) throws
630       ApplicationException {
631     try {
632       if (comms.session != null) {
633         comms.application.getSessionManager().passivateSession(Thread.
634             currentThread(),
635             comms.session.getSessionKey());
636       }
637     }
638     catch (SessionException e) {
639       throw new ApplicationException(e);
640     }
641   }
642
643   /**
644    * This is called when no valid session is found in an incoming request.
645    * A new session is created and added to <CODE>comms</CODE>. If
646    * sending session cookies is enabled, a cookie is created and
647    * added to the response, so future requests will be associated
648    * with the newly created session. If sending session cookies is
649    * disabled, it is the application's responsibility to include
650    * the session ID in URLs to associate further requests with the
651    * session.<P>
652    *
653    * <I>Warning:</I> At first <CODE>comms.session</CODE>
654    * and <CODE>comms.sessionData</CODE> are null. This method initializes
655    * them both.
656    *
657    * @param comms
658    * Object containing request, response and redirect objects. Session
659    * and SessionData objects are initialized.
660    * @exception ApplicationException
661    * If an error occurs setting up the session.
662    * @see #setCookieForNewSession
663    */

664   protected void initializeNewSession(HttpPresentationComms comms) throws
665       ApplicationException {
666     comms.session = createSession(comms);
667     if (sendCookieForNewSession) {
668       StandardAppUtil.bindSessionToClient(comms);
669     }
670     comms.sessionData = comms.session.getSessionData();
671   }
672
673   /**
674    * Returns the specified url rewritten to include the sessionId
675    *
676    * @param url String to urlencode
677    * @return the param url rewritten to contain the sessionId
678    */

679   public String JavaDoc encodeUrl(String JavaDoc url, String JavaDoc sessionKey) throws
680       ApplicationException {
681     return StandardAppUtil.encodeUrl(url, sessionKey);
682   }
683
684   /**
685    * Returns the specified url rewritten to include the sessionId
686    *
687    * @param url String to urlencode
688    * @return the param url rewritten to contain the sessionId
689    * @deprecated Use encodeUrl(String,String)
690    */

691   public String JavaDoc encodeUrl(String JavaDoc url, String JavaDoc sessionKey, String JavaDoc appName) throws
692       ApplicationException {
693     return StandardAppUtil.encodeUrl(url, sessionKey);
694   }
695
696   /**
697    * Default application request preprocessor. This method sets up
698    * a session data structure if a cookie is not set for the application.
699    * It doesn't require a login however. The unauthenticated session is
700    * useful for persistence in simple applications. It is possible to
701    * later force a login. If the URL is not a reference to a presentation
702    * object, then a session will not be allocated if it does not already
703    * exist. This prevents allocation of multiple sessions when a browser
704    * is requesting other objects, such as gifs, in parallel. Thus, after
705    * this function is called, it is possible for session to be null. <P>
706    *
707    * N.B. Purposely not syncronized for speed/concurrency.
708    *
709    * @param comms
710    * Object containing request, response and redirect objects.
711    * @return
712    * Always returns false, as request handling is not done.
713    * @exception Exception
714    * May throw any exception, as with a presentation object;
715    * including page redirects.
716    */

717   public boolean requestPreprocessor(HttpPresentationComms comms) throws
718       Exception JavaDoc {
719     /**
720      * Remap / ---> "defaultUrl" if defined.
721      */

722     if (defaultUrl != null) {
723       String JavaDoc ap = comms.request.getApplicationPath();
724       if (!ap.endsWith("/")) {
725         ap += "/";
726       }
727       String JavaDoc page = comms.request.getPresentationObjectPath();
728       if (!page.endsWith("/")) {
729         page += "/";
730       }
731       if (page.equals(ap)) {
732         // Don't want two slashes in a row.
733
String JavaDoc target = comms.request.getHttpServletRequest().getContextPath();
734         if (target.equals("/")) {
735           target = "";
736         }
737         target = "";
738         if (defaultUrl.startsWith("/")) {
739           target += ap + defaultUrl.substring(1);
740         }
741         else {
742           target += ap + defaultUrl;
743         }
744         // get query string and add it to target
745
String JavaDoc query = comms.request.getQueryString();
746         if (query != null) {
747           target += "?" + query;
748         }
749         
750         /**
751          * Initialize session if one doesn't exist
752          */

753         if (StandardAppUtil.getRequestSession(comms) == null){
754             initializeNewSession(comms);
755         }
756               
757         /**
758          * Set URL encoding for the first application page
759          * to enable further session propagation
760          */

761         try {
762             if (sessionManager instanceof StandardSessionManager){
763                 if (((StandardSessionManager)sessionManager).getEncodeFirstUrl()){
764                     comms.request.setRequestedSessionIdFromUrl(true);
765                 }
766             }
767         } catch (Throwable JavaDoc trowable){}
768         
769         throw new ClientPageRedirectException(target);
770       }
771     }
772     // Only need the session if we haven't redirected to a new page.
773
ensureSession(comms);
774     return false; // Proceed normally.
775
}
776
777   /**
778    * Get the <CODE>SessionManager</CODE> associated with this application.
779    *
780    * @return
781    * The session manager or <CODE>null</CODE> if the application
782    * doesn't have a <CODE>SessionManager</CODE>.
783    */

784   public SessionManager getSessionManager() {
785     return sessionManager;
786   }
787
788   /**
789    * Get the <CODE>DatabaseManager</CODE> associated with this application.
790    *
791    * @return
792    * The database manager or <CODE>null</CODE> if the application
793    * doesn't have a <CODE>DatabaseManager</CODE>.
794    */

795   public DatabaseManager getDatabaseManager() {
796     return databaseManager;
797   }
798
799   /**
800    * Get the <CODE>HttpPresentationManager</CODE> associated with this
801    * application.
802    *
803    * @return The presentation manager.
804    */

805   public HttpPresentationManager getHttpPresentationManager() {
806     return presentationManager;
807   }
808
809   /**
810    * Tells the application about the Presentation Manager running it.
811    * This is necessary because the presentation manager is created
812    * before the application.
813    *
814    * @param pm The HTTP presentation manager running this application.
815    */

816   public void setHttpPresentationManager(HttpPresentationManager pm) {
817     presentationManager = pm;
818   }
819
820   /**
821    * This is a hook that allows applications to act on requests before
822    * they enter the Enhydra framework. This implementation always returns
823    * false, so the request is processed normally. <B>Do not override this
824    * unless you absolutly have to.</B> Currently the only application
825    * that needs to is the debugger, because it needs to hand off requests
826    * to other non-Enhydra servlets. <P>
827    *
828    * In contrast, the method requestPreprocessor() is commonly overridden.
829    * It provides applications with a centeral place to put code that has
830    * to be run on every request before it is sent to the presentation
831    * objects.
832    *
833    * @param servlet
834    * The servlet we are running in.
835    * @param context
836    * The ServletContext that was used to initialize our servlet.
837    * @param request
838    * The incomming request object.
839    * @param response
840    * The incomming response object.
841    * @return
842    * True if this method handled the request, in which case no
843    * further action will be taken. Or false if normal processing
844    * should continue.
845    * @exception ServletException
846    * You are allowed to throw the same exceptions that the servlet's
847    * service() method throws.
848    * @exception IOException
849    * You are allowed to throw the same exceptions that the servlet's
850    * service() method throws.
851    */

852   public boolean servletRequestPreprocessor(Servlet JavaDoc servlet,
853                                             ServletContext JavaDoc context,
854                                             HttpServletRequest JavaDoc request,
855                                             HttpServletResponse JavaDoc response) throws
856       ServletException JavaDoc,
857       IOException JavaDoc {
858     return false;
859   }
860
861   /**
862    * Get the XMLC factory object being used by the application.
863    */

864   public XMLCFactory getXMLCFactory() {
865     return xmlcFactory;
866   }
867
868   /**
869    * Set the XMLC factory based on the deferred parsing option.
870    */

871   public void setXMLCFactory(boolean enableDeferredParsing) {
872     if (enableDeferredParsing) {
873       xmlcFactory = new XMLCDeferredParsingFactory(new DocumentLoaderImpl(),
874           (MultiClassLoader) presentationManager.getAppClassLoader(),
875           new EnhydraXMLCLogger(logChannel));
876     }
877     else {
878       xmlcFactory = new XMLCStdFactory(presentationManager.getAppClassLoader(),
879                                        new EnhydraXMLCLogger(logChannel));
880     }
881   }
882
883   /**
884    * Initializes the Jivan factory object which can be used by application.
885    * @param reload swich which indicates realoading status of Jivan generated
886    * pages in presentation layer (true = reload is on, false = reload is off)
887    */

888   public void setJivanFactory(boolean reload) {
889     this.jivanFactory = new JivanFactory(reload, this.logChannel);
890   }
891
892   /**
893    * Get the Jivan factory object being used by the application.
894    */

895   public JivanFactory getJivanFactory() {
896     return this.jivanFactory;
897   }
898   
899
900   /**
901    * Get the MBeanServer object being used by the application.
902    */

903   private MBeanServer JavaDoc findMBeanServer() throws com.lutris.appserver.server.
904
      session.SessionException {
905     MBeanServer JavaDoc mBeanServer;
906     try {
907       java.util.ArrayList JavaDoc server = MBeanServerFactory.findMBeanServer(null);
908       if (server == null) {
909         return null;
910       }
911       else {
912         mBeanServer = (MBeanServer JavaDoc) server.get(0);
913       }
914     }
915     catch (Exception JavaDoc e) {
916       throw new com.lutris.appserver.server.session.SessionException(e);
917     }
918     return mBeanServer;
919   }
920   
921   /**
922    * Get the Application Info HTML presentation.
923    */

924   public String JavaDoc toHtml() {
925     return "No Application Info";
926   }
927   
928   /**
929    * Application MBean definition section
930    *
931    * Definitions of application MBean implementations.
932    * All present MBean Implementations extend basic
933    * EafConfigMBean implementation which defines basic
934    * Config MBean actions.
935    **/

936   
937   private void registerApplicationMBean(){
938       if (appName == null) {
939         return;
940       }
941       
942