KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icesoft > faces > context > DOMResponseWriter


1 /*
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * "The contents of this file are subject to the Mozilla 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 at
7  * http://www.mozilla.org/MPL/
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 the
11  * License for the specific language governing rights and limitations under
12  * the License.
13  *
14  * The Original Code is ICEfaces 1.5 open source software code, released
15  * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
16  * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
17  * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
18  *
19  * Contributor(s): _____________________.
20  *
21  * Alternatively, the contents of this file may be used under the terms of
22  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
23  * License), in which case the provisions of the LGPL License are
24  * applicable instead of those above. If you wish to allow use of your
25  * version of this file only under the terms of the LGPL License and not to
26  * allow others to use your version of this file under the MPL, indicate
27  * your decision by deleting the provisions above and replace them with
28  * the notice and other provisions required by the LGPL License. If you do
29  * not delete the provisions above, a recipient may use your version of
30  * this file under either the MPL or the LGPL License."
31  *
32  */

33
34 package com.icesoft.faces.context;
35
36 import com.icesoft.faces.application.D2DViewHandler;
37 import com.icesoft.faces.application.StartupTime;
38 import com.icesoft.faces.context.effects.JavascriptContext;
39 import com.icesoft.faces.util.CoreUtils;
40 import com.icesoft.faces.webapp.http.common.Configuration;
41 import com.icesoft.jasper.Constants;
42 import org.apache.commons.logging.Log;
43 import org.apache.commons.logging.LogFactory;
44 import org.w3c.dom.Document JavaDoc;
45 import org.w3c.dom.Element JavaDoc;
46 import org.w3c.dom.Node JavaDoc;
47 import org.w3c.dom.NodeList JavaDoc;
48
49 import javax.faces.FacesException;
50 import javax.faces.application.ViewHandler;
51 import javax.faces.component.UIComponent;
52 import javax.faces.context.FacesContext;
53 import javax.faces.context.ResponseWriter;
54 import javax.servlet.http.HttpServletRequest JavaDoc;
55 import javax.xml.parsers.DocumentBuilder JavaDoc;
56 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
57 import javax.xml.parsers.ParserConfigurationException JavaDoc;
58 import java.beans.Beans JavaDoc;
59 import java.io.IOException JavaDoc;
60 import java.io.Writer JavaDoc;
61 import java.util.ArrayList JavaDoc;
62 import java.util.Collection JavaDoc;
63 import java.util.HashMap JavaDoc;
64 import java.util.Iterator JavaDoc;
65 import java.util.Locale JavaDoc;
66 import java.util.Map JavaDoc;
67
68 /**
69  * <p><strong>DOMResponseWriter</strong> is a DOM specific implementation of
70  * <code>javax.faces.context.ResponseWriter</code>.
71  */

