KickJava   Java API By Example, From Geeks To Geeks.

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


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 /*
35  * $Id: DOMContext.java,v 1.0 2004/07/20 14:02:36 tedg Exp $
36  */

37 package com.icesoft.faces.context;
38
39 import com.icesoft.faces.util.HalterDump;
40 import com.icesoft.faces.webapp.http.common.Configuration;
41 import com.icesoft.faces.webapp.http.common.ConfigurationException;
42 import org.w3c.dom.DOMException JavaDoc;
43 import org.w3c.dom.Document JavaDoc;
44 import org.w3c.dom.Element JavaDoc;
45 import org.w3c.dom.NamedNodeMap JavaDoc;
46 import org.w3c.dom.Node JavaDoc;
47 import org.w3c.dom.NodeList JavaDoc;
48 import org.w3c.dom.Text JavaDoc;
49
50 import javax.faces.component.UIComponent;
51 import javax.faces.context.FacesContext;
52 import javax.faces.context.ResponseWriter;
53 import java.io.IOException JavaDoc;
54 import java.util.ArrayList JavaDoc;
55 import java.util.HashMap JavaDoc;
56 import java.util.List JavaDoc;
57 import java.util.Map JavaDoc;
58
59 /**
60  * <p><strong>DOMContext</strong> provides a component specific interface to the
61  * DOM renderer
62  */

