001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.xml;
030:
031: import com.caucho.xpath.pattern.NodeListIterator;
032:
033: import org.w3c.dom.DOMException;
034: import org.w3c.dom.NamedNodeMap;
035: import org.w3c.dom.Node;
036: import org.w3c.dom.NodeList;
037:
038: import java.util.Iterator;
039:
040: /**
041: * QNode represents any node that can have children.
042: */
043: public abstract class QNode extends QAbstractNode {
044: protected QAbstractNode _firstChild;
045: protected QAbstractNode _lastChild;
046:
047: protected QNode() {
048: }
049:
050: protected QNode(QDocument owner) {
051: super (owner);
052: }
053:
054: public String getNodeValue() {
055: return null;
056: }
057:
058: public void setNodeValue(String value) {
059: }
060:
061: /**
062: * Returns a node list of the children.
063: */
064: public NodeList getChildNodes() {
065: return new ChildNodeList();
066: }
067:
068: public Node getFirstChild() {
069: return _firstChild;
070: }
071:
072: public Node getLastChild() {
073: return _lastChild;
074: }
075:
076: public Node getPreviousSibling() {
077: return _previous;
078: }
079:
080: public Node getNextSibling() {
081: return _next;
082: }
083:
084: public NamedNodeMap getAttributes() {
085: return null;
086: }
087:
088: public Node insertBefore(Node newChild, Node refChild)
089: throws DOMException {
090: QAbstractNode qNewChild = (QAbstractNode) newChild;
091: QAbstractNode qRefChild = (QAbstractNode) refChild;
092:
093: if (qNewChild._owner != _owner && qNewChild._owner != this )
094: throw new QDOMException(DOMException.WRONG_DOCUMENT_ERR,
095: "insertBefore new child from wrong document");
096:
097: qNewChild.remove();
098:
099: if (qRefChild != null && qRefChild._parent != this )
100: throw new QDOMException(DOMException.NOT_FOUND_ERR,
101: "insertBefore has no such child");
102:
103: if (qNewChild instanceof QDocumentFragment) {
104: QDocumentFragment frag = (QDocumentFragment) qNewChild;
105: QAbstractNode first = frag._firstChild;
106: QAbstractNode next = null;
107: for (QAbstractNode ptr = first; ptr != null; ptr = next) {
108: next = ptr._next;
109: insertBefore(ptr, refChild);
110: }
111:
112: return first;
113: }
114:
115: qNewChild._parent = this ;
116:
117: if (refChild == null) {
118: if (_firstChild == null) {
119: qNewChild._previous = null;
120: qNewChild._next = null;
121: _firstChild = _lastChild = qNewChild;
122: } else {
123: _lastChild._next = qNewChild;
124: qNewChild._previous = _lastChild;
125: _lastChild = qNewChild;
126: qNewChild._next = null;
127: }
128:
129: return qNewChild;
130: }
131:
132: qNewChild._previous = qRefChild._previous;
133: qNewChild._next = qRefChild;
134: if (qRefChild._previous == null)
135: _firstChild = qNewChild;
136: else
137: qRefChild._previous._next = qNewChild;
138: qRefChild._previous = qNewChild;
139:
140: return qNewChild;
141: }
142:
143: public Node replaceChild(Node newChild, Node refChild)
144: throws DOMException {
145: QAbstractNode qNewChild = (QAbstractNode) newChild;
146: QAbstractNode qRefChild = (QAbstractNode) refChild;
147:
148: if (qRefChild == null || qRefChild._parent != this )
149: throw new QDOMException(DOMException.NOT_FOUND_ERR,
150: "ref is not child");
151:
152: if (qNewChild == null || qNewChild._owner != _owner)
153: throw new QDOMException(DOMException.WRONG_DOCUMENT_ERR,
154: "wrong document");
155:
156: if (_owner != null)
157: _owner._changeCount++;
158:
159: qNewChild._previous = qRefChild._previous;
160: qNewChild._next = qRefChild._next;
161: qNewChild._parent = this ;
162:
163: if (qNewChild._previous == null)
164: _firstChild = qNewChild;
165: else
166: qNewChild._previous._next = qNewChild;
167:
168: if (qNewChild._next == null)
169: _lastChild = qNewChild;
170: else
171: qNewChild._next._previous = qNewChild;
172:
173: qRefChild._previous = null;
174: qRefChild._next = null;
175: qRefChild._parent = null;
176:
177: return qRefChild;
178: }
179:
180: public Node removeChild(Node oldChild) throws DOMException {
181: QAbstractNode qOldChild = (QAbstractNode) oldChild;
182:
183: if (qOldChild != null && qOldChild._parent != this ) {
184: throw new QDOMException(DOMException.NOT_FOUND_ERR,
185: "removeChild has no such child");
186: }
187:
188: if (_owner != null)
189: _owner._changeCount++;
190:
191: if (qOldChild._previous == null)
192: _firstChild = qOldChild._next;
193: else
194: qOldChild._previous._next = qOldChild._next;
195:
196: if (qOldChild._next == null)
197: _lastChild = qOldChild._previous;
198: else
199: qOldChild._next._previous = qOldChild._previous;
200:
201: qOldChild._parent = null;
202: qOldChild._next = null;
203: qOldChild._previous = null;
204:
205: return qOldChild;
206: }
207:
208: private static void setOwner(QAbstractNode node, QDocument owner) {
209: if (node._owner == null) {
210: node._owner = owner;
211:
212: String namespace = node.getNamespaceURI();
213:
214: if (namespace != "")
215: owner.addNamespace(node.getPrefix(), namespace);
216:
217: for (QAbstractNode child = (QAbstractNode) node
218: .getFirstChild(); child != null; child = (QAbstractNode) child
219: .getNextSibling()) {
220: setOwner(child, owner);
221: }
222: }
223: }
224:
225: public Node appendChild(Node newNode) throws DOMException {
226: QAbstractNode qNewNode = (QAbstractNode) newNode;
227:
228: setOwner(qNewNode, _owner);
229:
230: if (qNewNode._owner != _owner && qNewNode._owner != this ) {
231: throw new QDOMException(DOMException.WRONG_DOCUMENT_ERR,
232: "can't appendChild from different document");
233: }
234:
235: qNewNode.remove();
236:
237: if (qNewNode instanceof QDocumentFragment) {
238: QDocumentFragment frag = (QDocumentFragment) qNewNode;
239: QAbstractNode first = frag._firstChild;
240: QAbstractNode next = null;
241: for (QAbstractNode ptr = first; ptr != null; ptr = next) {
242: next = ptr._next;
243: appendChild(ptr);
244: }
245:
246: return first;
247: }
248:
249: qNewNode._parent = this ;
250: qNewNode._next = null;
251: qNewNode._previous = _lastChild;
252: if (_lastChild == null) {
253: _lastChild = qNewNode;
254: _firstChild = qNewNode;
255: } else {
256: _lastChild._next = qNewNode;
257: _lastChild = qNewNode;
258: }
259:
260: return qNewNode;
261: }
262:
263: public boolean hasChildNodes() {
264: return _firstChild != null;
265: }
266:
267: public void setTextContent(String content) {
268: QText text = new QText(content);
269: text._owner = _owner;
270:
271: _firstChild = _lastChild = text;
272: }
273:
274: public void normalize() {
275: }
276:
277: public boolean checkValid() throws Exception {
278: if (!super .checkValid())
279: throw new Exception("super bad: " + this );
280:
281: if (_firstChild != null && _firstChild._previous != null)
282: throw new Exception("first child bad: " + this );
283:
284: if (_lastChild != null && _lastChild._next != null)
285: throw new Exception("last child bad:" + this );
286:
287: QAbstractNode ptr = _firstChild;
288: for (; ptr != null; ptr = ptr._next) {
289: if (ptr._parent != this )
290: throw new Exception("child parent bad:" + this + " "
291: + ptr);
292: if (ptr._owner != _owner && ptr._owner != this )
293: throw new Exception("child owner bad:" + this + " "
294: + ptr + " " + ptr._owner + " " + _owner);
295: if (ptr._next != null && ptr._next._previous != ptr)
296: throw new Exception("child links bad:" + this + " "
297: + ptr);
298: }
299:
300: ptr = _lastChild;
301: for (; ptr != null; ptr = ptr._previous) {
302: if (ptr._parent != this )
303: throw new Exception("child parent bad:" + this + " "
304: + ptr);
305: if (ptr._owner != _owner && ptr._owner != this )
306: throw new Exception("child owner bad:" + this + " "
307: + ptr);
308: if (ptr._previous != null && ptr._previous._next != ptr)
309: throw new Exception("child links bad:" + this + " "
310: + ptr);
311: }
312:
313: return true;
314: }
315:
316: public QAbstractNode getNextPreorder() {
317: if (_firstChild != null)
318: return _firstChild;
319: else if (_next != null)
320: return _next;
321:
322: for (QNode ptr = _parent; ptr != null; ptr = ptr._parent) {
323: if (ptr._next != null)
324: return ptr._next;
325: }
326:
327: return null;
328: }
329:
330: public boolean equals(Object arg) {
331: return this == arg;
332: }
333:
334: public boolean equals(Node arg, boolean deep) {
335: return this == arg;
336: }
337:
338: // NodeList methods
339:
340: public class ChildNodeList implements NodeList {
341: /**
342: * Returns the child with the given index.
343: */
344: public Node item(int index) {
345: QAbstractNode ptr = _firstChild;
346: for (; ptr != null && index > 0; index--) {
347: ptr = ptr._next;
348: }
349:
350: return ptr;
351: }
352:
353: /**
354: * Returns the number of children.
355: */
356: public int getLength() {
357: int index = 0;
358: for (QAbstractNode ptr = _firstChild; ptr != null; ptr = ptr._next)
359: index++;
360:
361: return index;
362: }
363:
364: // for quercus
365: public Iterator<Node> iterator() {
366: return new NodeListIterator(null, this);
367: }
368: }
369: }
|