001: // THIS SOFTWARE IS PROVIDED BY SOFTARIS PTY.LTD. AND OTHER METABOSS
002: // CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
003: // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
004: // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTARIS PTY.LTD.
005: // OR OTHER METABOSS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
006: // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
007: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
008: // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
009: // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
010: // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
011: // EVEN IF SOFTARIS PTY.LTD. OR OTHER METABOSS CONTRIBUTORS ARE ADVISED OF THE
012: // POSSIBILITY OF SUCH DAMAGE.
013: //
014: // Copyright 2000-2005 © Softaris Pty.Ltd. All Rights Reserved.
015: package com.metaboss.enterprise.xi.enhydrabarracuda;
016:
017: import java.io.IOException;
018: import java.io.PrintWriter;
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Map;
023: import java.util.TreeMap;
024:
025: import javax.servlet.ServletConfig;
026: import javax.servlet.ServletException;
027: import javax.servlet.http.HttpServlet;
028: import javax.servlet.http.HttpServletRequest;
029: import javax.servlet.http.HttpServletResponse;
030: import javax.servlet.http.HttpSession;
031:
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034: import org.enhydra.barracuda.core.comp.BComponent;
035: import org.enhydra.barracuda.core.comp.DefaultViewContext;
036: import org.enhydra.barracuda.core.comp.RenderException;
037: import org.enhydra.barracuda.core.comp.ViewContext;
038: import org.enhydra.barracuda.core.event.ClientSideRedirectException;
039: import org.enhydra.barracuda.core.event.EventException;
040: import org.enhydra.barracuda.core.helper.servlet.DefaultServletRequestWrapper;
041: import org.enhydra.barracuda.core.helper.servlet.ScriptDetector;
042: import org.enhydra.barracuda.core.util.dom.DOMWriter;
043: import org.enhydra.barracuda.core.util.dom.DefaultDOMWriter;
044: import org.enhydra.barracuda.core.util.http.URLRewriter;
045: import org.enhydra.barracuda.core.view.ViewCapabilities;
046: import org.enhydra.barracuda.plankton.data.ObjectRepository;
047: import org.enhydra.barracuda.plankton.exceptions.ExceptionUtil;
048: import org.enhydra.barracuda.plankton.exceptions.NestableException;
049: import org.enhydra.xml.io.OutputOptions;
050: import org.w3c.dom.Document;
051: import org.w3c.dom.html.HTMLBodyElement;
052: import org.w3c.dom.html.HTMLDivElement;
053: import org.w3c.dom.html.HTMLDocument;
054: import org.w3c.dom.html.HTMLElement;
055: import org.w3c.dom.html.HTMLHRElement;
056: import org.w3c.dom.html.HTMLHeadingElement;
057: import org.w3c.dom.html.HTMLLIElement;
058: import org.w3c.dom.html.HTMLUListElement;
059:
060: import com.metaboss.enterprise.ui.UIException;
061: import com.metaboss.util.StringUtils;
062:
063: /** This servlet drives MetaBoss web application */
064: public class ApplicationServlet extends HttpServlet {
065: // Static logging instance
066: private static final Log sLogger = LogFactory
067: .getLog(ApplicationServlet.class);
068:
069: // Store of creation metadata for already loaded pages. Structure is stored
070: // indexed by Relative Path - after context before query
071: private class PageCreationMetadata {
072: public Class mResourceClass = null;
073: public Class mApplicationClass = null;
074: }
075:
076: private static HashMap sDocumentClassesStorage = new HashMap();
077:
078: private boolean sUseHierarchicalDataStore = false;
079: private boolean sCreateDebugOutput = false;
080:
081: /** Initialisation method */
082: public void init() throws ServletException {
083: ServletConfig lConfig = getServletConfig();
084: // See if we need hierarchcal datastore
085: String lUseHierarchicalDataStore = lConfig
086: .getInitParameter("useHierarchicalDataStore");
087: if (lUseHierarchicalDataStore != null)
088: sUseHierarchicalDataStore = Boolean.valueOf(
089: lUseHierarchicalDataStore).booleanValue();
090: // See if we need debug output
091: String lCreateDebugOutput = lConfig
092: .getInitParameter("createDebugOutput");
093: if (lCreateDebugOutput != null)
094: sCreateDebugOutput = Boolean.valueOf(lCreateDebugOutput)
095: .booleanValue();
096: }
097:
098: public static boolean sPrintPretty = false;
099: public static boolean sPreventCaching = false;
100: public static int sMaxAge = 0;
101: public boolean recycleChildren = false;
102:
103: //-------------------- ComponentGateway ----------------------
104: /**
105: * <p>Handle the default HttpRequest. This is the method developers
106: * will typically override. The developers shaould add any components
107: * to the root component and then return the underlying DOM Document (that
108: * backs their components) so it can be rendered
109: *
110: * @param root the root component which will get rendered as a result
111: * of this request
112: * @param vc the ViewContext object describes what features the
113: * client view is capable of supporting
114: * @param req the servlet request
115: * @param req the servlet response
116: * @return the Document to be rendered
117: * @throws ServletException
118: * @throws IOException
119: */
120: public Document handleDefault(BComponent root, ViewContext vc,
121: HttpServletRequest req, HttpServletResponse resp)
122: throws ServletException, IOException, RenderException,
123: EventException {
124: return null;
125: }
126:
127: /**
128: * <p>Handle an EventException. Basically, this is where we handle the
129: * really bad, unexpected type of event exceptions. Generally, as you code,
130: * if you want to interrupt the dispatch and fire a new event, you should
131: * throw an InterruptDispatchException. Only throw EventExceptions in
132: * truly exceptional circumstances.
133: *
134: * @param vc the ViewContext object describes what features the
135: * client view is capable of supporting
136: * @param req the servlet request
137: * @param req the servlet response
138: * @throws ServletException
139: * @throws IOException
140: */
141: public void handleEventException(EventException e, ViewContext vc,
142: HttpServletRequest req, HttpServletResponse resp)
143: throws ServletException, IOException {
144: //first see what the base exception is...if it's a servlet exception
145: //or an IOException, rethrow it...
146: Exception rootException = NestableException.getRootException(e);
147: if (rootException instanceof ServletException)
148: throw (ServletException) rootException;
149: if (rootException instanceof IOException)
150: throw (IOException) rootException;
151:
152: //csc_061202.1 - added
153: //set the caching hdrs (this will allow the static resources to be cached by the browser)
154: resp.setHeader("Cache-Control", "max-age=0");
155: resp.setDateHeader("Last-Modified", System.currentTimeMillis());
156:
157: //if we get an EventException, log it and print the base exception
158: resp.setContentType("text/html");
159: PrintWriter out = resp.getWriter();
160: ExceptionUtil.logExceptionAsHTML(out, e, req);
161: sLogger.warn("Unexpected event exception: ", e);
162: if (rootException != e) {
163: sLogger.warn("Root Exception: ", rootException);
164: }
165: }
166:
167: /**
168: * <p>Handle a RenderException. Basically, this is where we handle the
169: * really bad, unexpected type of errors that occur while unexpectedldy
170: * rendering the component hierarchy.
171: *
172: * @param vc the ViewContext object describes what features the
173: * client view is capable of supporting
174: * @param req the servlet request
175: * @param req the servlet response
176: * @throws ServletException
177: * @throws IOException
178: */
179: public void handleRenderException(RenderException e,
180: ViewContext vc, HttpServletRequest req,
181: HttpServletResponse resp) throws ServletException,
182: IOException {
183: //first see what the base exception is...if it's a servlet exception
184: //or an IOException, rethrow it...
185: Exception rootException = NestableException.getRootException(e);
186: if (rootException instanceof ServletException)
187: throw (ServletException) rootException;
188: if (rootException instanceof IOException)
189: throw (IOException) rootException;
190:
191: //csc_061202.1 - added
192: //set the caching hdrs (this will allow the static resources to be cached by the browser)
193: resp.setHeader("Cache-Control", "max-age=0");
194: resp.setDateHeader("Last-Modified", System.currentTimeMillis());
195:
196: //if we get a RenderException, log it and print the base exception
197: resp.setContentType("text/html");
198: PrintWriter out = resp.getWriter();
199: ExceptionUtil.logExceptionAsHTML(out, e, req);
200: sLogger.warn("Unexpected event exception: ", e);
201: if (rootException != e) {
202: sLogger.warn("Root Exception:", rootException);
203: }
204: }
205:
206: /**
207: * <p>Get a DOMWriter. By default, we use a DefaultDOMWriter. If
208: * you'd like to use something else, override this method.
209: *
210: * @return a DOMWriter to be used to render the DOM
211: */
212: public DOMWriter getDOMWriter() {
213: //return DefaultDOM writer
214: OutputOptions lOutputOptions = new OutputOptions();
215: lOutputOptions.setFormat(OutputOptions.FORMAT_HTML);
216: lOutputOptions.setPrettyPrinting(sPrintPretty);
217: return new DefaultDOMWriter(lOutputOptions, sPrintPretty,
218: sPreventCaching, sMaxAge);
219: }
220:
221: /** Handle GET action */
222: protected void doGet(HttpServletRequest pHttpRequest,
223: HttpServletResponse pHttpResponse) throws ServletException,
224: IOException {
225: performAction(pHttpRequest, pHttpResponse);
226: }
227:
228: /** Handle POST action */
229: protected void doPost(HttpServletRequest pHttpRequest,
230: HttpServletResponse pHttpResponse) throws ServletException,
231: IOException {
232: performAction(pHttpRequest, pHttpResponse);
233: }
234:
235: /** Default implementation of the http request handler */
236: private void performAction(HttpServletRequest pHttpRequest,
237: HttpServletResponse pHttpResponse) throws ServletException,
238: IOException {
239: try {
240: Application lApplication = null;
241: String lSourceNavigationInstanceId = null;
242: String lSourcePageId = null;
243: String lSourceFormResourceId = null;
244: String lSourceAnchorResourceId = null;
245: // Get session and application object
246: HttpSession lSession = pHttpRequest.getSession(true);
247: if (lSession.isNew()) {
248: System.out.println("New session detected : "
249: + lSession.getId());
250: // Create application object and add it to the session
251: lSession.setAttribute("Application",
252: lApplication = new Application());
253: lApplication
254: .setUseHierarchicalDataStore(sUseHierarchicalDataStore);
255: // Source navigation is ignored as this is a new hit
256: // Latter on we may check if there was navigation id on url and warn that page has expired
257: lSourceNavigationInstanceId = null;
258: lSourcePageId = null;
259: lSourceFormResourceId = null;
260: lSourceAnchorResourceId = null;
261: } else {
262: System.out.println("Old session detected : "
263: + lSession.getId());
264: lApplication = (Application) lSession
265: .getAttribute("Application");
266: if (lApplication == null)
267: throw new ServletException(
268: "Unable to find Application object inside existing HTTPSession");
269: // Note that if this is fresh entry to this application (i.e. refresh of the home page would
270: // result in url without navigation id arriving to already established application) than
271: // lSourceNavigationInstanceId will be null. All it means that there will be new alternative
272: // navigation tree established inside application object
273: lSourceNavigationInstanceId = pHttpRequest
274: .getParameter(Constants.NAVIGATION_INSTANCE_REQUEST_PARAMETER_NAME);
275: // If we have got navigation instance where we came from - we can process form submits see if this navigation
276: // is the result of form action this would be indicated by the presence of form resource id in request
277: if (lSourceNavigationInstanceId != null) {
278: lSourcePageId = pHttpRequest
279: .getParameter(Constants.PAGE_ID_REQUEST_PARAMETER_NAME);
280: lSourceFormResourceId = pHttpRequest
281: .getParameter(Constants.FORM_ID_REQUEST_PARAMETER_NAME);
282: lSourceAnchorResourceId = pHttpRequest
283: .getParameter(Constants.ANCHOR_ID_REQUEST_PARAMETER_NAME);
284: }
285: }
286:
287: // Find out the name of the application class and the name of the resource class to load
288: String lContextPath = pHttpRequest.getContextPath();
289: String lRequestURI = pHttpRequest.getRequestURI();
290: String lDestinationRelativePath = lRequestURI
291: .substring(lContextPath.length() + 1);
292: // Register this navigation move and execute action
293: Map lParameterMap = pHttpRequest.getParameterMap();
294: Application.NavigationMove lThisMove = lApplication
295: .createNavigationMove(lSourceNavigationInstanceId,
296: lParameterMap);
297: // If this is a form, we need to put obtained widget values. Do not store special values
298: if (lSourceFormResourceId != null && lSourcePageId != null) {
299: // This is form submission - we may have some new values obtained from the form controls - save them
300: for (Iterator lIterator = lParameterMap.entrySet()
301: .iterator(); lIterator.hasNext();) {
302: Map.Entry lParameter = (Map.Entry) lIterator.next();
303: String lParameterKey = (String) lParameter.getKey();
304: // Do not store special values
305: if (lParameterKey
306: .equals(Constants.ANCHOR_ID_REQUEST_PARAMETER_NAME) == false
307: && lParameterKey
308: .equals(Constants.FORM_ID_REQUEST_PARAMETER_NAME) == false
309: && lParameterKey
310: .equals(Constants.NAVIGATION_INSTANCE_REQUEST_PARAMETER_NAME) == false
311: && lParameterKey
312: .equals(Constants.PAGE_ID_REQUEST_PARAMETER_NAME) == false) {
313: // Now make sure that we have something with this id. This is necessary because
314: // form submit uses name attribute and not the id attribute when posting
315: // we here want to simplify things by forgetting about the name, so what we do is
316: // making sure that the name matches id
317: Class lWidgetClass = Page.getWidgetClass(
318: lSourcePageId, lParameterKey);
319: if (lWidgetClass != null) {
320: WidgetModel lFormWidgetModel = lThisMove
321: .getFormWidgetModel(lSourcePageId,
322: lSourceFormResourceId,
323: lParameterKey);
324: if (lFormWidgetModel != null)
325: lFormWidgetModel
326: .applyFormValues((String[]) lParameter
327: .getValue());
328: } else
329: sLogger
330: .warn("Unable to find widget with Id = "
331: + lParameterKey
332: + " on the source page. Widget value will not be saved");
333: }
334: }
335: // Execute action (if there is one associated with the form)
336: // This may result in redirection
337: String lRedirectedRelativePath = Action
338: .processFormAction(lSourcePageId,
339: lSourceFormResourceId, lApplication,
340: lThisMove);
341: if (lRedirectedRelativePath != null)
342: lDestinationRelativePath = lRedirectedRelativePath;
343: }
344:
345: // Obtain the class representing the document
346: // Load class from the cache if possible, otherwise create one
347: Class lDocumentClass = (Class) sDocumentClassesStorage
348: .get(lDestinationRelativePath);
349: if (lDocumentClass == null) {
350: // We have not loaded this page yet. Analyse name and create metadata
351: int lDotHtmlPos = lDestinationRelativePath
352: .indexOf(".html");
353: if (lDotHtmlPos <= 0)
354: throw new ServletException(
355: "Unable to process requested URL : "
356: + lRequestURI);
357: String lDocumentName = lDestinationRelativePath
358: .substring(0, lDotHtmlPos);
359: String lDocumentClassName = StringUtils.replace(
360: lDocumentName, "/", ".")
361: + "HTML";
362: // If we are unable to load document class name - there is nothing we can do
363: try {
364: lDocumentClass = Class.forName(lDocumentClassName);
365: } catch (ClassNotFoundException e) {
366: throw new ServletException(e);
367: } catch (NoClassDefFoundError e) {
368: throw new ServletException(e);
369: }
370: // Store document class
371: sDocumentClassesStorage.put(lDestinationRelativePath,
372: lDocumentClass);
373: }
374:
375: // Now we have everything to create the page
376: Page lDestinationPage = Page.createInstance(lDocumentClass,
377: lApplication, lThisMove);
378: lDestinationPage.render();
379: lDestinationPage.signAnchors();
380: HTMLDocument lResultDocument = lDestinationPage
381: .getHTMLDocument();
382: if (sCreateDebugOutput)
383: appendDebugOutput(lResultDocument, lApplication,
384: lThisMove);
385: getDOMWriter().write(lResultDocument, pHttpResponse);
386: lApplication.logStatistics();
387: } catch (UIException e) {
388: throw new ServletException(e);
389: } catch (InstantiationException e) {
390: throw new ServletException(e);
391: } catch (IllegalAccessException e) {
392: throw new ServletException(e);
393: }
394: }
395:
396: /**
397: * <p>By default the OPTIONS request is mapped to the handleDefault method
398: *
399: * @param req the servlet request
400: * @param req the servlet response
401: * @throws ServletException
402: * @throws IOException
403: */
404: protected void doOptions(HttpServletRequest req,
405: HttpServletResponse resp) throws ServletException,
406: IOException {
407: handleDefault(new DefaultServletRequestWrapper(req), resp);
408: }
409:
410: /**
411: * <p>By default the DELETE request is mapped to the handleDefault method
412: *
413: * @param req the servlet request
414: * @param req the servlet response
415: * @throws ServletException
416: * @throws IOException
417: */
418: protected void doDelete(HttpServletRequest req,
419: HttpServletResponse resp) throws ServletException,
420: IOException {
421: handleDefault(new DefaultServletRequestWrapper(req), resp);
422: }
423:
424: /**
425: * <p>By default the PUT request is mapped to the handleDefault method
426: *
427: * @param req the servlet request
428: * @param req the servlet response
429: * @throws ServletException
430: * @throws IOException
431: */
432: protected void doPut(HttpServletRequest req,
433: HttpServletResponse resp) throws ServletException,
434: IOException {
435: handleDefault(new DefaultServletRequestWrapper(req), resp);
436: }
437:
438: /**
439: * <p>By default the TRACE request is mapped to the handleDefault method
440: *
441: * @param req the servlet request
442: * @param req the servlet response
443: * @throws ServletException
444: * @throws IOException
445: */
446: protected void doTrace(HttpServletRequest req,
447: HttpServletResponse resp) throws ServletException,
448: IOException {
449: handleDefault(new DefaultServletRequestWrapper(req), resp);
450: }
451:
452: protected void handleDefault(HttpServletRequest req,
453: HttpServletResponse resp) throws ServletException,
454: IOException {
455:
456: long bmillis = 0;
457: long smillis = 0;
458: long emillis = 0;
459: long elapsed1 = 0;
460: long elapsed2 = 0;
461: if (sLogger.isInfoEnabled())
462: bmillis = System.currentTimeMillis();
463: if (sLogger.isInfoEnabled())
464: sLogger.info("Handling incoming HTTP request in " + this );
465:
466: ViewContext vc = null;
467: try {
468: //Session ObjectRepository
469: ObjectRepository.setupSessionRepository(req); //csc_022101.1
470:
471: //start by figuring out the ViewCapabilities
472: if (sLogger.isDebugEnabled())
473: sLogger.debug("Create the ViewContext");
474: //csc_101701.1 vc = new DefaultViewContext(new ViewCapabilities(req, resp));
475: vc = new DefaultViewContext(
476: new ViewCapabilities(req, resp), req, resp); //csc_101701.1
477:
478: //create our root component
479: if (sLogger.isDebugEnabled())
480: sLogger.debug("Create component root");
481: BComponent broot = new BComponent();
482: broot.setName("Root");
483:
484: //give the implementation a chance to add any components to the root
485: if (sLogger.isDebugEnabled())
486: sLogger.debug("Handling default");
487: Document doc = handleDefault(broot, vc, req, resp);
488:
489: //now init the component
490: if (sLogger.isDebugEnabled())
491: sLogger
492: .debug("Invoking initCycle on component hierarchy");
493: broot.initCycle();
494:
495: //now render the component
496: if (sLogger.isDebugEnabled())
497: sLogger.debug("Rendering component hierarchy");
498: if (sLogger.isDebugEnabled())
499: smillis = System.currentTimeMillis();
500: broot.render(vc);
501: if (sLogger.isDebugEnabled())
502: elapsed1 = System.currentTimeMillis() - smillis;
503:
504: //its possible the implementor may want to recycle children...if so, remove them
505: //prior to calling destroy on the root
506: if (recycleChildren) {
507: if (sLogger.isDebugEnabled())
508: sLogger.debug("Recycling child components");
509: List children = broot.getChildren();
510: if (children != null) {
511: for (int i = children.size() - 1; i >= 0; i--) {
512: broot.removeChild(i);
513: }
514: }
515: }
516:
517: //now destroy the component
518: if (sLogger.isDebugEnabled())
519: sLogger
520: .debug("Invoking destroyCycle on component hierarchy");
521: broot.destroyCycle();
522:
523: //csc_102201.1
524: //now adjust the outgoing page (this is critical to make sure we
525: //can accurately detect client scripting)
526: ScriptDetector.prepareClientResp(doc, vc);
527:
528: //now render the page
529: if (sLogger.isDebugEnabled())
530: sLogger.debug("Rendering the DOM");
531: if (sLogger.isInfoEnabled())
532: smillis = System.currentTimeMillis();
533: this .getDOMWriter().write(doc, resp);
534: if (sLogger.isInfoEnabled()) {
535: elapsed2 = System.currentTimeMillis() - smillis;
536: emillis = System.currentTimeMillis();
537: }
538:
539: if (sLogger.isInfoEnabled())
540: sLogger.info("Dispatching complete! (rendered in "
541: + (elapsed1) + "/written in " + (elapsed2)
542: + " of " + (emillis - bmillis) + " millis)");
543:
544: } catch (ClientSideRedirectException re) {
545: //if we get a redirect exception, request the browser to redirect accordingly
546: // if (sLogger.isInfoEnabled()) sLogger.info("ClientSideRedirectException...redirecting to "+re.getRedirectURL());
547: // resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
548: // resp.setHeader("Location", re.getRedirectURL());
549:
550: String url = URLRewriter.encodeRedirectURL(req, resp, re
551: .getRedirectURL());
552: url = ScriptDetector.prepareRedirectURL(url, vc
553: .getViewCapabilities()); //csc_102501.2
554: if (sLogger.isInfoEnabled())
555: sLogger
556: .info("ClientSideRedirectException...redirecting to "
557: + url);
558: resp.sendRedirect(url);
559:
560: } catch (RenderException e) {
561: //if we get a RenderException, handle it
562: if (sLogger.isInfoEnabled())
563: sLogger.info("Handling RenderException:" + e);
564: handleRenderException(e, vc, req, resp);
565:
566: } catch (EventException e) {
567: //if we get an EventException, handle it
568: if (sLogger.isInfoEnabled())
569: sLogger.info("Handling EventException:" + e);
570: handleEventException(e, vc, req, resp);
571:
572: } finally {
573: //make sure we always clean up session/local repository stuff
574: ObjectRepository.removeSessionRepository(); //csc_022101.1
575: ObjectRepository.removeLocalRepository(); //csc_022101.1
576: }
577: }
578:
579: private void appendDebugOutput(HTMLDocument lDocument,
580: Application pApplication,
581: Application.NavigationMove pThisMove) {
582: // Create debug pane
583: HTMLElement lBodyElement = lDocument.getBody();
584: if (lBodyElement != null
585: && lBodyElement instanceof HTMLBodyElement) {
586: HTMLDivElement lDivElement = (HTMLDivElement) lDocument
587: .createElement("DIV");
588: lDivElement.setAttribute("STYLE",
589: "background:rgb(179,213,253)");
590: lBodyElement.appendChild(lDivElement);
591: {
592: HTMLHRElement lElement = (HTMLHRElement) lDivElement
593: .appendChild(lDocument.createElement("HR"));
594: lElement.setSize("5");
595: lElement.setAttribute("color", "Red");
596: }
597: {
598: HTMLHeadingElement lHeadingElement = (HTMLHeadingElement) lDivElement
599: .appendChild(lDocument.createElement("H4"));
600: lHeadingElement.appendChild(lDocument
601: .createTextNode("DEBUG INFORMATION"));
602:
603: HTMLElement lIElement = (HTMLElement) lDivElement
604: .appendChild(lDocument.createElement("I"));
605: lIElement
606: .appendChild(lDocument
607: .createTextNode("You are seeing this because creation of the debug output is enabled in servlet initialisation properties"));
608: }
609: // Now output the navigation map
610: {
611: HTMLHRElement lHRElement = (HTMLHRElement) lDivElement
612: .appendChild(lDocument.createElement("HR"));
613: lHRElement.setSize("2");
614: lHRElement.setAttribute("color", "Red");
615: HTMLHeadingElement lHeadingElement = (HTMLHeadingElement) lDivElement
616: .appendChild(lDocument.createElement("H5"));
617: lHeadingElement.appendChild(lDocument
618: .createTextNode("DATA STORE VIEW"));
619:
620: // Output navigation map
621: appendNavigationDebugInformation(lDocument,
622: lDivElement, pApplication, pThisMove);
623: }
624: // Finish it off
625: {
626: HTMLHRElement lElement = (HTMLHRElement) lDivElement
627: .appendChild(lDocument.createElement("HR"));
628: lElement.setSize("5");
629: lElement.setAttribute("color", "Red");
630: }
631: }
632: }
633:
634: // Helper. Appends navigation debug information to the ready document
635: private void appendNavigationDebugInformation(
636: HTMLDocument lDocument, HTMLElement lRootElement,
637: Application pApplication,
638: Application.NavigationMove pThisMove) {
639: HTMLUListElement lNavListElement = (HTMLUListElement) lRootElement
640: .appendChild(lDocument.createElement("UL"));
641: while (pThisMove != null) {
642: HTMLLIElement lNavElement = (HTMLLIElement) lNavListElement
643: .appendChild(lDocument.createElement("LI"));
644: {
645: lNavElement.appendChild(
646: lDocument.createElement("STRONG")).appendChild(
647: lDocument.createTextNode("Nav Id : "));
648: lNavElement.appendChild(lDocument
649: .createTextNode(pThisMove.getInstanceId()));
650: // List navigation parameters
651: Map lParameters = pThisMove.getLocalParameters();
652: if (lParameters != null
653: && lParameters.isEmpty() == false) {
654: // Sort parameters in alphabetical order
655: Map lSortedParametersMap = new TreeMap(lParameters);
656: HTMLUListElement lParameterListElement = (HTMLUListElement) lNavElement
657: .appendChild(lDocument.createElement("UL"));
658: for (Iterator lParametersIterator = lSortedParametersMap
659: .entrySet().iterator(); lParametersIterator
660: .hasNext();) {
661: Map.Entry lParameterEntry = (Map.Entry) lParametersIterator
662: .next();
663: Object lParameterKey = lParameterEntry.getKey();
664: Object lParameterValue = lParameterEntry
665: .getValue();
666: HTMLLIElement lParameterElement = (HTMLLIElement) lParameterListElement
667: .appendChild(lDocument
668: .createElement("LI"));
669: lParameterElement
670: .appendChild(
671: lDocument
672: .createElement("STRONG"))
673: .appendChild(
674: lDocument
675: .createTextNode("Navigation Parameter Name : "));
676: lParameterElement.appendChild(lDocument
677: .createTextNode(lParameterKey
678: .toString()));
679: lParameterElement
680: .appendChild(
681: lDocument
682: .createElement("STRONG"))
683: .appendChild(
684: lDocument
685: .createTextNode(" Value : "));
686: if (lParameterValue == null) {
687: lParameterElement.appendChild(lDocument
688: .createTextNode("<null>"));
689: } else if (!lParameterValue.getClass()
690: .isArray()) {
691: lParameterElement.appendChild(lDocument
692: .createTextNode("'"
693: + lParameterValue
694: .toString() + "'"));
695: } else {
696: Object[] lParameterArray = (Object[]) lParameterValue;
697: if (lParameterArray.length == 1) {
698: lParameterElement.appendChild(lDocument
699: .createTextNode("'"
700: + lParameterArray[0]
701: .toString()
702: + "'"));
703: } else {
704: StringBuffer lStringBuffer = new StringBuffer(
705: "[");
706: for (int i = 0; i < lParameterArray.length; i++) {
707: if (i > 0)
708: lStringBuffer.append(",");
709: lStringBuffer.append("'");
710: lStringBuffer
711: .append(lParameterArray[i]
712: .toString());
713: lStringBuffer.append("'");
714: }
715: lStringBuffer.append("]");
716: lParameterElement.appendChild(lDocument
717: .createTextNode(lStringBuffer
718: .toString()));
719: }
720: }
721: }
722: }
723: // Now interogate the widget values for this navigation
724: String[] lPageIds = pThisMove.getLocalPageIds();
725: if (lPageIds != null && lPageIds.length > 0) {
726: HTMLUListElement lPageListElement = (HTMLUListElement) lNavElement
727: .appendChild(lDocument.createElement("UL"));
728: for (int i = 0; i < lPageIds.length; i++) {
729: String lPageId = lPageIds[i];
730: String lPageUrl = Page.getPageUrl(lPageId);
731: HTMLLIElement lPageElement = (HTMLLIElement) lPageListElement
732: .appendChild(lDocument
733: .createElement("LI"));
734: lPageElement
735: .appendChild(
736: lDocument
737: .createElement("STRONG"))
738: .appendChild(
739: lDocument
740: .createTextNode("Page Id : "));
741: lPageElement.appendChild(lDocument
742: .createTextNode(lPageId));
743: if (lPageUrl != null) {
744: lPageElement
745: .appendChild(
746: lDocument
747: .createElement("STRONG"))
748: .appendChild(
749: lDocument
750: .createTextNode(" Page Url : "));
751: lPageElement.appendChild(lDocument
752: .createTextNode(lPageUrl));
753: }
754: // Dump Widget values for this navigation
755: Map lWidgetValuesForPage = pThisMove
756: .getLocalWidgetValues(lPageId);
757: if (lWidgetValuesForPage != null
758: && lWidgetValuesForPage.size() > 0) {
759: HTMLUListElement lWidgetListElement = (HTMLUListElement) lPageElement
760: .appendChild(lDocument
761: .createElement("UL"));
762: Iterator lPageWidgetsIterator = lWidgetValuesForPage
763: .entrySet().iterator();
764: while (lPageWidgetsIterator.hasNext()) {
765: Map.Entry lPageWidgetEntry = (Map.Entry) lPageWidgetsIterator
766: .next();
767: HTMLLIElement lPageWidgetElement = (HTMLLIElement) lWidgetListElement
768: .appendChild(lDocument
769: .createElement("LI"));
770: lPageWidgetElement
771: .appendChild(
772: lDocument
773: .createElement("STRONG"))
774: .appendChild(
775: lDocument
776: .createTextNode("Widget Id : "));
777: lPageWidgetElement
778: .appendChild(lDocument
779: .createTextNode((String) lPageWidgetEntry
780: .getKey()));
781: WidgetModel lWidgetModel = (WidgetModel) lPageWidgetEntry
782: .getValue();
783: if (lWidgetModel != null) {
784: lPageWidgetElement
785: .appendChild(
786: lDocument
787: .createElement("STRONG"))
788: .appendChild(
789: lDocument
790: .createTextNode(" Value : "));
791: lPageWidgetElement
792: .appendChild(lDocument
793: .createTextNode(lWidgetModel
794: .getDebugString()));
795: } else {
796: lPageWidgetElement
797: .appendChild(
798: lDocument
799: .createElement("STRONG"))
800: .appendChild(
801: lDocument
802: .createTextNode(" No Value "));
803: }
804: }
805: }
806: // Dump Form Widget values for this navigation
807: String[] lFormIds = pThisMove
808: .getLocalFormIds(lPageId);
809: if (lFormIds != null && lFormIds.length > 0) {
810: for (int j = 0; j < lFormIds.length; j++) {
811: String lFormId = lFormIds[j];
812: Map lWidgetValuesForForm = pThisMove
813: .getLocalFormWidgetValues(
814: lPageId, lFormId);
815: if (lWidgetValuesForForm != null
816: && lWidgetValuesForForm.size() > 0) {
817: HTMLUListElement lWidgetListElement = (HTMLUListElement) lPageElement
818: .appendChild(lDocument
819: .createElement("UL"));
820: Iterator lFormWidgetsIterator = lWidgetValuesForForm
821: .entrySet().iterator();
822: while (lFormWidgetsIterator
823: .hasNext()) {
824: Map.Entry lFormWidgetEntry = (Map.Entry) lFormWidgetsIterator
825: .next();
826: HTMLLIElement lPageWidgetElement = (HTMLLIElement) lWidgetListElement
827: .appendChild(lDocument
828: .createElement("LI"));
829: lPageWidgetElement
830: .appendChild(
831: lDocument
832: .createElement("STRONG"))
833: .appendChild(
834: lDocument
835: .createTextNode("Form Id : "));
836: lPageWidgetElement
837: .appendChild(lDocument
838: .createTextNode(lFormId));
839: lPageWidgetElement
840: .appendChild(
841: lDocument
842: .createElement("STRONG"))
843: .appendChild(
844: lDocument
845: .createTextNode(" Widget Id : "));
846: lPageWidgetElement
847: .appendChild(lDocument
848: .createTextNode((String) lFormWidgetEntry
849: .getKey()));
850: WidgetModel lWidgetModel = (WidgetModel) lFormWidgetEntry
851: .getValue();
852: if (lWidgetModel != null) {
853: lPageWidgetElement
854: .appendChild(
855: lDocument
856: .createElement("STRONG"))
857: .appendChild(
858: lDocument
859: .createTextNode(" Value : "));
860: lPageWidgetElement
861: .appendChild(lDocument
862: .createTextNode(lWidgetModel
863: .getDebugString()));
864: } else {
865: lPageWidgetElement
866: .appendChild(
867: lDocument
868: .createElement("STRONG"))
869: .appendChild(
870: lDocument
871: .createTextNode(" No Value "));
872: }
873: }
874: }
875: }
876: }
877: }
878: }
879: }
880: pThisMove = pApplication
881: .getPreceedingNavigationMove(pThisMove);
882: }
883: }
884: }
|