KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ozoneDB > xml > dom > DocumentImpl


1 /**
2  * org/ozone-db/xml/dom/DocumentImpl.java
3  *
4  * The contents of this file are subject to the OpenXML Public
5  * License Version 1.0; you may not use this file except in compliance
6  * with the License. You may obtain a copy of the License at
7  * http://www.openxml.org/license.html
8  *
9  * THIS SOFTWARE IS DISTRIBUTED ON AN "AS IS" BASIS WITHOUT WARRANTY
10  * OF ANY KIND, EITHER EXPRESSED OR IMPLIED. THE INITIAL DEVELOPER
11  * AND ALL CONTRIBUTORS SHALL NOT BE LIABLE FOR ANY DAMAGES AS A
12  * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
13  * DERIVATIVES. SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING
14  * RIGHTS AND LIMITATIONS UNDER THE LICENSE.
15  *
16  * The Initial Developer of this code under the License is Assaf Arkin.
17  * Portions created by Assaf Arkin are Copyright (C) 1998, 1999.
18  * All Rights Reserved.
19  */

20
21 /**
22  * Changes for Persistent DOM running with ozone are
23  * Copyright 1999 by SMB GmbH. All rights reserved.
24  */

25
26 package org.ozoneDB.xml.dom;
27
28 import java.util.*;
29 import java.io.*;
30 import org.w3c.dom.*;
31 import org.ozoneDB.*;
32 import org.ozoneDB.xml.dom.*;
33 import org.ozoneDB.xml.util.XMLContainerHelper;
34
35
36 /**
37  * Implements an XML document, and also derived to implement an HTML document.
38  * Provides access to the top level element in the document ({@link
39  * #getDocumentElement}), to the DTD if one exists ({@link #getDoctype},
40  * and to all node operations.
41  * <P>
42  * Several methods create new nodes of all basic types (comment, text, element,
43  * etc.). These methods create new nodes but do not place them in the document
44  * tree. The nodes may be placed in the document tree using {@link
45  * org.w3c.dom.Node#appendChild} or {@link org.w3c.dom.Node#insertBefore}, or
46  * they may be placed in some other document tree.
47  * <P>
48  * Notes:
49  * <OL>
50  * <LI>Node type is {@link org.w3c.dom.Node#DOCUMENT_NODE}
51  * <LI>Node supports childern
52  * <LI>Node name is always "#document"
53  * <LI>Node does not have a value
54  * <LI>Node may not be added to other nodes
55  * </OL>
56  * This class contains some extensions beyond the DOM API definition. For a list
57  * of all extensions, see {@link org.ozoneDB.xml.XMLDocument}.
58  *
59  *
60  * @version $Revision$ $Date$
61  * @author <a HREF="mailto:arkin@trendline.co.il">Assaf Arkin</a>
62  * @see org.w3c.dom.Document
63  * @see NodeImpl
64  * @see org.w3c.dom.DOMImplementation
65  */