63 public class DOMContext implements java.io.Serializable JavaDoc {
64     private transient DOMResponseWriter writer;
65     private Node JavaDoc cursor;
66     private Document JavaDoc document;
67     private Node JavaDoc rootNode;
68     private Node JavaDoc parentElement;
69     private boolean initialized;
70
71     protected DOMContext(DOMResponseWriter writer, Document JavaDoc document,
72                          Node JavaDoc parentElement) {
73         this.writer = writer;
74         this.document = document;
75         this.cursor = parentElement;
76         this.parentElement = parentElement;
77         this.initialized = false;
78     }
79
80     /**
81      * <p>Determine whether this instance is initialized. An initialized
82      * instance is guaranteed to have a root node.</p>
83      *
84      * @return boolean reflecting whether this instance is initialized.
85      */

86     public boolean isInitialized() {
87         return initialized;
88     }
89
90     /**
91      * <p>This method returns the DOMContext associated with the specified
92      * component.</p>
93      *
94      * @param facesContext an instance of {@link FacesContext} associated with
95      * the lifecycle
96      * @param component component associated with this {@link DOMContext}
97      * @return the attached {@link DOMContext}
98      */

99     public static DOMContext attachDOMContext(FacesContext facesContext,
100                                               UIComponent component) {
101         ResponseWriter responseWriter = facesContext.getResponseWriter();
102         DOMResponseWriter domWriter;
103         if (responseWriter instanceof DOMResponseWriter) {
104             domWriter = (DOMResponseWriter) responseWriter;
105         } else {
106             domWriter = createTemporaryDOMResponseWriter(responseWriter, facesContext);
107         }
108         Node JavaDoc cursorParent = domWriter.getCursorParent();
109         Document JavaDoc doc = domWriter.getDocument();
110         Map JavaDoc domContexts = domWriter.getDomResponseContexts();
111
112         DOMContext context = null;
113         String JavaDoc clientId =
114                 component.getClientId(FacesContext.getCurrentInstance());
115         if (clientId != null && domContexts.containsKey(clientId)) {
116             context = (DOMContext) domContexts.get(clientId);
117         }
118         if (null == context) {
119             context = new DOMContext(domWriter, doc, cursorParent);
120             domContexts.put(clientId, context);
121         }
122         //context may have been severed from the tree at some point
123
if (context.isInitialized()) {
124             if (!(cursorParent instanceof Element JavaDoc)) {
125                 context.stepOver();
126                 return context;
127             }
128             context.attach((Element JavaDoc) cursorParent);
129         }
130         context.stepOver();
131
132         return context;
133     }
134
135     private static DOMResponseWriter createTemporaryDOMResponseWriter(
136             ResponseWriter responseWriter, FacesContext facesContext) {
137         DOMResponseWriter domWriter;
138         domWriter = new DOMResponseWriter(facesContext, null, new Configuration() {
139             public String JavaDoc getName() {
140                 return "noop configuration";
141             }
142
143             public Configuration getChild(String JavaDoc child) throws ConfigurationException {
144                 throw new ConfigurationException("child not available");
145             }
146
147             public Configuration[] getChildren(String JavaDoc name) throws ConfigurationException {
148                 throw new ConfigurationException("children not available");
149             }
150
151             public String JavaDoc getAttribute(String JavaDoc paramName) throws ConfigurationException {
152                 throw new ConfigurationException("attribute not available");
153             }
154
155             public String JavaDoc getValue() throws ConfigurationException {
156                 throw new ConfigurationException("value not available");
157             }
158         });
159         Document JavaDoc doc = domWriter.getDocument();
160         Element JavaDoc html = doc.createElement("html");
161         doc.appendChild(html);
162         Element JavaDoc body = doc.createElement("body");
163         html.appendChild(body);
164         domWriter.setCursorParent(body);
165         return domWriter;
166     }
167
168     /**
169      * <p>Get the DOMContext associated with the component. Do not attach the
170      * DOMContext instance to its parent element.</p>
171      *
172      * @param facesContext
173      * @param component the {@link UIComponent} instance whose DOMContext we
174      * are retrieving
175      * @return {@link DOMContext}
176      */

177     public static DOMContext getDOMContext(FacesContext facesContext,
178                                            UIComponent component) {
179         ResponseWriter responseWriter = facesContext.getResponseWriter();
180         DOMResponseWriter domWriter;
181         if (responseWriter instanceof DOMResponseWriter) {
182             domWriter = (DOMResponseWriter) responseWriter;
183         } else {
184             domWriter = createTemporaryDOMResponseWriter(responseWriter, facesContext);
185         }
186         Document JavaDoc doc = domWriter.getDocument();
187         Map JavaDoc domContexts = domWriter.getDomResponseContexts();
188
189         DOMContext context = null;
190         String JavaDoc clientId =
191                 component.getClientId(FacesContext.getCurrentInstance());
192         if (domContexts.containsKey(clientId)) {
193             context = (DOMContext) domContexts.get(clientId);
194         }
195         if (null == context) {
196             Node JavaDoc cursorParent = domWriter.getCursorParent();
197             context = new DOMContext(domWriter, doc, cursorParent);
198             domContexts.put(clientId, context);
199         }
200         return context;
201     }
202
203     private void attach(Element JavaDoc cursorParent) {
204         if (null == rootNode) { //nothing to attach
205
return;
206         }
207         if (rootNode.equals(cursorParent)) {
208             return;
209         }
210
211         //TODO needs proper fix
212
//Quick & temp fix for ICEfacesWebPresentation application
213
//This exception only happens when "rootNode" is ancestor of "cursor"
214
if (rootNode.getParentNode() != cursorParent) {
215             try {
216                 //re-attaching on top of another node
217
//replace them and assume they will re-attach later
218
cursorParent.appendChild(rootNode);
219             } catch (DOMException JavaDoc e) {
220                 //this happens in strea-write mode only.
221
}
222         }
223     }
224
225
226     /**
227      * <p>Creates an element of the type specified. Note that the instance
228      * returned implements the <code>Element</code> interface, so attributes can
229      * be specified directly on the returned object. <br>In addition, if there
230      * are known attributes with default values, <code>Attr</code> nodes
231      * representing them are automatically created and attached to the
232      * element.</p>
233      *
234      * @param name the specified Element type to create
235      * @return the created element
236      */

237     public Element JavaDoc createElement(String JavaDoc name) {
238         return document.createElement(name);
239     }
240
241     /**
242      * <p/>
243      * Creates a <code>Text</code> node given the specified string. </p>
244      *
245      * @param cData The data for the node.
246      * @return The new <code>Text</code> object.
247      */

248     public Text JavaDoc createTextNode(String JavaDoc cData) {
249         return document.createTextNode(cData);
250     }
251
252     /**
253      * <p/>
254      * Set the rootNode member variable to the parameter Node. </p>
255      *
256      * @param rootNode
257      */

258     public void setRootNode(Node JavaDoc rootNode) {
259         this.rootNode = rootNode;
260         parentElement.appendChild(rootNode);
261         initialized = true;
262     }
263
264     /**
265      * <p/>
266      * Creates an element of the type specified. Note that the instance returned
267      * implements the <code>Element</code> interface, so attributes can be
268      * specified directly on the returned object. <br>In addition, if there are
269      * known attributes with default values, <code>Attr</code> nodes
270      * representing them are automatically created and attached to the element.
271      * Set the rootNode member variable of this instance to the newly-created
272      * Element. </p>
273      *
274      * @param name
275      * @return Element
276      */

277     public Element JavaDoc createRootElement(String JavaDoc name) {
278         Element JavaDoc rootElement = createElement(name);
279         setRootNode(rootElement);
280         return rootElement;
281     }
282
283     void setIsolatedRootNode(Node JavaDoc rootElement) {
284         this.rootNode = rootElement;
285         initialized = true;
286     }
287
288     /**
289      * <p>Get the rootNode member variable.</p>
290      *
291      * @return rootNode the root node of this <code>DOMContext</code> instance
292      */

293     public Node JavaDoc getRootNode() {
294         return rootNode;
295     }
296
297     /**
298      * Set the position at which the next rendered node will be appended
299      *
300      * @param cursorParent
301      */

302     public void setCursorParent(Node JavaDoc cursorParent) {
303         this.cursor = cursorParent;
304         writer.setCursorParent(cursorParent);
305     }
306
307     /**
308      * Get the position in the document where the next DOM node will be
309      * rendererd.
310      */

311     public Node JavaDoc getCursorParent() {
312         return cursor;
313     }
314
315
316     /**
317      * Maintain the cursor and cursor position; step to the position where the
318      * next sibling should be rendered.
319      */

320     public void stepOver() {
321         if (null != rootNode && rootNode.getParentNode() != null) {
322             setCursorParent(rootNode.getParentNode());
323         }
324     }
325
326     /**
327      * Maintain the cursor and cursor such that the next rendered component will
328      * be rendered as a child of the parameter component.
329      *
330      * @param component
331      */

332     public void stepInto(UIComponent component) {
333         if (rootNode != null) {
334             // default behaviour;
335
// just like calling setCursorParent at the end of encode begin
336
setCursorParent(rootNode);
337         }
338     }
339
340
341     /**
342      * Retrieve the org.w3c.dom.Document instance associated with this
343      * DOMContext
344      *
345      * @return Document
346      */

347     public Document JavaDoc getDocument() {
348         return document;
349     }
350
351     /**
352      * Remove all children from Node parent
353      *
354      * @param parent - the root node to remove
355      */

356     public static void removeChildren(Node JavaDoc parent) {
357         while (parent.hasChildNodes()) {
358             parent.removeChild(parent.getFirstChild());
359         }
360     }
361
362     /**
363      * Removes from the root element all children with node name equal to the
364      * nodeName parameter
365      *
366      * @param rootElement
367      * @param name
368      */

369     public static void removeChildrenByTagName(Element JavaDoc rootElement,
370                                                String JavaDoc name) {
371
372         Node JavaDoc nextChildToRemove = null;
373         while (rootElement.hasChildNodes()
374                 && ((nextChildToRemove = findChildWithNodeName(rootElement,
375                 name)) != null)) {
376             rootElement.removeChild(nextChildToRemove);
377         }
378     }
379
380     /**
381      * Find and return root's child Node with name nodeName or null if no such
382      * child Node exists.
383      */

384     private static Node JavaDoc findChildWithNodeName(Element JavaDoc root, String JavaDoc nodeName) {
385         NodeList JavaDoc children = root.getChildNodes();
386         int length = children.getLength();
387         for (int i = 0; i < length; i++) {
388             Node JavaDoc nextChildNode = children.item(i);
389             String JavaDoc name = nextChildNode.getNodeName();
390             if (name.equalsIgnoreCase(nodeName)) {
391                 return nextChildNode;
392             }
393         }
394         return null;
395     }
396
397     public static List JavaDoc findChildrenWithNodeName(Element JavaDoc root, String JavaDoc nodeName) {
398         NodeList JavaDoc children = root.getChildNodes();
399         int length = children.getLength();
400         List JavaDoc foundItems = new ArrayList JavaDoc();
401         for (int i = 0; i < length; i++) {
402             Node JavaDoc nextChildNode = children.item(i);
403             String JavaDoc name = nextChildNode.getNodeName();
404             if (name.equalsIgnoreCase(nodeName)) {
405                 foundItems.add(nextChildNode);
406             }
407         }
408         return foundItems;
409     }
410
411
412     private HashMap JavaDoc halterDumps = new HashMap JavaDoc();
413
414     /**
415      * <p>Writes the DOM subtree anchored at <code>root</code> to the current
416      * ResponseWriter. Serialization is halted at the node <code>halter</code>
417      * (writing only the opening tag) and will be resumed from this node on the
418      * next call to this function.</p>
419      *
420      * @param facesContext current FacesContext
421      * @param component JSF component being rendered
422      * @param root node indicating subtree of DOM to eventually
423      * serialize
424      * @param halter node upon which to halt serialization on this pass
425      */

426     public void streamWrite(FacesContext facesContext, UIComponent component,
427                             Node JavaDoc root, Node JavaDoc halter) throws IOException JavaDoc {
428         if (!DOMResponseWriter.isStreamWriting()) {
429             return;
430         }
431         HalterDump halterDump = (HalterDump) halterDumps.get(root);
432         if (null == halterDump) {
433             halterDump = new HalterDump(facesContext.getResponseWriter(),
434                     component, root);
435             halterDumps.put(root, halterDump);
436         }
437         halterDump.streamWrite(halter);
438     }
439
440     /**
441      * <p>Convenience method for <code>streamWrite(facesContext, component,
442      * this.rootNode, null)</code>.</p>
443      *
444      * @param facesContext current FacesContext
445      * @param component JSF component being rendered
446      */

447     public void streamWrite(FacesContext facesContext, UIComponent component)
448             throws IOException JavaDoc {
449         streamWrite(facesContext, component, rootNode, null);
450     }
451
452     /**
453      * <p>Convenience method used by renderers to determine if Stream writing is
454      * enabled.
455      */

456     public boolean isStreamWriting() {
457         return DOMResponseWriter.isStreamWriting();
458     }
459
460     /**
461      * This method can be used as an alternative to the streamWrite method. When
462      * using this method you must also use the endNode method.
463      */

464     public void startNode(FacesContext facesContext, UIComponent component,
465                           Node JavaDoc node)
466             throws IOException JavaDoc {
467         if (!isStreamWriting()) {
468             return;
469         } else {
470             // get writer
471
ResponseWriter writer = facesContext.getResponseWriter();
472
473             // write by node type
474
switch (node.getNodeType()) {
475
476                 case Node.DOCUMENT_NODE:
477                     break;
478
479                 case Node.ELEMENT_NODE:
480                     // start the element
481
writer.startElement(node.getNodeName().toLowerCase(),
482                             component);
483                     // write attributes
484
NamedNodeMap JavaDoc attributes = node.getAttributes();
485
486                     for (int i = 0; i < attributes.getLength(); i++) {
487                         Node JavaDoc current = attributes.item(i);
488                         writer.writeAttribute(current.getNodeName(),
489                                 current.getNodeValue(),
490                                 current.getNodeName());
491                     }
492                     break;
493
494                 case Node.TEXT_NODE:
495                     writer.writeText(node.getNodeValue(), "text");
496                     break;
497             }
498         }
499     }
500
501     /**
502      * This method can be used as an alternative to the streamWrite method. When
503      * using this method you must also use the startNode method.
504      */

505     public void endNode(FacesContext facesContext, UIComponent component,
506                         Node JavaDoc node)
507             throws IOException JavaDoc {
508         if (!isStreamWriting()) {
509             return;
510         } else {
511             // get writer
512
ResponseWriter writer = facesContext.getResponseWriter();
513             switch (node.getNodeType()) {
514
515                 case Node.DOCUMENT_NODE:
516                     break;
517
518                 case Node.ELEMENT_NODE:
519                     writer.endElement(node.getNodeName().toLowerCase());
520                     break;
521
522                 case Node.TEXT_NODE:
523                     break;
524             }
525         }
526     }
527
528 }
529
Popular Tags