001: /**
002: * org/ozone-db/xml/dom/DocumentTypeImpl.java
003: *
004: * The contents of this file are subject to the OpenXML Public
005: * License Version 1.0; you may not use this file except in compliance
006: * with the License. You may obtain a copy of the License at
007: * http://www.openxml.org/license.html
008: *
009: * THIS SOFTWARE IS DISTRIBUTED ON AN "AS IS" BASIS WITHOUT WARRANTY
010: * OF ANY KIND, EITHER EXPRESSED OR IMPLIED. THE INITIAL DEVELOPER
011: * AND ALL CONTRIBUTORS SHALL NOT BE LIABLE FOR ANY DAMAGES AS A
012: * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
013: * DERIVATIVES. SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING
014: * RIGHTS AND LIMITATIONS UNDER THE LICENSE.
015: *
016: * The Initial Developer of this code under the License is Assaf Arkin.
017: * Portions created by Assaf Arkin are Copyright (C) 1998, 1999.
018: * All Rights Reserved.
019: */
020:
021: /**
022: * Changes for Persistent DOM running with ozone are
023: * Copyright 1999 by SMB GmbH. All rights reserved.
024: */package org.ozoneDB.xml.dom;
025:
026: import java.util.*;
027: import java.io.*;
028: import org.w3c.dom.*;
029:
030: /**
031: * Each document {@link org.w3c.dom.Document#getDoctype()} attribute whose
032: * value is either null or an object that represents the document type definition
033: * (DTD). HTML documents do not have a DTD. At the moment, this object provides
034: * the list of entities that are defined for the document and little else.
035: * Access is provided through {@link org.w3c.dom.NamedNodeMap} collections.
036: * <P>
037: * Notes:
038: * <OL>
039: * <LI>Node type is {@link org.w3c.dom.Node#DOCUMENT_TYPE_NODE}
040: * <LI>Does not support childern
041: * <LI>Node does not have a value
042: * <LI>Node does not have parents or siblings and is only accessible from
043: * {@link org.w3c.dom.Document}
044: * </OL>
045: * <P>
046: * The internal implementation also provides access to other elements that are
047: * part of the DTD, so full XML documents can be generated and parsed. These
048: * extensions are beyond the DOM API and are covered in an extended API.
049: * For more information see {@link org.openxml.DTDDocument}.
050: *
051: *
052: * @version $Revision: 1.1 $ $Date: 2001/12/18 11:03:24 $
053: * @author <a href="mailto:arkin@trendline.co.il">Assaf Arkin</a>
054: * @see org.w3c.dom.DocumentType
055: * @see org.openxml.DTDDocument
056: * @see NodeImpl
057: * @see org.w3c.dom.NamedNodeMap
058: */
059: public class DocumentTypeImpl extends DocumentImpl implements
060: DocumentTypeProxy {
061:
062: final static long serialVersionUID = 1;
063:
064: public java.lang.String getInternalSubset() {
065: throw new DOMExceptionImpl(
066: DOMException.NOT_SUPPORTED_ERR,
067: "DocumentType.getInternalSubset(): ozone's persistent DOM doesn't support DOM level 2 yet.");
068: }
069:
070: public short getNodeType() {
071: return DOCUMENT_TYPE_NODE;
072: }
073:
074: public String getName() {
075: return getNodeName();
076: }
077:
078: public NamedNodeMap getEntities() {
079: return (NamedNodeMap) _entities;
080: }
081:
082: public void setEntities(NamedNodeMap entities) {
083: _entities = (NamedNodeMapProxy) entities;
084: }
085:
086: public NamedNodeMap getNotations() {
087: return (NamedNodeMap) _notations;
088: }
089:
090: public void setNotations(NamedNodeMap notations) {
091: _notations = (NamedNodeMapProxy) notations;
092: }
093:
094: public Hashtable getParams() {
095: return _params;
096: }
097:
098: public void setParams(Hashtable params) {
099: _params = params;
100: }
101:
102: public String getPublicId() {
103: return _publicId;
104: }
105:
106: public void setSystemId(String systemId) {
107: _systemId = systemId;
108: }
109:
110: public void setPublicId(String publicId) {
111: _publicId = publicId;
112: }
113:
114: public String getSystemId() {
115: return _systemId;
116: }
117:
118: public String internalAsText() {
119: return null;
120: }
121:
122: public boolean getStandalone() {
123: return _standalone;
124: }
125:
126: public void setStandalone(boolean standalone) {
127: _standalone = standalone;
128: }
129:
130: /**
131: * Creates a new external general entity declaration and returns it.
132: *
133: * @param name The notation name
134: * @param systemID The system identifier
135: * @param publicID The public identifier
136: * @return Returns a new entity node
137: */
138: public Entity createEntity(String name, String systemID,
139: String publicID) {
140: EntityProxy entity = null;
141: try {
142: entity = (EntityProxy) database().createObject(
143: EntityImpl.class.getName());
144: entity.init(this , name, systemID, publicID);
145: } catch (Exception except) {
146: throw new DOMExceptionImpl(DOMExceptionImpl.PDOM_ERR,
147: except.getMessage());
148: }
149: return (Entity) entity;
150: }
151:
152: /**
153: * Creates a new unparsed general entity declaration and returns it.
154: *
155: * @param name The notation name
156: * @param systemID The system identifier
157: * @param publicID The public identifier
158: * @param notation The notation
159: * @return Returns a new entity node
160: */
161: public Entity createEntity(String name, String systemID,
162: String publicID, String notation) {
163: EntityProxy entity = null;
164: try {
165: entity = (EntityProxy) database().createObject(
166: EntityImpl.class.getName());
167: entity.init(this , name, systemID, publicID, notation);
168: } catch (Exception except) {
169: throw new DOMExceptionImpl(DOMExceptionImpl.PDOM_ERR,
170: except.getMessage());
171: }
172: return entity;
173: }
174:
175: /**
176: * Creates a new internal entity declaration and returns it. The entity value
177: * is given after parameter entity and character reference substitution.
178: *
179: * @param name The notation name
180: * @param value The entity value
181: * @return Returns a new entity node
182: */
183: public Entity createEntity(String name, String value) {
184: EntityProxy entity = null;
185: try {
186: entity = (EntityProxy) database().createObject(
187: EntityImpl.class.getName());
188: entity.init(this , name, value);
189: } catch (Exception except) {
190: throw new DOMExceptionImpl(DOMExceptionImpl.PDOM_ERR,
191: except.getMessage());
192: }
193: return entity;
194: }
195:
196: /**
197: * Declares a new general entity declaration. If a general entity with the same
198: * name is already declared, it remains intact and the existing entity is
199: * returned. If no such entity exists, the entity is declared and returned.
200: *
201: * @param general The general entity to declare
202: * @return The declared entity
203: */
204: public Entity declareEntity(Entity general) {
205: EntityProxy old = null;
206:
207: isReadOnly();
208: if (_entities == null) {
209: try {
210: _entities = (NamedNodeMapProxy) database()
211: .createObject(NamedNodeMapImpl.class.getName());
212: _entities.init(this , new Hashtable());
213: } catch (Exception except) {
214: throw new DOMExceptionImpl(DOMExceptionImpl.PDOM_ERR,
215: except.getMessage());
216: }
217: old = null;
218: } else {
219: old = (EntityProxy) _entities.getNamedItem(general
220: .getNodeName());
221: }
222: if (old == null) {
223: _entities.setNamedItem(general);
224: return general;
225: } else {
226: return old;
227: }
228: }
229:
230: /**
231: * Returns the named general entity declaration if one has been declared.
232: *
233: * @param name The entity name
234: * @return The named general entity
235: */
236: public Entity findEntity(String name) {
237: if (_entities == null) {
238: return null;
239: }
240: return (Entity) _entities.getNamedItem(name);
241: }
242:
243: /*
244: public EntityImpl deleteEntity( String name )
245: {
246: return (EntityImpl) _entities.removeNamedItem( name );
247: }
248: */
249:
250: /**
251: * Creates a new notation and returns it. Notation must have either or both
252: * system and public identifiers.
253: *
254: * @param name The notation name
255: * @param systemID The system identifier
256: * @param publicID The public identifier
257: * @return Returns a new notation node
258: */
259: public Notation createNotation(String name, String systemID,
260: String publicID) {
261: NotationProxy notation = null;
262: try {
263: notation = (NotationProxy) database().createObject(
264: NotationImpl.class.getName());
265: notation.init(this , name, systemID, publicID);
266: } catch (Exception except) {
267: throw new DOMExceptionImpl(DOMExceptionImpl.PDOM_ERR,
268: except.getMessage());
269: }
270: return (Notation) notation;
271: }
272:
273: /**
274: * Declares a new notation. If a notation with the same name is already
275: * declared, it remains intact and the existing notation is returned.
276: * If no such notation exists, the notation is declared and returned.
277: *
278: * @param notation The notation to declare
279: * @return The declared notation
280: */
281: public Notation declareNotation(Notation notation) {
282: NotationProxy old;
283:
284: isReadOnly();
285: if (_notations == null) {
286: try {
287: _notations = (NamedNodeMapProxy) database()
288: .createObject(NamedNodeMapImpl.class.getName());
289: _notations.init(this , new Hashtable());
290: old = null;
291: } catch (Exception except) {
292: throw new DOMExceptionImpl(DOMExceptionImpl.PDOM_ERR,
293: except.getMessage());
294: }
295: } else {
296: old = (NotationProxy) _notations.getNamedItem(notation
297: .getNodeName());
298: }
299: if (old == null) {
300: _notations.setNamedItem(notation);
301: return notation;
302: } else {
303: return old;
304: }
305: }
306:
307: /**
308: * Returns the named notation if one has been declared.
309: *
310: * @param name The notation name
311: * @return The named notation
312: */
313: public Notation findNotation(String name) {
314: if (_notations == null) {
315: return null;
316: }
317: return (Notation) _notations.getNamedItem(name);
318: }
319:
320: /**
321: * Creates a new external parameter entity and returns it.
322: *
323: * @param name The notation name
324: * @param systemID The system identifier
325: * @param publicID The public identifier
326: * @return Returns a new entity node
327: */
328: public ParamEntity createParamEntity(String name, String systemID,
329: String publicID) {
330: ParamEntityProxy entity;
331: try {
332: entity = (ParamEntityProxy) database().createObject(
333: ParamEntity.class.getName());
334: entity.init((DocumentProxy) this , name, systemID, publicID);
335: } catch (Exception except) {
336: throw new DOMExceptionImpl(DOMExceptionImpl.PDOM_ERR,
337: except.getMessage());
338: }
339: return (ParamEntity) entity;
340: }
341:
342: /**
343: * Creates a new internal parameter and returns it. The entity value is given
344: * after character reference substitution.
345: *
346: * @param name The notation name
347: * @param value The entity value
348: * @return Returns a new entity node
349: */
350: public ParamEntity createParamEntity(String name, String value) {
351: ParamEntityProxy entity;
352: try {
353: entity = (ParamEntityProxy) database().createObject(
354: ParamEntity.class.getName());
355: entity.init(this , name, value);
356: } catch (Exception except) {
357: throw new DOMExceptionImpl(DOMExceptionImpl.PDOM_ERR,
358: except.getMessage());
359: }
360: return (ParamEntity) entity;
361: }
362:
363: /**
364: * Declares a new parameter entity. If a parameter entity with the same name
365: * is already declared, it remains intact and the existing entity is returned.
366: * If no such entity exists, the entity is declared and returned.
367: *
368: * @param general The parameter entity to declare
369: * @return The declared entity
370: */
371: public ParamEntity declareParamEntity(ParamEntity param) {
372: ParamEntity old;
373:
374: isReadOnly();
375: if (_params == null) {
376: _params = new Hashtable();
377: old = null;
378: } else {
379: old = (ParamEntity) _params.get(param.getNodeName());
380: }
381: if (old == null) {
382: _params.put(param.getNodeName(), param);
383: return param;
384: } else {
385: return old;
386: }
387: }
388:
389: /**
390: * Returns the named parameter entity if one has been declared.
391: *
392: *
393: * @param name The entity name
394: * @return The named parameter entity
395: */
396: public ParamEntity findParamEntity(String name) {
397: if (_params == null) {
398: return null;
399: }
400: return (ParamEntity) _params.get(name);
401: }
402:
403: /**
404: * Returns a dictionary of all the parameter entitites declared in this
405: * DTD. If no PEs were declared, null is returned.
406: *
407: *
408: * @return Dictionary of param entities, or null
409: */
410: public Dictionary getParamEntities() {
411: return _params;
412: }
413:
414: public boolean isStandalone() {
415: return _standalone;
416: }
417:
418: public Element getDocumentElement() {
419: return null;
420: }
421:
422: /*
423: public Element createElement( String tagName )
424: throws DOMException
425: {
426: throw new DOMExceptionImpl( DOMException.NOT_SUPPORTED_ERR );
427: }
428: */
429:
430: public synchronized boolean equals(Object other) {
431: DocumentTypeProxy otherX;
432: boolean equal;
433:
434: // Use Node's equals method to perform the first tests of equality.
435: // If these tests do not pass, return false.
436: if (!super .equals(other)) {
437: return false;
438: }
439:
440: // Very simple equality test: are the document types equal.
441: // There's nothing else about the document to compare.
442: synchronized (other) {
443: otherX = (DocumentTypeProxy) other;
444: equal = _standalone == otherX.getStandalone()
445: && (_systemId == null
446: && otherX.getSystemId() == null || _systemId != null
447: && otherX.getSystemId() != null
448: && _systemId.equals(otherX.getSystemId())
449: && (_publicId == null
450: && otherX.getPublicId() == null || _publicId != null
451: && otherX.getPublicId() != null
452: && _publicId.equals(otherX
453: .getPublicId())));
454: if (equal) {
455: equal = _entities == null
456: && otherX.getEntities() == null
457: || _entities != null
458: && otherX.getEntities() != null
459: && _entities.equals(otherX.getEntities());
460: }
461: if (equal) {
462: equal = _notations == null
463: && otherX.getNotations() == null
464: || _notations != null
465: && otherX.getNotations() != null
466: && _notations.equals(otherX.getNotations());
467: }
468: if (equal) {
469: equal = _params == null && otherX.getParams() == null
470: || _params != null
471: && otherX.getParams() != null
472: && _params.equals(otherX.getParams());
473: }
474: }
475: return equal;
476: }
477:
478: public Object clone() {
479: DocumentTypeProxy clone = null;
480: try {
481: clone = (DocumentTypeProxy) database().createObject(
482: DocumentTypeImpl.class.getName(), 0, null);
483: clone.init(_systemId);
484: cloneInto((NodeProxy) clone, true);
485: } catch (Exception except) {
486: throw new DOMExceptionImpl(DOMExceptionImpl.PDOM_ERR,
487: except.getMessage());
488: }
489: return clone;
490: }
491:
492: public Node cloneNode(boolean deep) {
493: DocumentTypeProxy clone = null;
494: try {
495: clone = (DocumentTypeProxy) database().createObject(
496: DocumentTypeImpl.class.getName());
497: clone.init(_systemId);
498: cloneInto((NodeProxy) clone, deep);
499: } catch (Exception except) {
500: throw new DOMExceptionImpl(DOMExceptionImpl.PDOM_ERR,
501: except.getMessage());
502: }
503: return clone;
504: }
505:
506: public String toString() {
507: String name;
508:
509: name = getName();
510: if (name.length() > 32) {
511: name = name.substring(0, 32) + "..";
512: }
513: name = name.replace('\n', '|');
514: return "Doctype { " + name + " }";
515: }
516:
517: public synchronized void cloneInto( NodeProxy into, boolean deep ) {
518: Hashtable dictionary;
519: Enumeration enum;
520: Node node;
521:
522: // Use the parent to clone the object. If the clone is shallow, the cloned
523: // will contain reference to the same node maps. If the clone is deep,
524: // these node maps must be duplicated.
525: super .cloneInto( into, deep );
526:
527: ((DocumentTypeProxy)into).setStandalone( _standalone );
528: ((DocumentTypeProxy)into).setSystemId( _systemId );
529: ((DocumentTypeProxy)into).setPublicId( _publicId );
530:
531: if (deep) {
532: // Repeat this for each node map. Create a new dictionary, get an
533: // enumeration of the elements in the node map, one by one clone each
534: // element and place it in the new dictionary. Create a new node map
535: // with that new dictionary and associate it with the clone.
536: if (_entities != null) {
537: dictionary = new Hashtable();
538: enum = _entities.elements();
539: while (enum.hasMoreElements()) {
540: node = ((Node)enum.nextElement()).cloneNode( deep );
541: dictionary.put( node.getNodeName(), node );
542: }
543: try {
544: NamedNodeMapProxy entities =
545: (NamedNodeMapProxy)database().createObject( NamedNodeMapImpl.class.getName() );
546: entities.init( into, dictionary );
547: ((DocumentTypeProxy)into).setEntities( entities );
548: } catch (Exception except) {
549: throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
550: }
551: }
552:
553: // Repeat after me...
554: if (_notations != null) {
555: dictionary = new Hashtable();
556: enum = _notations.elements();
557: while (enum.hasMoreElements()) {
558: node = ((Node)enum.nextElement()).cloneNode( deep );
559: dictionary.put( node.getNodeName(), node );
560: }
561: try {
562: NamedNodeMapProxy notations =
563: (NamedNodeMapProxy)database().createObject( NamedNodeMapImpl.class.getName() );
564: notations.init( into, dictionary );
565: ((DocumentTypeProxy)into).setNotations( notations );
566: } catch (Exception except) {
567: throw new DOMExceptionImpl( DOMExceptionImpl.PDOM_ERR, except.getMessage() );
568: }
569: }
570:
571: // Repeat after me...
572: if (_params != null) {
573: dictionary = new Hashtable();
574: enum = _params.elements();
575: while (enum.hasMoreElements()) {
576: node = ((Node)enum.nextElement()).cloneNode( deep );
577: dictionary.put( node.getNodeName(), node );
578: }
579: ((DocumentTypeProxy)into).setParams( dictionary );
580: }
581: } else {
582: ((DocumentTypeProxy)into).setEntities( _entities );
583: ((DocumentTypeProxy)into).setNotations( _notations );
584: ((DocumentTypeProxy)into).setParams( _params );
585: }
586: } protected Node castNewChild(Node newChild) throws DOMException {
587: Node result;
588:
589: // New children can either be an entity, a notation, an element or an
590: // attribute definition.
591: if (newChild == null) {
592: throw new DOMExceptionImpl(
593: DOMException.HIERARCHY_REQUEST_ERR,
594: "Child reference is null.");
595: }
596: if (!(newChild instanceof Node)) {
597: throw new DOMExceptionImpl(
598: DOMException.HIERARCHY_REQUEST_ERR,
599: "Child is not a compatible type for this node.");
600: }
601:
602: if (!(newChild instanceof Entity
603: || newChild instanceof ParamEntity
604: || newChild instanceof Notation
605: || newChild instanceof ElementDeclProxy
606: || newChild instanceof AttlistDecl
607: || newChild instanceof Text
608: || newChild instanceof Comment || newChild instanceof ProcessingInstruction)) {
609: throw new DOMExceptionImpl(
610: DOMException.HIERARCHY_REQUEST_ERR,
611: "Child is not a compatible type for this node.");
612: }
613: return (Node) newChild;
614: }
615:
616: public DocumentTypeImpl(String systemId) {
617: super (null);
618: _ownerDocument = this ;
619: _standalone = true;
620: _systemId = systemId;
621: }
622:
623: public DocumentTypeImpl(Document owner, String rootElement,
624: boolean standalone, String systemId, String publicId) {
625: super (rootElement);
626: _standalone = standalone;
627: _systemId = systemId;
628: _publicId = publicId;
629: }
630:
631: public DocumentTypeImpl() {
632: super ();
633: }
634:
635: public void init(String systemId) {
636: _ownerDocument = this ;
637: _standalone = true;
638: _systemId = systemId;
639: }
640:
641: /**
642: * Named node map provides access to an underlying hashtable that holds
643: * all the entities related with this DTD.
644: */
645: private NamedNodeMapProxy _entities;
646:
647: /**
648: * Named node map provides access to an underlying hashtable that holds
649: * all the notations related with this DTD.
650: */
651: private NamedNodeMapProxy _notations;
652:
653: /**
654: * The system identifier of this entity, if specified.
655: */
656: private String _systemId;
657:
658: /**
659: * The public identifier of this entity, if specified.
660: */
661: private String _publicId;
662:
663: /**
664: * True if the document type has been declared as standalone. Allows the
665: * document to be delivered with its DTD and no external subset.
666: */
667: private boolean _standalone;
668:
669: /**
670: * Named node map provides access to an underlying hashtable that holds
671: * all the parameter entities related with this DTD.
672: */
673: private Hashtable _params;
674:
675: /**
676: * Named node map provides access to an underlying hashtable that holds
677: * all the element definitions related with this DTD.
678: */
679: // private Hashtable _elements;
680:
681: /**
682: * Named node map provides access to an underlying hashtable that holds
683: * all the attribute definitions related with this DTD.
684: */
685: // private Hashtable _attributes;
686: }
|