66 public class DocumentImpl extends NodeImpl implements DocumentProxy {
67
68     final static long serialVersionUID = 1;
69
70     private XMLContainerHelper container;
71
72
73     /**
74      * The document type definition of this document (per DOM API). Only available
75      * if document was created with a DTD and not available for HTML documents.
76      */

77     private DocumentTypeProxy _docType;
78
79     /**
80      * Holds a reference to the locking thread. When unlocked, this reference is
81      * null. This object is used both to designate a lock, identify the locking
82      * thread, and perform a {@link Object#wait}.
83      *
84      * @see #lock
85      * @see #unlock
86      */

87     private Thread JavaDoc _lockThread;
88
89
90     /**
91      * Implement counting on locks, allowing {@link #lock} to be called a
92      * multiple number of times, and {@link #unlock} to still retain the lock
93      * on the outer calls.
94      *
95      * @see #lock
96      * @see #unlock
97      */

98     private int _lockCount;
99
100
101     /**
102      * Holds names and classes of application element types. When an element
103      * with a particular tag name is created, the matching {@link java.lang.Class}
104      * is used to create the element object. This reference is null unless an
105      * element has been defined.
106      */

107     private Hashtable _elementTypes;
108
109     public void writeExternal( ObjectOutput out ) throws IOException {
110         super.writeExternal( out );
111         out.writeObject ( container );
112     }
113
114
115     public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException JavaDoc {
116         super.readExternal( in );
117         container = (XMLContainerHelper)in.readObject();
118     }
119
120
121     /**
122      * Set the container of this document. This is needed to find the
123      * container that is responsible for a given Node.
124      */

125     public void setContainer( XMLContainerHelper _container ) {
126         this.container = _container;
127     }
128
129
130     /**
131      * Get the container of this document. This is needed to find the
132      * container that is responsible for a given Node.
133      */

134     public XMLContainerHelper getContainer() {
135         return this.container;
136     }
137
138
139     public Node importNode( Node importedNode, boolean deep ) throws DOMException {
140         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
141                 "Document.importNode() : ozone's persistent DOM doesn't support DOM level 2 yet." );
142     }
143
144
145     public Element createElementNS( java.lang.String JavaDoc namespaceURI, java.lang.String JavaDoc qualifiedName )
146             throws DOMException {
147         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
148                 "Document.createElementNS() : ozone's persistent DOM doesn't support DOM level 2 yet." );
149     }
150
151
152     public Attr createAttributeNS( java.lang.String JavaDoc namespaceURI, java.lang.String JavaDoc qualifiedName ) throws DOMException {
153         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
154                 "Document.createAttributeNS() : ozone's persistent DOM doesn't support DOM level 2 yet." );
155     }
156
157
158     public NodeList getElementsByTagNameNS( java.lang.String JavaDoc namespaceURI, java.lang.String JavaDoc localName ) {
159         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
160                 "Document.getElementsByTagNameNS() : ozone's persistent DOM doesn't support DOM level 2 yet." );
161     }
162
163
164     public Element getElementById( java.lang.String JavaDoc elementId ) {
165         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
166                 "Document.getElementById() : ozone's persistent DOM doesn't support DOM level 2 yet." );
167     }
168
169
170     public Document createDocument( java.lang.String JavaDoc namespaceURI, java.lang.String JavaDoc qualifiedName,
171             DocumentType doctype ) throws DOMException {
172         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
173                 "Document.createDocument() : ozone's persistent DOM doesn't support DOM level 2 yet." );
174     }
175
176
177     public DocumentType createDocumentType( java.lang.String JavaDoc qualifiedName, java.lang.String JavaDoc publicId,
178             java.lang.String JavaDoc systemId ) throws DOMException {
179         throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR,
180                 "Document.createDocumentType() : ozone's persistent DOM doesn't support DOM level 2 yet." );
181     }
182
183
184     public short getNodeType() {
185         return DOCUMENT_NODE;
186     }
187
188
189     public final void setNodeValue( String JavaDoc value ) {
190         throw new DOMExceptionImpl( DOMException.NO_DATA_ALLOWED_ERR, "This node type does not support values." );
191     }
192
193
194     public final DocumentType getDoctype() {
195         return _docType;
196     }
197
198
199     public final void setDoctype( DocumentType docType ) {
200         _docType = (DocumentTypeProxy)docType;
201     }
202
203
204     public final DOMImplementation getImplementation() {
205         return this;
206     }
207
208
209     public Element getDocumentElement() {
210         Node child;
211
212         // Returns the top-level element in this document. Might not exist, or
213
// might be the first of many.
214
child = getFirstChild();
215         while (child != null) {
216             if (child instanceof Element) {
217                 return (Element)child;
218             }
219             child = child.getNextSibling();
220         }
221         return null;
222     }
223
224
225     public void setElementTypes( Hashtable elementTypes ) {
226         _elementTypes = elementTypes;
227     }
228
229
230     public Element createElement( String JavaDoc tagName ) throws DOMException {
231         ElementProxy elem = null;
232         try {
233             elem = (ElementProxy)database().createObject( ElementImpl.class.getName() );
234             elem.init( this, tagName, null, true );
235         } catch (Exception JavaDoc except) {
236             throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
237         }
238         return elem;
239     }
240
241
242     public final DocumentFragment createDocumentFragment() {
243         DocumentFragmentProxy fragment = null;
244         try {
245             fragment = (DocumentFragmentProxy)database().createObject( DocumentFragmentImpl.class.getName() );
246             fragment.init( this, null );
247         } catch (Exception JavaDoc except) {
248             throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
249         }
250         return fragment;
251     }
252
253
254     public final Text createTextNode( String JavaDoc data ) {
255         TextProxy text = null;
256         try {
257             text = (TextProxy)database().createObject( TextImpl.class.getName() );
258             text.init( this, data );
259         } catch (Exception JavaDoc except) {
260             throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
261         }
262         return text;
263     }
264
265
266     public final Comment createComment( String JavaDoc data ) {
267         CommentProxy comment = null;
268         try {
269             comment = (CommentProxy)database().createObject( CommentImpl.class.getName() );
270             comment.init( this, data );
271         } catch (Exception JavaDoc except) {
272             throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
273         }
274         return comment;
275     }
276
277
278     public final CDATASection createCDATASection( String JavaDoc data ) throws DOMException {
279         CDATASectionProxy section = null;
280         try {
281             section = (CDATASectionProxy)database().createObject( CDATASectionImpl.class.getName() );
282             section.init( this, data );
283         } catch (Exception JavaDoc except) {
284             throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
285         }
286         return section;
287     }
288
289
290     public final ProcessingInstruction createProcessingInstruction( String JavaDoc target, String JavaDoc data ) throws DOMException {
291         ProcessingInstructionProxy pi = null;
292         try {
293             pi = (ProcessingInstructionProxy)database().createObject( ProcessingInstructionImpl.class.getName() );
294             pi.init( this, target, data );
295         } catch (Exception JavaDoc except) {
296             throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
297         }
298         return pi;
299     }
300
301
302     public final Attr createAttribute( String JavaDoc name ) throws DOMException {
303         AttrProxy attr = null;
304         try {
305             attr = (AttrProxy)database().createObject( AttrImpl.class.getName() );
306             attr.init( this, name, "" );
307         } catch (Exception JavaDoc except) {
308             except.printStackTrace();
309             throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
310         }
311         return attr;
312     }
313
314
315     /**
316      * Creates an attribute with the default value specified in the DTD.
317      * This method is not defined in the DOM but is used by the parser.
318      *
319      * @param name The name of the attribute
320      * @param defValue The default value of the attribute
321      */

