Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/enhydra/xml/lazydom/LazyDocument.java


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$
22   */
23  
24  package org.enhydra.xml.lazydom;
25  
26  import org.w3c.dom.*;
27  import org.apache.xerces.dom.DocumentImpl;
28  import org.enhydra.xml.io.PreFormattedTextDocument;
29  import org.enhydra.xml.io.OutputOptions;
30  
31  // FIXME: not sure the Lazy* constructors with TemplateNodes are actually
32  // needed, as we go thorugh the factory methods.
33  //FIXME: If no childred/attributes/etc exist, initialize expanded flag to true.
34  // FIXME: need serializable support.
35  //FIXME: Need clone support.
36  //FIXME: are createXXX(nodeId) really needed.
37  
38  /**
39   * A DOM Document that supports lazy instantiation of a template DOM.  Nodes
40   * in the instance DOM are created as accessed.  This can be either by
41   * traversing the tree or by direct access to a node by id number.
42   * Instantiation of nodes in the middle of the virtual tree is support.  Thus
43   * a node can exist without a parent being expanded. This is used by XMLC,
44   * were the dynamic nodes tend to be towards the leaves of the tree.
45   * <p>
46   * Instances contain a reference to a DOM that is a shared template for the
47   * document.  Each node in the template is assigned an integer node id that be
48   * used to index tables to directly look up the template of a node created
49   * from the template.
50   * <p>
51   * This DOM also supports associating pre-formatted text with some nodes, which
52   * is used to avoid exprensive string scanning operations during the output
53   * of unmodified nodes.
54   * <p>
55   * When a child of a node is requested, all direct children are expanded.
56   * This eliminates a lot of difficult book keep.  Attributes are treated
57   * as a separate set from children, only instantiated when an atttribute 
58   * is accessed.
59   *
60   * Expansion of nodes accesed from an existing node works as follows:
61   * <ul>
62   * <li> Lazy nodes have internal flag to indicate if the particular type
63   *      of expansion has occured (parent, child, or attribute).
64   * <li> When an access is made, check the flag to see if the expansion has
65   *      occured.
66   * <li> If expansion has not occured, call the appropriate LazyDocument 
67   *      doExpand method, which is synchronized.  This method again check
68   *      the flag on the node and expands if necessary.  Some expansion
69   *      are only used by one node class and maybe implemented there,
70   *      but still synchronize on the document.
71   * <li> To simplify the book keeping, all children of a node will be expanded
72   *      when one is expanded.
73   * <li> When the parent of a node is requested, the parent and all of the other
74   *      children will be expanded and linked.
75   * <li> Nodes created using create methods (without node ids), are always
76   *      marked as expanded, as they always go through standard DOM methods to
77   *      be inserted into the tree.
78   * </ul>
79   *
80   * This coarse-grained locking approach minimizes the number of locks * on the
81   * assumption that collisions do not occur frequently
82   * <p>
83   * To created an extended DOM, one must override both the factory methods that
84   * take strings and those that take node ids.
85   */
86  public class LazyDocument extends DocumentImpl
87      implements LazyParent, PreFormattedTextDocument {
88      /**
89       * Constructor.
90       * @param documentType Document type to associate with this document,
91       *  or null if no doctype or should be obtained from template.
92       * @param templateDOM Template DOM, with each node cotaining a node id.
93       *  Maybe null if no associated template.
94       */
95      public LazyDocument(DocumentType documentType,
96                          TemplateDOM templateDOM) {
97          super(documentType);
98          if (templateDOM != null) {
99              fTemplateDOM = templateDOM;
100             fExpandedNodes = new LazyNode[fTemplateDOM.getMaxNodeId()+1];
101             fExpandedNodes[DOCUMENT_NODE_ID] = this;
102             fTemplateNode = (LazyDocument)fTemplateDOM.getNode(DOCUMENT_NODE_ID);
103             fNodeId = fTemplateNode.getNodeId();
104         } else {
105             // No template, mark as expanded.
106             fDocTypeExpanded = true;
107             fChildrenExpanded = true;
108             fIsTemplateNode = true;  // No template, so this must be a template.
109         }
110     }
111 
112     /**
113      * Constructor with no argument, for LazyHTMLDocument.
114      */
115     public LazyDocument() {
116         this(null, null);
117     }
118 
119     /**
120      * @see Document#getDocumentElement
121      */
122     public Element getDocumentElement() {
123         if (!fChildrenExpanded) {
124             expandChildren();
125         }
126         return super.getDocumentElement();
127     }
128 
129     /**
130      * @see Document#DOMImplementation
131      */
132     public DOMImplementation getImplementation() {
133         return LazyDOMImplementation.getDOMImplementation();
134     }
135     
136     //-------------------------------------------------------------------------
137     // Document-wide expansion support (FIXME: move to a different class???)
138     //-------------------------------------------------------------------------
139 
140     /**
141      * Template document DOM. This is shared by all instances and must not be
142      * modified.
143      */
144     private TemplateDOM fTemplateDOM;
145     
146     /**
147      * Table of LazyNodes that have already been expanded, indexed
148      * by nodeId.  Entry is null if the node has not been expanded.
149      */
150     private LazyNode[] fExpandedNodes;
151 
152     /**
153      * Detection of recursive calls of one of the expansion routines.
154      */
155     private boolean fExpanding = false;
156 
157     /**
158      * Flag that an expansion is in progress, which is used to detect
159      * recursion. MUST be synchronized on document.
160      */
161     protected final void enterExpansion() {
162         if (fExpanding) {
163             throw new LazyDOMError("recursive call doing lazy DOM expansion");
164         }
165         fExpanding = true;
166     }
167 
168     /**
169      * Flag that an expansion is complete.
170      * MUST be synchronized on document.
171      */
172     protected final void leaveExpansion() {
173         fExpanding = false;
174     }
175 
176     /**
177      * Create a new node from a template, placing it in the expanded table.
178      * Uses factory methods so that derived document can override node type.
179      * MUST be synchronized on document.
180      */
181     private LazyNode createLazyNode(int nodeId) {
182         LazyNode template = fTemplateDOM.getNode(nodeId);
183         switch (template.getNodeType()) {
184         case ELEMENT_NODE:
185             return createElement(nodeId);
186         case ATTRIBUTE_NODE:
187             return createAttribute(nodeId);
188         case TEXT_NODE:
189             return createTextNode(nodeId);
190         case CDATA_SECTION_NODE:
191             return createCDATASection(nodeId);
192         case ENTITY_REFERENCE_NODE:
193             return createEntityReference(nodeId);
194         case ENTITY_NODE:
195             return createEntity(nodeId);
196         case PROCESSING_INSTRUCTION_NODE:
197             return createProcessingInstruction(nodeId);
198         case COMMENT_NODE:
199             return createComment(nodeId);
200         case NOTATION_NODE:
201             return createNotation(nodeId);
202         case DOCUMENT_TYPE_NODE:
203             return createDocumentType(nodeId);
204         case DOCUMENT_NODE:
205         case DOCUMENT_FRAGMENT_NODE:
206             throw new LazyDOMError(nodeId, "Can't create node from template of type "
207                                    + template.getNodeType());
208         default:
209             throw new LazyDOMError(nodeId, "Invalid node type "
210                                    + template.getNodeType());
211         }
212     }
213 
214     /** 
215      * Get or create a lazy node, given its id.  Expanding if it doesn't
216      * exist.  All node creation must go through here so that a derived
217      * document create factory is used.
218      */
219     public final LazyNode getNodeById(int nodeId) {
220         if (fExpandedNodes[nodeId] == null) {
221             synchronized(this) {
222                 if (fExpandedNodes[nodeId] == null) {
223                     fExpandedNodes[nodeId] = createLazyNode(nodeId);
224                 }
225             }
226         }
227         return fExpandedNodes[nodeId];
228     }
229 
230     /**
231      * Get or create a node given, the template node.
232      * @see getNodeById
233      */
234     public final LazyNode getNodeFromTemplate(LazyNode template) {
235         return getNodeById(template.getNodeId());
236     }
237 
238     /**
239      * Method to expand children of a node once synchronized and fExpanding is
240      * set.
241      * MUST be synchronized on document.
242      */
243     private void expandNodeChildren(LazyParent node) {
244         if (!node.areChildrenExpanded()) {
245             LazyNode template = node.getTemplateNode();
246             for (LazyNode templateChild = (LazyNode)template.getFirstChild();
247                  templateChild != null;
248                  templateChild = (LazyNode)templateChild.getNextSibling()) {
249                 // Ignore doctype if its a child
250                 if (!(templateChild instanceof DocumentType)) {
251                     LazyNode child = getNodeFromTemplate(templateChild);
252                     node.appendChildWhileExpanding(child);
253                     if (child instanceof LazyParent) {
254                         // Tell child parent is expanded
255                         ((LazyParent)child).setParentExpanded();
256                     }
257                 }
258             }
259             node.setChildrenExpanded();
260         }
261     }
262 
263     /**
264      * Do work of expanding the parent of a node, if it is not already
265      * expanded.  This also expands the children, as this keeps the expansion
266      * bookkeeping simple and getting a parent not a common operation except to
267      * access a sibling or add a new sibling
268      * Only used internally to this package.
269      */
270     protected synchronized void doExpandParent(LazyParent node) {
271         // Check again for it being expanded now that we are synchronized
272         // getParent used during insertion of new node, so allow for recursion
273         // without actually expanding.
274         if (!node.isParentExpanded() && !fExpanding) {
275             enterExpansion();
276             try {
277                 LazyParent parentTemplate = (LazyParent)node.getTemplateNode().getParentNode();
278                 if (parentTemplate != null) {
279                     expandNodeChildren((LazyParent)getNodeFromTemplate(parentTemplate));
280                 }
281                 node.setParentExpanded(); 
282             } finally {
283                 leaveExpansion();
284             }
285         }
286     }
287 
288     /**
289      * Do work of expanding the children of a node, if they are not already
290      * expanded. Only lazy parent's have a flag for siblings, as data nodes
291      * can never be accessed without going through the parent and expanding
292      * the children.
293      * Only used internally to this package.
294      */
295     protected synchronized void doExpandChildren(LazyParent node) {
296         enterExpansion();
297         try {
298             expandNodeChildren(node);
299         } finally {
300             leaveExpansion();
301         }
302     }
303 
304     /**
305      * Get a pointer to a node if its been expanded, otherwise
306      * return null.
307      */
308     public final LazyNode getExpandedNode(int nodeId) {
309         return fExpandedNodes[nodeId];
310     }
311 
312     /**
313      * Get a template node, given a node id.
314      */
315     public final LazyNode getTemplateNode(int nodeId) {
316         return fTemplateDOM.getNode(nodeId);
317     }
318 
319     //-------------------------------------------------------------------------
320     // LazyDocument specific
321     //-------------------------------------------------------------------------
322 
323     /**
324      * Has the DocumentType been expanded?
325      */
326     private boolean fDocTypeExpanded = false;
327 
328     /**
329      * Detection of recursive calls of doctype expansion.  A seperate
330      * flag, since doctype maybe expanded while expanding attributes.
331      */
332     private boolean fExpandingDocType = false;
333     
334     /**
335      * Template for this Document.
336      */
337     private LazyDocument fTemplateNode = null;
338 
339     /**
340      * Has the DocumentType been expanded?
341      */
342     public boolean isDocTypeExpanded() {
343         return fDocTypeExpanded;
344     }
345     
346     /**
347      * Get the template for this node.
348      * @see LazyNode#getTemplateNode
349      */
350     public LazyDocument getTemplateDocument() {
351         return fTemplateNode;
352     }
353 
354     /**
355      * @see Node#cloneNode
356      */
357     public Node cloneNode(boolean deep) {
358         if (deep) {
359             // If children are copied, we must expand now.
360             if (!fDocTypeExpanded) {
361                 doExpandDocType();
362             }
363             if (!fChildrenExpanded) {
364                 expandChildren();
365             }
366         }
367         
368         /**
369          * This does a clone(), must clean up all fields and make
370          * fully expanded.
371          * FIXME: Should support cloning in unexpanded state.
372          */
373         LazyDocument newDocument = (LazyDocument)super.cloneNode(deep);
374         newDocument.fTemplateDOM = null;
375         newDocument.fExpandedNodes = null;
376         newDocument.fDocTypeExpanded = true;
377         newDocument.fChildrenExpanded = true;
378         return newDocument;
379     }
380 
381     //-------------------------------------------------------------------------
382     // LazyNode support
383     //-------------------------------------------------------------------------
384 
385     /*
386      * Node id for this element.
387      */
388     private int fNodeId = NULL_NODE_ID;
389 
390     /**
391      * Is this a template node?
392      */
393     private boolean fIsTemplateNode;
394 
395     /*
396      * @see LazyNode#makeTemplateNode
397      */
398     public void makeTemplateNode(int nodeId) {
399         fNodeId = nodeId;
400         fIsTemplateNode = true;
401     }
402 
403     /**
404      * @see LazyNode#getNodeId
405      */
406     public int getNodeId() {
407         return fNodeId;
408     }
409 
410     /**
411      * @see LazyNode#isTemplateNode
412      */
413     public boolean isTemplateNode() {
414         return fIsTemplateNode;
415     }
416 
417     /**
418      * @see LazyNode#getTemplateNode
419      */
420     public LazyNode getTemplateNode() {
421         return fTemplateNode;
422     }
423 
424     /**
425      * @see LazyNode#templateClone
426      */
427     public LazyNode templateClone(Document ownerDocument) {
428         throw new LazyDOMError("templateClone not support on LazyDocument node");
429     }
430 
431     /**
432      * Set the node value, invalidating the id.  All node data is modified
433      * by this routine.
434      * @see org.w3c.dom.Node.setNodeValue
435      */
436     public void setNodeValue(String value) {
437         fNodeId = NULL_NODE_ID;
438         super.setNodeValue(value);
439     }
440 
441     //-------------------------------------------------------------------------
442     // LazyParent support
443     //-------------------------------------------------------------------------
444 
445     /**
446      * Children expanded flag.
447      * NB: code is special, since there is node parent.
448      */
449     private boolean fChildrenExpanded = false;
450     
451     /**
452      * @see LazyParent#isParentExpanded()
453      */
454     public boolean isParentExpanded() {
455         return true;
456     }
457     
458     /**
459      * @see LazyParent#setParentExpanded
460      */
461     public void setParentExpanded() {
462         throw new LazyDOMError("setParentExpanded invalid on document");
463     }
464     
465     /**
466      * @see LazyParent#setParentWhileExpanding
467      */
468     public void setParentWhileExpanding(Node parent) {
469         throw new LazyDOMError("setParentWhileExpanding invalid on document");
470     }
471     
472     /**
473      * @see LazyParent#areChildrenExpanded()
474      */
475     public boolean areChildrenExpanded() {
476         return fChildrenExpanded;
477     }
478     
479     /**
480      * @see LazyParent#setChildrenExpanded
481      */
482     public void setChildrenExpanded() {
483         fChildrenExpanded = true;
484     }
485 
486     /**
487      * @see LazyParent#appendChildWhileExpanding
488      */
489     public void appendChildWhileExpanding(Node child) {
490         super.insertBefore(child, null);
491     }
492 
493     /**
494      * Expand the parent of this element, if it is not already expanded.
495      */
496     private void expandParent() {
497         doExpandParent(this);
498     }
499 
500     /**
501      * Expand the children of this element, if they are not already expanded.
502      */
503     private void expandChildren() {
504         doExpandChildren(this);
505     }
506 
507     /**
508      * @see org.w3c.dom.Node#getChildNodes
509      */
510     public NodeList getChildNodes() {
511         if (!fChildrenExpanded) {
512             expandChildren();
513         }
514         return super.getChildNodes();
515     }
516 
517     /**
518      * @see org.w3c.dom.Node#getFirstChild
519      */
520     public Node getFirstChild() {
521         if (!fChildrenExpanded) {
522             expandChildren();
523         }
524         return super.getFirstChild();
525     }
526 
527     /**
528      * @see org.w3c.dom.Node#getLastChild
529      */
530     public Node getLastChild() {
531         if (!fChildrenExpanded) {
532             expandChildren();
533         }
534         return super.getLastChild();
535     }
536 
537     /**
538      * @see org.w3c.dom.Node#insertBefore
539      */
540     public Node insertBefore(Node newChild, 
541                              Node refChild)
542         throws DOMException {
543         if (!fChildrenExpanded) {
544             expandChildren();
545         }
546         return super.insertBefore(newChild, refChild);
547     }
548 
549     /**
550      * @see org.w3c.dom.Node#replaceChild
551      */
552     public Node replaceChild(Node newChild, 
553                              Node oldChild)
554         throws DOMException {
555         if (!fChildrenExpanded) {
556             expandChildren();
557         }
558         return super.replaceChild(newChild, oldChild);
559     }
560 
561     /**
562      * @see org.w3c.dom.Node#removeChild
563      */
564     public Node removeChild(Node oldChild)
565         throws DOMException {
566         if (!fChildrenExpanded) {
567             expandChildren();
568         }
569         return super.removeChild(oldChild);
570     }
571 
572     /**
573      * @see org.w3c.dom.Node#appendChild
574      */
575     public Node appendChild(Node newChild)
576         throws DOMException {
577         if (!fChildrenExpanded) {
578             expandChildren();
579         }
580         return super.appendChild(newChild);
581     }
582 
583     /**
584      * @see org.w3c.dom.Node#hasChildNodes
585      */
586     public boolean hasChildNodes() {
587         if (!fChildrenExpanded) {
588             return fTemplateNode.hasChildNodes();
589         } else {
590             return super.hasChildNodes();
591         }
592     }
593     
594     /**
595      * @see org.w3c.dom.Node#normalize
596      */
597     public void normalize() {
598         if (!fChildrenExpanded) {
599             expandChildren();
600         }
601         super.normalize();
602     }
603 
604     //-------------------------------------------------------------------------
605     // DocumentType support
606     //-------------------------------------------------------------------------
607 
608     /**
609      * Expand the document type if needed.
610      */
611     private synchronized void doExpandDocType() {
612         if (!fDocTypeExpanded) {
613             if (fExpandingDocType) {
614                 throw new LazyDOMError("recursive call expanding Lazy DOM DocumentType");
615             }
616             fExpandingDocType = true;
617             try {
618                 LazyDocumentType template = (LazyDocumentType)fTemplateNode.getDoctype();
619                 if (template != null) {
620                     docType = (LazyDocumentType)getNodeFromTemplate(template);
621                 }
622                 fDocTypeExpanded = true;
623             } finally {
624                 fExpandingDocType = false;
625             }
626         }
627     }
628 
629     /**
630      * @see Document#getDoctype
631      */
632     public DocumentType getDoctype() {
633         if (!fDocTypeExpanded) {
634             doExpandDocType();
635         }
636         return super.getDoctype();
637     }
638 
639     //-------------------------------------------------------------------------
640     // Implemention of node org.w3c.dom.Document factories
641     //-------------------------------------------------------------------------
642 
643     /**
644      * @see org.w3c.dom.Document#createElement
645      */
646     public Element createElement(String tagName) throws DOMException {
647         return new LazyElementNoNS(this, null, tagName);
648     }
649 
650     /**
651      * @see org.w3c.dom.Document#createTextNode
652      */
653     public Text createTextNode(String data) {
654         return new LazyText(this, null, data);
655     }
656 
657     /**
658      * @see org.w3c.dom.Document#createComment
659      */
660     public Comment createComment(String data) {
661         return new LazyComment(this, null, data);
662     }
663 
664     /**
665      * @see org.w3c.dom.Document#createCDATASection
666      */
667     public CDATASection createCDATASection(String data) throws DOMException {
668         return new LazyCDATASection(this, null, data);
669     }
670 
671     /**
672      * @see org.w3c.dom.Document#createProcessingInstruction
673      */
674     public ProcessingInstruction createProcessingInstruction(String target, 
675                                                              String data) {
676         return new LazyProcessingInstruction(this, null, target, data);
677     }
678 
679     /**
680      * @see org.w3c.dom.Document#createAttribute
681      */
682     public Attr createAttribute(String name) throws DOMException {
683         return new LazyAttrNoNS(this, null, name);
684     }
685 
686     /**
687      * @see org.w3c.dom.Document#createNotation
688      */
689     public Notation createNotation(String name) throws DOMException {
690         return new LazyNotation(this, null, name, null, null);
691     }
692 
693     /**
694      * @see org.w3c.dom.Document#createEntityReference
695      */
696     public EntityReference createEntityReference(String name) throws DOMException {
697         return new LazyEntityReference(this, null, name);
698     }
699 
700     /**
701      * @see org.w3c.dom.Document#createElementNS
702      */
703     public Element createElementNS(String namespaceURI, 
704                                    String qualifiedName) throws DOMException {
705         return new LazyElementNS(this, null, namespaceURI, qualifiedName);
706     }
707 
708     /**
709      * @see org.w3c.dom.Document#createAttributeNS
710      */
711     public Attr createAttributeNS(String namespaceURI, 
712                                   String qualifiedName) throws DOMException {
713         return new LazyAttrNS(this, null, namespaceURI, qualifiedName);
714     }
715 
716     /**
717      * Create a new DocumentType object (Non-DOM).
718      * @see DocumentImpl#createDocumentType
719      */
720     public DocumentType createDocumentType(String qualifiedName,
721                                            String publicID,
722                                            String systemID,
723                                            String internalSubset) throws DOMException {
724       return new LazyDocumentType(this, null, qualifiedName, publicID, systemID, internalSubset);
725     }
726 
727     /**
728      * Create a new DocumentType object (Non-DOM).  This overrides the method
729      * in the Xerces DOM used by importNode().
730      * @see DocumentImpl#createDocumentType
731      */
732     public DocumentType createDocumentType(String qualifiedName,
733                                            String publicID,
734                                            String systemID) throws DOMException {
735 
736       return new LazyDocumentType(this, null, qualifiedName, publicID, systemID, null);
737 
738     }
739     /**
740      * Create a new Entity object (Non-DOM).
741      * @see DocumentImpl#createEntity
742      */
743     public Entity createEntity(String name) throws DOMException {
744         return new LazyEntity(this, null, name, null, null, null);
745     }
746 
747     //-------------------------------------------------------------------------
748     // Node id-based node creation methods.
749     //-------------------------------------------------------------------------
750 
751     /**
752      * Create a element from a template given its id.
753      * @see org.w3c.dom.Document#createElement
754      */
755     public LazyElement createElement(int nodeId) throws DOMException {
756         Node template = (LazyElement)fTemplateDOM.getNode(nodeId);
757         if (template instanceof LazyElementNS) {
758             return new LazyElementNS(this, (LazyElementNS)template, null, null);
759         } else {
760             return new LazyElementNoNS(this, (LazyElementNoNS)template, null);
761         }
762     }
763 
764     /**
765      * Create a text node from a template given its id.
766      * @see org.w3c.dom.Document#createTextNode
767      */
768     public LazyText createTextNode(int nodeId) {
769         return new LazyText(this, (LazyText)fTemplateDOM.getNode(nodeId), null);
770     }
771 
772     /**
773      * Create a comment from a template given its id.
774      * @see org.w3c.dom.Document#createComment
775      */
776     public LazyComment createComment(int nodeId) {
777         return new LazyComment(this, (LazyComment)fTemplateDOM.getNode(nodeId), null);
778     }
779 
780     /**
781      * Create a CDATASection from a template given its id.
782      * @see org.w3c.dom.Document#createCDATASection
783      */
784     public LazyCDATASection createCDATASection(int nodeId) throws DOMException {
785         return new LazyCDATASection(this, (LazyCDATASection)fTemplateDOM.getNode(nodeId), null);
786     }
787 
788     /**
789      * Create a process instruction node from a template given its id.
790      * @see org.w3c.dom.Document#createProcessingInstruction
791      */
792     public LazyProcessingInstruction createProcessingInstruction(int nodeId) {
793         return new LazyProcessingInstruction(this, (LazyProcessingInstruction)fTemplateDOM.getNode(nodeId), null, null);
794     }
795 
796     /**
797      * Create an attribute from a template given its id.
798      * @see org.w3c.dom.Document#createAttribute
799      */
800     public LazyAttr createAttribute(int nodeId) throws DOMException {
801         Node template = fTemplateDOM.getNode(nodeId);
802         if (template instanceof LazyAttrNS) {
803             return new LazyAttrNS(this, (LazyAttrNS)template, null, null);
804         } else {
805             return new LazyAttrNoNS(this, (LazyAttrNoNS)fTemplateDOM.getNode(nodeId), null);
806         }
807     }
808 
809     /**
810      * Create a notation node from a template given its id.
811      * @see org.w3c.dom.Document#createNotation
812      */
813     public LazyNotation createNotation(int nodeId) throws DOMException {
814         return new LazyNotation(this, (LazyNotation)fTemplateDOM.getNode(nodeId),
815                                 null, null, null);
816     }
817 
818     /**
819      * Create a entity reference from a template given its id.
820      * @see org.w3c.dom.Document#createEntityReference
821      */
822     public LazyEntityReference createEntityReference(int nodeId) throws DOMException {
823         return new LazyEntityReference(this, (LazyEntityReference)fTemplateDOM.getNode(nodeId), null);
824     }
825 
826     /**
827      * Create a new DocumentType object (Non-DOM).
828      * @see DocumentImpl#createDocumentType
829      */
830     public LazyDocumentType createDocumentType(int nodeId) throws DOMException {
831         // FIXME: This isn't all that useful, as one can't set doctype after creating
832         // the document.
833       return new LazyDocumentType(this, (LazyDocumentType)fTemplateDOM.getNode(nodeId),
834                                     null, null, null, null);
835     }
836 
837     /**
838      * Create a new Entity object (Non-DOM).
839      * @see DocumentImpl#createEntity
840      */
841     public LazyEntity createEntity(int nodeId) throws DOMException {
842         return new LazyEntity(this, (LazyEntity)fTemplateDOM.getNode(nodeId),
843                               null, null, null, null);
844     }
845 
846     //-------------------------------------------------------------------------
847     // Template node creation methods.
848     //-------------------------------------------------------------------------
849 
850     /**
851      * Create a template element.  This will call the derived document create
852      * method.
853      *
854      * @see #createElement(String)
855      * @see org.w3c.dom.Document#createElement
856      */
857     public LazyElement createTemplateElement(String tagName,
858                                              int nodeId,
859                                              String preFormattedText) throws DOMException {
860         LazyElement element = (LazyElement)createElement(tagName);
861         element.makeTemplateNode(nodeId, preFormattedText);
862         return element;
863     }
864 
865     /**
866      * Create a template text node.  This will call the derived document
867      * create method.
868      *
869      * @see #createText(String)
870      * @see org.w3c.dom.Document#createTextNode
871      */
872     public LazyText createTemplateTextNode(String data,
873                                            int nodeId,
874                                            String preFormattedText) {
875         LazyText text = (LazyText)createTextNode(data);
876         text.makeTemplateNode(nodeId, preFormattedText);
877         return text;
878     }
879 
880     /**
881      * Create a template comment.  This will call the derived document create
882      * method.
883      *
884      * @see #createComment(String)
885      * @see org.w3c.dom.Document#createComment
886      */
887     public LazyComment createTemplateComment(String data,
888                                              int nodeId) {
889         LazyComment comment = (LazyComment)createComment(data);
890         comment.makeTemplateNode(nodeId);
891         return comment;
892     }
893 
894     /**
895      * Create a template CDATASection.  This will call the derived document
896      * create method.
897      *
898      * @see #createCDataSection(String)
899      * @see org.w3c.dom.Document#createCDATASection
900      */
901     public LazyCDATASection createTemplateCDATASection(String data,
902                                                        int nodeId) throws DOMException {
903         LazyCDATASection cdataSection = (LazyCDATASection)createCDATASection(data);
904         cdataSection.makeTemplateNode(nodeId);
905         return cdataSection;
906     }
907 
908     /**
909      * Create a template ProcessingInstruction.  This will call the derived
910      * document create method.
911      *
912      * @see #createProcessingInstruction(String,String)
913      * @see org.w3c.dom.Document#createProcessingInstruction
914      */
915     public LazyProcessingInstruction createTemplateProcessingInstruction(String target, 
916                                                                          String data,
917                                                                          int nodeId) {
918         LazyProcessingInstruction pi = (LazyProcessingInstruction)createProcessingInstruction(target, data);
919         pi.makeTemplateNode(nodeId);
920         return pi;
921     }
922 
923     /**
924      * Create a template Attr.  This will call the derived document create
925      * method.
926      *
927      * @see createAttribute(String)
928      * @see org.w3c.dom.Document#createAttribute
929      */
930     public LazyAttr createTemplateAttribute(String name,
931                                             int nodeId) throws DOMException {
932         LazyAttr attr = (LazyAttr)createAttribute(name);
933         attr.makeTemplateNode(nodeId);
934         return attr;
935     }
936 
937     /**
938      * Create a template Attr.  This will call the derived document create
939      * method.
940      *
941      * @see createAttributeNS(String,String)
942      * @see org.w3c.dom.Document#createAttributeNS
943      */
944     public LazyAttr createTemplateAttributeNS(String namespaceURI, 
945                                               String qualifiedName,
946                                               int nodeId) throws DOMException {
947         LazyAttr attr = (LazyAttr)createAttributeNS(namespaceURI, qualifiedName);
948         attr.makeTemplateNode(nodeId);
949         return attr;
950     }
951 
952     /**
953      * Create a template Notation.  This will call the derived document create
954      * method.
955      *
956      * @see #createNotation(String)
957      * @see org.w3c.dom.Document#createNotation
958      */
959     public LazyNotation createTemplateNotation(String name,
960                                                int nodeId) throws DOMException {
961         LazyNotation notation = (LazyNotation) createNotation(name);
962         notation.makeTemplateNode(nodeId);
963         return notation;
964     }
965 
966     /**
967      * Create a template EntityReference.  This will call the derived document
968      * create method.
969      *
970      * @see #createEntityReference(String)
971      * @see org.w3c.dom.Document#createEntityReference
972      */
973     public LazyEntityReference createTemplateEntityReference(String name,
974                                                              int nodeId) throws DOMException {
975         LazyEntityReference entityRef = (LazyEntityReference)createEntityReference(name);
976         entityRef.makeTemplateNode(nodeId);
977         return entityRef;
978     }
979 
980     /**
981      * Create a template Element with namespace.  This will call the derived
982      * document create method.
983      *
984      * @see #createElementNS(String,String)
985      * @see org.w3c.dom.Document#createElementNS
986      */
987     public LazyElement createTemplateElementNS(String namespaceURI, 
988                                                String qualifiedName,
989                                                int nodeId,
990                                                String preFormattedText) throws DOMException {
991         LazyElement element = (LazyElement)createElementNS(namespaceURI,
992                                                            qualifiedName);
993         element.makeTemplateNode(nodeId, preFormattedText);
994         return element;
995     }
996 
997     /**
998      * Create a template Attr with namespace.  This will call the derived
999      * document create method.
1000     *
1001     * @see #createAttributeNS(String,String)
1002     * @see org.w3c.dom.Document#createAttributeNS
1003     */
1004    public LazyAttr createAttributeNS(String namespaceURI, 
1005                                      String qualifiedName,
1006                                      int nodeId) throws DOMException {
1007        LazyAttr attr = (LazyAttr)createAttributeNS(namespaceURI, qualifiedName);
1008        attr.makeTemplateNode(nodeId);
1009        return attr;
1010    }
1011
1012    /**
1013     * Create a template DocumentType.
1014     *
1015     * @see #createDocumentType(String,String,String,String)
1016     * @see DocumentImpl#createDocumentType
1017     */
1018    public LazyDocumentType createTemplateDocumentType(String qualifiedName,
1019                                                       String publicID,
1020                                                       String systemID,
1021                                                       String internalSubset,
1022                                                       int nodeId) throws DOMException {
1023        LazyDocumentType docType = new LazyDocumentType(this, null, qualifiedName, publicID,
1024                                                        systemID, internalSubset);
1025        docType.makeTemplateNode(nodeId);
1026        return docType;
1027    }
1028
1029    /**
1030     * Create a template Entity.
1031     *
1032     * @see #createEntity(String)
1033     * @see DocumentImpl#createEntity
1034     */
1035    public LazyEntity createTemplateEntity(String name,
1036                                           String publicId,
1037                                           String systemId,
1038                                           String notationName,
1039                                           int nodeId) throws DOMException {
1040        LazyEntity entity = new LazyEntity(this, null, name, publicId,
1041                                           systemId, notationName);
1042        entity.makeTemplateNode(nodeId);
1043        return entity;
1044    }
1045
1046    //-------------------------------------------------------------------------
1047    // PreFormattedTextDocument specific
1048    //-------------------------------------------------------------------------
1049
1050    /**
1051     * OutputOptions used for creating the preformatted text.
1052     */
1053    private OutputOptions fPreFormatOutputOptions;
1054
1055    /**
1056     * Set the output options that were used to preformat this document.
1057     * @param outputOptions The output options; should be read-only.
1058     */
1059    public void setPreFormatOutputOptions(OutputOptions outputOptions) {
1060        fPreFormatOutputOptions = outputOptions;
1061    }
1062
1063    /**
1064     * @see PreFormattedTextDocument#getPreFormatOutputOptions
1065     */
1066    public OutputOptions getPreFormatOutputOptions() {
1067        return fPreFormatOutputOptions;
1068    }
1069}