72 public class DOMResponseWriter extends ResponseWriter {
73     private static final Log log = LogFactory.getLog(DOMResponseWriter.class);
74     public static final String JavaDoc STREAM_WRITING = "com.icesoft.faces.streamWriting";
75     //DOM and current node being written to for this ResponseWriter
76
public static final String JavaDoc DOCTYPE_PUBLIC = "com.icesoft.doctype.public";
77     public static final String JavaDoc DOCTYPE_SYSTEM = "com.icesoft.doctype.system";
78     public static final String JavaDoc DOCTYPE_ROOT = "com.icesoft.doctype.root";
79     public static final String JavaDoc DOCTYPE_OUTPUT = "com.icesoft.doctype.output";
80     public static final String JavaDoc DOCTYPE_PRETTY_PRINTING =
81             "com.icesoft.doctype.prettyprinting";
82
83     public static final String JavaDoc RESPONSE_DOM = "com.icesoft.domResponseDocument";
84     public static final String JavaDoc RESPONSE_DOM_ID =
85             "com.icesoft.domResponseDocumentID";
86     public static final String JavaDoc OLD_DOM = "com.icesoft.oldDocument";
87     public static final String JavaDoc RESPONSE_VIEWROOT =
88             "com.icesoft.domResponseViewRoot";
89     //Hashtable of DOMContext objects associated with each component
90
public static final String JavaDoc RESPONSE_CONTEXTS_TABLE =
91             "com.icesoft.domResponseContexts";
92     private static DocumentBuilder JavaDoc DOCUMENT_BUILDER;
93
94     static {
95         try {
96             DOCUMENT_BUILDER =
97                     DocumentBuilderFactory.newInstance().newDocumentBuilder();
98         } catch (ParserConfigurationException JavaDoc e) {
99             log.error("Cannot acquire a DocumentBuilder", e);
100         }
101     }
102
103     private static boolean isStreamWritingFlag = false;
104     private Document JavaDoc document;
105     private Node JavaDoc cursor;
106     private Map JavaDoc domResponseContexts;
107     private Map JavaDoc contextServletTable;
108     private BridgeFacesContext context;
109     private DOMSerializer serializer;
110     private Configuration configuration;
111
112     public DOMResponseWriter(FacesContext context, DOMSerializer serializer, Configuration configuration) {
113         this.serializer = serializer;
114         this.configuration = configuration;
115         try {
116             this.context = (BridgeFacesContext) context;
117         } catch (ClassCastException JavaDoc e) {
118             throw new IllegalStateException JavaDoc(
119                     "ICEfaces requires the PersistentFacesServlet. " +
120                             "Please check your web.xml servlet mappings");
121         }
122         this.initialize();
123     }
124
125     Map JavaDoc getDomResponseContexts() {
126         return domResponseContexts;
127     }
128
129     public Node JavaDoc getCursorParent() {
130         return cursor;
131     }
132
133     public Document JavaDoc getDocument() {
134         return document;
135     }
136
137     public String JavaDoc getContentType() {
138         return "text/html; charset=UTF-8";
139     }
140
141     public String JavaDoc getCharacterEncoding() {
142         return "UTF-8";
143     }
144
145     public void startDocument() throws IOException JavaDoc {
146     }
147
148     private void initialize() {
149         contextServletTable = D2DViewHandler.getContextServletTable(context);
150         // contexts for each component
151
if (contextServletTable
152                 .containsKey(DOMResponseWriter.RESPONSE_CONTEXTS_TABLE)) {
153             domResponseContexts = (Map JavaDoc) contextServletTable
154                     .get(DOMResponseWriter.RESPONSE_CONTEXTS_TABLE);
155         }
156         if (null == domResponseContexts) {
157             domResponseContexts = new HashMap JavaDoc();
158             contextServletTable.put(DOMResponseWriter.RESPONSE_CONTEXTS_TABLE,
159                     domResponseContexts);
160         }
161         // viewroot, application
162
contextServletTable.put(DOMResponseWriter.RESPONSE_VIEWROOT,
163                 context.getViewRoot());
164         cursor = document = DOCUMENT_BUILDER.newDocument();
165         contextServletTable.put(DOMResponseWriter.RESPONSE_DOM, document);
166         boolean streamWritingParam = "true".equalsIgnoreCase(
167                 context.getExternalContext().getInitParameter(
168                         DOMResponseWriter.STREAM_WRITING));
169         DOMResponseWriter.isStreamWritingFlag =
170                 Beans.isDesignTime() || streamWritingParam;
171     }
172
173     public void endDocument() throws IOException JavaDoc {
174         if (!isStreamWriting()) {
175             enhanceAndFixDocument();
176             serializer.serialize(document);
177         }
178     }
179
180     public void flush() throws IOException JavaDoc {
181     }
182
183     public void startElement(String JavaDoc name, UIComponent componentForElement)
184             throws IOException JavaDoc {
185         Node JavaDoc oldCursor = cursor;
186         Element JavaDoc elem = document.createElement(name);
187         cursor = cursor.appendChild(elem);
188         if (log.isTraceEnabled()) {
189             log.trace("startElement() name: " + name + " elem: " + elem +
190                     " oldCursor: " + oldCursor + " newCursor: " + cursor);
191         }
192     }
193
194     public void endElement(String JavaDoc name) throws IOException JavaDoc {
195         Node JavaDoc oldCursor = cursor;
196         cursor = cursor.getParentNode();
197         if (log.isTraceEnabled()) {
198             log.trace("endElement() name: " + name + " oldCursor: " +
199                     oldCursor + " newCursor: " + cursor);
200         }
201     }
202
203     public void writeAttribute(String JavaDoc name, Object JavaDoc value,
204                                String JavaDoc componentPropertyName)
205             throws IOException JavaDoc {
206         //name.trim() because cardemo had a leading space in an attribute name
207
//which made the DOM processor choke
208
((Element JavaDoc) cursor).setAttribute(name.trim(), String.valueOf(value));
209     }
210
211     public void writeURIAttribute(String JavaDoc name, Object JavaDoc value,
212                                   String JavaDoc componentPropertyName)
213             throws IOException JavaDoc {
214         String JavaDoc stringValue = String.valueOf(value);
215         if (stringValue.startsWith("javascript:")) {
216             ((Element JavaDoc) cursor).setAttribute(name, stringValue);
217         } else {
218             ((Element JavaDoc) cursor)
219                     .setAttribute(name, stringValue.replace(' ', '+'));
220         }
221     }
222
223     public void writeComment(Object JavaDoc comment) throws IOException JavaDoc {
224         if (log.isTraceEnabled()) {
225             log.trace("writeComment() comment: " + comment);
226         }
227         cursor.appendChild(document.createComment(String.valueOf(comment)));
228     }
229
230     public void writeText(Object JavaDoc text, String JavaDoc componentPropertyName)
231             throws IOException JavaDoc {
232         if (log.isTraceEnabled()) {
233             log.trace("writeText(O,S) text: " + text);
234         }
235         cursor.appendChild(document.createTextNode(String.valueOf(text)));
236     }
237
238     public void writeText(char text[], int off, int len) throws IOException JavaDoc {
239         if (log.isTraceEnabled()) {
240             log.trace("writeText(c[],i,i) text: " +
241                     (new String JavaDoc(text, off, len)));
242         }
243         cursor.appendChild(document.createTextNode(new String JavaDoc(text, off, len)));
244     }
245
246     public ResponseWriter cloneWithWriter(Writer writer) {
247         //FIXME: This is a hack for DOM rendering but JSF currently clones the writer
248
//just as the components are complete
249
if (null != document) {
250             try {
251                 endDocument();
252             } catch (IOException JavaDoc e) {
253                 throw new IllegalStateException JavaDoc(e.toString());
254             }
255         }
256         try {
257             return new DOMResponseWriter(context, serializer, configuration);
258         } catch (FacesException e) {
259             throw new IllegalStateException JavaDoc();
260         }
261     }
262
263     public void close() throws IOException JavaDoc {
264     }
265
266     public void write(char[] cbuf, int off, int len) throws IOException JavaDoc {
267         if (log.isTraceEnabled()) {
268             log.trace("writeText(c[],i,i) str: " +
269                     (new String JavaDoc(cbuf, off, len)));
270         }
271         cursor.appendChild(document.createTextNode(new String JavaDoc(cbuf, off, len)));
272     }
273
274     public void write(int c) throws IOException JavaDoc {
275         if (log.isTraceEnabled()) {
276             log.trace("write(i) hex: " + Integer.toHexString(c) +
277                     " decimal: " + c);
278         }
279         cursor.appendChild(document.createTextNode(String.valueOf((char) c)));
280     }
281
282     public void write(String JavaDoc str) throws IOException JavaDoc {
283         if (log.isTraceEnabled()) {
284             log.trace("write(S) str: " + str);
285         }
286         cursor.appendChild(document.createTextNode(str));
287     }
288
289     public void write(String JavaDoc str, int off, int len) throws IOException JavaDoc {
290         if (log.isTraceEnabled()) {
291             log.trace("write(S,i,i) str_sub: " + str.substring(off, len));
292         }
293         cursor.appendChild(document.createTextNode(str.substring(off, len)));
294     }
295
296     private void enhanceAndFixDocument() {
297         Element JavaDoc html = (Element JavaDoc) document.getDocumentElement();
298         enhanceHtml(html = "html".equals(html.getTagName()) ? html : fixHtml());
299
300         Element JavaDoc head = (Element JavaDoc) document.getElementsByTagName("head").item(0);
301         enhanceHead(head == null ? fixHead() : head);
302
303         Element JavaDoc body = (Element JavaDoc) document.getElementsByTagName("body").item(0);
304         enhanceBody(body == null ? fixBody() : body);
305     }
306
307     private void enhanceHtml(Element JavaDoc html) {
308         //add lang attribute
309
Locale JavaDoc locale = context.getApplication().getViewHandler().calculateLocale(context);
310         html.setAttribute("lang", locale.getLanguage());
311     }
312
313     private void enhanceBody(Element JavaDoc body) {
314         //id required for forwarded (server-side) redirects
315
body.setAttribute("id", "body");
316         Element JavaDoc iframe = document.createElement("iframe");
317         body.insertBefore(iframe, body.getFirstChild());
318         iframe.setAttribute("id", "history-frame");
319         Object JavaDoc request = context.getExternalContext().getRequest();
320
321         final String JavaDoc frameURI;
322         //another "workaround" to resolve the iframe URI
323
if (request instanceof HttpServletRequest JavaDoc) {
324             HttpServletRequest JavaDoc httpRequest = (HttpServletRequest JavaDoc) request;
325             if (httpRequest.getRequestURI() == null) {
326                 frameURI = "about:blank";
327             } else {
328                 frameURI = CoreUtils.resolveResourceURL(FacesContext.getCurrentInstance(),
329                         "/xmlhttp/blank.iface");
330             }
331         } else {
332             frameURI = "about:blank";
333         }
334         iframe.setAttribute("title", "Icefaces Redirect");
335         iframe.setAttribute("src", frameURI);
336         iframe.setAttribute("frameborder", "0");
337         iframe.setAttribute("style",
338                 "z-index: 10000; visibility: hidden; width: 0; height: 0; position: absolute; opacity: 0.22; filter: alpha(opacity=22);");
339
340         // TODO This is only meant to be a transitional focus retention(management) solution.
341
String JavaDoc focusId = context.getFocusId();
342         if (focusId != null && !focusId.equals("null")) {
343             JavascriptContext.focus(context, focusId);
344         }
345
346         Element JavaDoc script =
347                 (Element JavaDoc) body.appendChild(document.createElement("script"));
348         script.setAttribute("id", JavascriptContext.DYNAMIC_CODE_ID);
349         script.setAttribute("language", "javascript");
350         String JavaDoc calls = JavascriptContext.getJavascriptCalls(context);
351         script.appendChild(document.createTextNode(calls));
352
353         Map JavaDoc session = context.getExternalContext().getSessionMap();
354         ElementController.from(session).addInto(body);
355
356         String JavaDoc sessionIDScript = "window.session='" + context.getIceFacesId() + "'; ";
357         String JavaDoc configurationScript =
358                 "window.configuration = {" +
359                         "synchronous: " + configuration.getAttribute("synchronousUpdate", "false") + "," +
360                         "redirectURI: " + configuration.getAttribute("connectionLostRedirectURI", "null") + "," +
361                         "connection: {" +
362                         "context: '" + context.getApplication().getViewHandler().getResourceURL(context, "/") + "'," +
363                         "timeout: " + configuration.getAttributeAsLong("connectionTimeout", 30000) + "," +
364                         "heartbeat: {" +
365                         "interval: " + configuration.getAttributeAsLong("heartbeatInterval", 20000) + "," +
366                         "timeout: " + configuration.getAttributeAsLong("heartbeatTimeout", 3000) + "," +
367                         "retries: " + configuration.getAttributeAsLong("heartbeatRetries", 3) +
368                         "}" +
369                         "}" +
370                         "};";
371
372         Element JavaDoc configurationElement = (Element JavaDoc) body.appendChild(document.createElement("script"));
373         configurationElement.setAttribute("language", "javascript");
374         configurationElement.appendChild(document.createTextNode(sessionIDScript + configurationScript));
375         body.appendChild(configurationElement);
376     }
377
378     private void enhanceHead(Element JavaDoc head) {
379         ViewHandler handler = context.getApplication().getViewHandler();
380         //id required for forwarded (server-side) redirects
381
head.setAttribute("id", "head");
382         Element JavaDoc meta =
383                 (Element JavaDoc) head.appendChild(document.createElement("meta"));
384         meta.setAttribute("name", "icefaces");
385         meta.setAttribute("content", "Rendered by ICEFaces D2D");
386
387         Element JavaDoc noscript =
388                 (Element JavaDoc) head.appendChild(document.createElement("noscript"));
389         Element JavaDoc noscriptMeta =
390                 (Element JavaDoc) noscript.appendChild(document.createElement("meta"));
391         noscriptMeta.setAttribute("http-equiv", "refresh");
392         noscriptMeta
393                 .setAttribute("content", "0;url=" + handler.getResourceURL(context, "/xmlhttp/javascript-blocked"));
394
395         //load libraries
396
Collection JavaDoc libs = new ArrayList JavaDoc();
397         if (context.getExternalContext().getInitParameter(D2DViewHandler.INCLUDE_OPEN_AJAX_HUB) != null) {
398             libs.add("/xmlhttp/openajax.js");
399         }
400         libs.add("/xmlhttp" + StartupTime.getStartupInc() + "icefaces-d2d.js");
401         //todo: refactor how extral libraries are loaded into the bridge; always include extra libraries for now
402
libs.add("/xmlhttp" + StartupTime.getStartupInc() + "ice-extras.js");
403         if (context.getExternalContext().getRequestMap().get(Constants.INC_SERVLET_PATH) == null) {
404             String JavaDoc[] componentLibs = JavascriptContext.getIncludedLibs(context);
405             for (int i = 0; i < componentLibs.length; i++) {
406                 String JavaDoc componentLib = componentLibs[i];
407                 if (!libs.contains(componentLib)) {
408                     libs.add(componentLib);
409                 }
410             }
411         }
412
413         Iterator JavaDoc iterator = libs.iterator();
414         while (iterator.hasNext()) {
415             String JavaDoc lib = (String JavaDoc) iterator.next();
416             Element JavaDoc script = (Element JavaDoc) head
417                     .appendChild(document.createElement("script"));
418             script.setAttribute("language", "javascript");
419             script.setAttribute("src", handler.getResourceURL(context, lib));
420         }
421
422         String JavaDoc sessionIdentifier = context.getIceFacesId();
423         Element JavaDoc viewAndSessionScript = (Element JavaDoc) head.appendChild(document.createElement("script"));
424         viewAndSessionScript.setAttribute("language", "javascript");
425         viewAndSessionScript.appendChild(document.createTextNode(
426                 "window.session = '" + sessionIdentifier + "';"
427         ));
428     }
429
430     private Element JavaDoc fixHtml() {
431         Element JavaDoc root = document.getDocumentElement();
432         Element JavaDoc html = document.createElement("html");
433         document.replaceChild(html, root);
434         html.appendChild(root);
435
436         return html;
437     }
438
439     private Element JavaDoc fixBody() {
440         Element JavaDoc html = document.getDocumentElement();
441         Element JavaDoc body = document.createElement("body");
442         NodeList JavaDoc children = html.getChildNodes();
443         int length = children.getLength();
444         Node JavaDoc[] nodes = new Node JavaDoc[length];
445         //copy the children first, since NodeList is live
446
for (int i = 0; i < nodes.length; i++) nodes[i] = children.item(i);
447         for (int i = 0; i < nodes.length; i++) {
448             Node JavaDoc node = nodes[i];
449             if (!(node instanceof Element JavaDoc &&
450                     "head".equals(((Element JavaDoc) node).getTagName())))
451                 body.appendChild(node);
452         }
453         html.appendChild(body);
454
455         return body;
456     }
457
458     private Element JavaDoc fixHead() {
459         Element JavaDoc html = document.getDocumentElement();
460         Element JavaDoc head = document.createElement("head");
461         html.insertBefore(head, html.getFirstChild());
462
463         return head;
464     }
465
466     /**
467      * This method sets the write cursor for DOM modifications. Subsequent DOM
468      * modifications will take place below the cursor element.
469      *
470      * @param cursorParent parent node for subsequent modifications to the DOM
471      */

472     protected void setCursorParent(Node JavaDoc cursorParent) {
473         this.cursor = cursorParent;
474     }
475
476     public static boolean isStreamWriting() {
477         return isStreamWritingFlag;
478     }
479
480
481 }
482
Popular Tags