322     public final Attr createAttribute( String JavaDoc name, String JavaDoc defValue ) throws DOMException {
323         AttrProxy attr = null;
324         try {
325             attr = (AttrProxy)database().createObject( AttrImpl.class.getName() );
326             attr.init( this, name, defValue == null ? "" : defValue );
327         } catch (Exception JavaDoc except) {
328             throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
329         }
330         return attr;
331     }
332
333
334     public final EntityReference createEntityReference( String JavaDoc name ) throws DOMException {
335         EntityReferenceProxy entity = null;
336         try {
337             entity = (EntityReferenceProxy)database().createObject( EntityReferenceImpl.class.getName() );
338         // entity.init (this, name);
339
} catch (Exception JavaDoc except) {
340             throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
341         }
342         return entity;
343     }
344
345     /**
346      * Creates a document type with the specified name (the name follows the
347      * <TT>!DOCTYPE</TT> entity) and associates it with the document.
348      * If the document is HTML or already has a DTD associated with it, throws
349      * an exception. This method is not defined in the DOM but is used by the
350      * parser.
351      *
352      * @param name The name of the document type
353      * @param name The public identifier, if exists
354      * @param name The system identifier, if exists
355      * @throws org.w3c.dom.DOMException <T>NOT_SUPPORTED_ERR</TT>
356      * Document is HTML or already has a DTD
357      */

358     /*
359     public final DocumentType createDocumentType (String name, String publicId,
360                                                   String systemId)
361                                                   throws DOMException {
362         if (isHtmlDoc () || _docType != null)
363             throw new DOMExceptionImpl (DOMException.NOT_SUPPORTED_ERR);
364         _docType = new DocumentTypeImpl( this, name );
365         return _docType;
366         }
367      */

368
369
370     public final NodeList getElementsByTagName( String JavaDoc tagName ) {
371         return new org.ozoneDB.xml.dom.ElementListImpl( this, tagName );
372     }
373
374
375     /**
376      * Return true if certain feature for specific DOM version supported by this
377      * implementation.
378      *
379      * @param feature Name of feature to check
380      * @param version Optional version number
381      * @return True if supported
382      */

383     public boolean hasFeature( String JavaDoc feature, String JavaDoc version ) {
384         // Versions higher than 1.0 not supported yet.
385
if (version != null) {
386             if (version.indexOf( "1.0" ) < 0 && version.indexOf( "Level 1" ) < 0) {
387                 return false;
388             }
389         }
390         // Supports XML and HTML.
391
if (feature != null) {
392             if (feature.equalsIgnoreCase( "XML" ) || feature.equalsIgnoreCase( "HTML" )) {
393                 return true;
394             }
395         }
396         return false;
397     }
398
399
400     /**
401      * Register an application-defined element type. The element's tag name and
402      * class are specified. When a so named element is created with {@link
403      * #createElement}, an object of the specified class is created and returned.
404      * This allows applications to define classes for specific element types.
405      *
406      * @param tagName The name of the element tag
407      * @param elementClass Class derived from {@link org.ozoneDB.xml.XMLElement},
408      * used to construct the element
409      */

410     public void registerElement( String JavaDoc tagName, Class JavaDoc elementClass ) {
411         if (tagName == null || tagName.length() == 0) {
412             throw new NullPointerException JavaDoc( "Argument 'tagName' is null or an empty string." );
413         }
414         if (elementClass == null || elementClass.isAssignableFrom( Element.class )) {
415             throw new IllegalArgumentException JavaDoc( "Argument 'elementClass' is null or does not extend Element." );
416         }
417         if (_elementTypes == null) {
418             _elementTypes = new Hashtable();
419         }
420         _elementTypes.put( tagName, elementClass );
421     }
422
423
424     public void assignDoctype( DocumentTypeProxy docType ) {
425         if (docType == null) {
426             throw new NullPointerException JavaDoc( "Argument 'docType' is null." );
427         }
428         if (_docType != null) {
429             throw new IllegalStateException JavaDoc( "Document type already assigned to this document." );
430         }
431         _docType = docType;
432     }
433
434     /**
435      * Implements a lock mechanism. The lock mechanism differs from synchronization
436      * in that it supports multiple function calls, while still preserving the lock
437      * granted to a specific thread. Caution is required as other threads may obtain
438      * access without first acquiring lock. All implementations of the lock mechanism
439      * should use {@link #lock}, {@link #unlock} and {@link #acquire} to assure true
440      * synchronization.
441      * <P>
442      * Calling {@link #lock} obtains a lock to the current running thread. If the
443      * lock has already been granted to some other thread, this call will block
444      * until the lock is released or until the lock has timed out.
445      * <P>
446      * Calling {@link #unlock} releases the lock from the current thread, if still
447      * held by the current thread. A thread may call {@link #lock} any number of
448      * times and must call {@link #unlock} that number of times to release the
449      * lock. The thread may call {@link #unlock} an additional number of times if
450      * necessary by the implementation.
451      * <P>
452      * If a thread requires access to a resource that might be lock, it should
453      * acquire it by calling {@link #acquire}. This method will block until the
454      * resource is unlocked by some other thread. If the resource is unlocked,
455      * or locked by the current thread, {@link #acquire} will return immediately.
456      */

457
458
459     /**
460      * Obtains a lock, preventing other threads from gaining access to the locked
461      * resource. The lock is retained across multiple calls, until {@link #unlock}
462      * is called. Attempts to call {@link #acquire} from another thread will be
463      * blocked.
464      * <P>
465      * If the resource is already locked by another thread, the method will
466      * block until the lock is released or until the block has timedout.
467      * <P>
468      * {@link #lock} may be called any number of times, and {@link #unlock} must
469      * be called that number of times to release the lock.
470      *
471      * @see #unlock
472      */

473     public void lock() throws RuntimeException JavaDoc {
474         synchronized (this) {
475             // If current thread is locking, increase the lock count.
476
// Otherwise, wait for lock to be released, acquire the lock and
477
// increase the lock count. If timeout has reached or thread has
478
// been interrupted, acquire() will throw an exception.
479
if (_lockThread == Thread.currentThread()) {
480                 ++_lockCount;
481             } else {
482                 acquire( Long.MAX_VALUE );
483                 _lockThread = Thread.currentThread();
484                 ++_lockCount;
485             }
486         }
487     }
488
489
490     /**
491      * Releases a lock, so other thread may gain access to the resource. {@link
492      * #unlock} must be called as many times as {@link #lock} was called to
493      * release the lock. {@link #unlock} may be called an additional number of
494      * times, if so required by the implementation (e.g. to assure that a lock
495      * is released at the end of a thread).
496      *
497      * @see #lock
498      */

499     public void unlock() {
500         // If the current thread is locking, decrease the lock count.
501
// If the lock count is zero, release the lock, otherwise unlock()
502
// must be called again to release lock.
503
if (_lockThread == Thread.currentThread()) {
504             synchronized (this) {
505                 --_lockCount;
506                 if (_lockCount == 0) {
507                     _lockThread = null;
508                     notify();
509                 }
510             }
511         }
512     }
513
514
515     /**
516      * Called to acquire access to a possible locked resource. If the resource
517      * was locked by the current thread, the method will return immediately.
518      * If the resource was locked by some other thread, the method will block
519      * until the resource is unlocked, or the block has timed out.
520      *
521      * @see #lock
522      * @see #unlock
523      */

524     public void acquire( long lockTimeout ) throws RuntimeException JavaDoc {
525         long start;
526
527         synchronized (this) {
528             try {
529                 // If the application is not locked by the current thread,
530
// wait until the application is unlocked, then proceed.
531
if (_lockThread != Thread.currentThread() && _lockThread != null) {
532                     // Remember when started waiting for lock to implement
533
// timeout. Repeat until lock is released by other thread,
534
// or until timeout has expired.
535
start = System.currentTimeMillis();
536                     while (_lockThread != null && lockTimeout > (System.currentTimeMillis() - start)) {
537                         // If the locking thread is dead, release the lock
538
// immediately, otherwise, wait for it to be released.
539
if (!_lockThread.isAlive()) {
540                             _lockThread = null;
541                         } else {
542                             wait( lockTimeout - System.currentTimeMillis() - start );
543                         }
544                     }
545                     // Timeout, throw an exception.
546
if (_lockThread != null) {
547                         throw new RuntimeException JavaDoc( "Timeout waiting for lock to be released." );
548                     }
549                 }
550             } catch (InterruptedException JavaDoc except) {
551                 // Thread interrupted, throw an exception.
552
throw new RuntimeException JavaDoc( "Timeout waiting for lock to be released." );
553             }
554         }
555     }
556
557
558     public synchronized boolean equals( Object JavaDoc other ) {
559         DocumentProxy otherX;
560
561         // Use Node's equals method to perform the first tests of equality.
562
// If these tests do not pass, return false.
563
if (!super.equals( other )) {
564             return false;
565         }
566
567         // Very simple equality test: are the document types equal.
568
// There's nothing else about the document to compare.
569
synchronized (other) {
570             otherX = (DocumentProxy)other;
571             return
572                     getDoctype() == null && otherX.getDoctype() == null || getDoctype() != null && otherX.getDoctype()
573                     != null && _docType.equals( otherX.getDoctype() );
574         }
575     }
576
577
578     public Object JavaDoc clone() {
579         DocumentProxy clone = null;
580         try {
581             clone = (DocumentProxy)database().createObject( DocumentImpl.class.getName() );
582             cloneInto( clone, true );
583         } catch (Exception JavaDoc except) {
584             throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
585         }
586         return clone;
587     }
588
589
590     public Node cloneNode( boolean deep ) {
591         DocumentProxy clone = null;
592         try {
593             clone = (DocumentProxy)database().createObject( DocumentImpl.class.getName() );
594             cloneInto( clone, deep );
595         } catch (Exception JavaDoc except) {
596             throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
597         }
598         return clone;
599     }
600
601     public String JavaDoc toString() {
602         return "Document: ";
603     }
604
605
606     public synchronized void cloneInto( NodeProxy into, boolean deep ) {
607
608         // Use the Node cloning method. The DOM object does not need cloning,
609
// but the document type (which contains entities, notations, etc)
610
// must be cloned.
611
super.cloneInto( into, deep );
612         if (deep) {
613             if (_docType != null) {
614                 ((DocumentProxy)into).setDoctype( (DocumentTypeProxy)_docType.clone() );
615             }
616             // If application elements are defined, clone the list as well.
617
if (_elementTypes != null) {
618                 ((DocumentProxy)into).setElementTypes( (Hashtable)_elementTypes.clone() );
619             }
620         } else {
621             ((DocumentProxy)into).setDoctype( _docType );
622             ((DocumentProxy)into).setElementTypes( _elementTypes );
623         }
624     // ((DocumentProxy)into).setElementFactory (_elementFactory);
625
}
626
627
628     protected final boolean supportsChildern() {
629         return true;
630     }
631
632
633     public DocumentImpl() {
634         super( null, "#document", null, false );
635         _ownerDocument = this;
636     }
637
638
639     protected DocumentImpl( String JavaDoc rootElement ) {
640         super( null, rootElement != null ? rootElement : "", null, rootElement != null );
641         _ownerDocument = this;
642     }
643
644
645     public void onDelete() {
646         clearDocument();
647     }
648
649
650     private void deleteAllChildern( Node node ) {
651         Node dummyNode;
652         while (node != null) {
653             if (node.hasChildNodes()) {
654                 deleteAllChildern( node.getFirstChild() );
655             }
656             dummyNode = node.getNextSibling();
657             System.out.println( "deleting " + node.getNodeName() );
658             database().deleteObject( (OzoneRemote)node );
659             node = dummyNode;
660         }
661     }
662
663     /**
664      * Deletes all child Nodes from this Document to provide a fresh and
665      * empty Document. Attention: This methods permanently removes the
666      * existing content!
667      */

668     public void clearDocument() {
669         // System.out.println( "clearDocument() " );
670
if (_docType != null) {
671             database().deleteObject( _docType );
672         }
673         Node node = getFirstChild();
674         while (node != null) {
675             deleteAllChildern( node );
676             node = getNextSibling();
677         }
678     }
679
680 }
Popular Tags