Package org.exist.dom

Source Code of org.exist.dom.StoredNode$PreviousSiblingVisitor

/*
* eXist Open Source Native XML Database
* Copyright (C) 2000-2007 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*  $Id$
*/
package org.exist.dom;

import java.io.IOException;
import java.util.Iterator;

import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;

import org.exist.EXistException;
import org.exist.numbering.NodeId;
import org.exist.stax.EmbeddedXMLStreamReader;
import org.exist.stax.ExtendedXMLStreamReader;
import org.exist.storage.DBBroker;
import org.exist.storage.NodePath;
import org.exist.storage.Signatures;
import org.exist.util.pool.NodePool;
import org.exist.xquery.Constants;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
*  The base class for all persistent DOM nodes in the database.
*
*@author     Wolfgang Meier <meier@ifs.tu-darmstadt.de>
*/
public class StoredNode extends NodeImpl implements Visitable, NodeHandle {

    public final static int LENGTH_SIGNATURE_LENGTH = 1; //sizeof byte
    public final static long UNKNOWN_NODE_IMPL_ADDRESS = -1;

    protected NodeId nodeId = null;

    protected DocumentImpl ownerDocument = null;

    private long internalAddress = UNKNOWN_NODE_IMPL_ADDRESS;

    private short nodeType = NodeProxy.UNKNOWN_NODE_TYPE;

    /**
     * Creates a new <code>StoredNode</code> instance.
     *
     * @param nodeType a <code>short</code> value
     */
    public StoredNode(short nodeType) {
        this.nodeType = nodeType;
    }

    /**
     * Creates a new <code>StoredNode</code> instance.
     *
     * @param nodeType a <code>short</code> value
     * @param nodeId a <code>NodeId</code> value
     */
    public StoredNode(short nodeType, NodeId nodeId) {
        this.nodeType = nodeType;
        this.nodeId = nodeId;
    }

    /**
     * Copy constructor: creates a copy of the other node.
     *
     * @param other a <code>StoredNode</code> value
     */
    public StoredNode(StoredNode other) {
        this.nodeType = other.nodeType;
        this.nodeId = other.nodeId;
        this.internalAddress = other.internalAddress;
        this.ownerDocument = other.ownerDocument;
    }

    /**
     * Creates a new <code>StoredNode</code> instance.
     *
     * @param other a <code>NodeProxy</code> value
     */
    public StoredNode(NodeProxy other) {
        this.ownerDocument = other.getDocument();
        this.nodeType = other.getNodeType();
        this.nodeId = other.getNodeId();     
        this.internalAddress = other.getInternalAddress();
    }

    /**
     * Reset this object to its initial state. Required by the
     * parser to be able to reuse node objects.
     */
    public void clear() {
        this.nodeId = null;
        this.internalAddress = UNKNOWN_NODE_IMPL_ADDRESS;
    }

    public byte[] serialize() {
        throw new DOMException(DOMException.INVALID_ACCESS_ERR, "Can't serialize " + getClass().getName());
    }

    /**
     * Read a node from the specified byte array.
     *
     * This checks the node type and calls the {@link #deserialize(byte[], int, int,DocumentImpl,boolean)}
     * method of the corresponding node class.
     *
     * @param data
     * @param start
     * @param len
     * @param doc
     */
    public static StoredNode deserialize(byte[] data, int start, int len, DocumentImpl doc) {
        return deserialize(data, start, len, doc, false);
    }

    /**
     * Read a node from the specified byte array.
     *
     * This checks the node type and calls the {@link #deserialize(byte[], int, int, DocumentImpl, boolean)}
     * method of the corresponding node class. The node will be allocated in the pool
     * and should be released once it is no longer needed.
     *
     * @param data
     * @param start
     * @param len
     * @param doc
     */
    public static StoredNode deserialize(byte[] data, int start, int len, DocumentImpl doc, boolean pooled) {
            final short type = Signatures.getType(data[start]);
        switch (type) {
        case Node.TEXT_NODE :
            return TextImpl.deserialize(data, start, len, doc, pooled);
        case Node.ELEMENT_NODE :
            return ElementImpl.deserialize(data, start, len, doc, pooled);
        case Node.ATTRIBUTE_NODE :
            return AttrImpl.deserialize(data, start, len, doc, pooled);
        case Node.PROCESSING_INSTRUCTION_NODE :
            return ProcessingInstructionImpl.deserialize(data, start, len, doc, pooled);
        case Node.COMMENT_NODE :
            return CommentImpl.deserialize(data, start, len, doc, pooled);
        case Node.CDATA_SECTION_NODE :
            return CDATASectionImpl.deserialize(data, start, len, doc, pooled);
        default :
            LOG.error("Unknown node type: " + type);
            Thread.dumpStack();
            return null;
        }
    }

    public QName getQName() {
        switch(getNodeType()) {
        case Node.DOCUMENT_NODE:
            return QName.DOCUMENT_QNAME;
        case Node.TEXT_NODE:
            return QName.TEXT_QNAME;
        case Node.COMMENT_NODE:
            return QName.COMMENT_QNAME;
        case Node.DOCUMENT_TYPE_NODE:
            return QName.DOCTYPE_QNAME;
        default:
            LOG.error("Unknown node type: " + getNodeType());
            return null;
        }
    }

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof StoredNode))
            {return false;}
        return ((StoredNode)obj).nodeId.equals(nodeId);
    }

    /**
     * The method <code>setNodeId</code>
     *
     * @param dln a <code>NodeId</code> value
     */
    public void setNodeId(NodeId dln) {
        this.nodeId = dln;
    }

    /**
     * The method <code>getNodeId</code>
     *
     * @return a <code>NodeId</code> value
     */
    public NodeId getNodeId() {
        return nodeId;
    }

    /**
     *  Get the internal storage address of this node
     *
     *@return    The internalAddress value
     */
    public long getInternalAddress() {
        return internalAddress;
    }

    /**
     *  Set the internal storage address of this node.
     *
     *@param  internalAddress  The new internalAddress value
     */
    public void setInternalAddress(long internalAddress) {
        this.internalAddress = internalAddress;
    }

    /**
     * Returns true if the node was modified recently and nodes
     * were inserted at the start or in the middle of its children.
     *
     * @return TRUE when node is 'dirty'
     */
    public boolean isDirty() {
        return true;
    }

    public void setDirty(boolean dirty) {
        //Nothing to do
    }

    /**
     * @see org.w3c.dom.Node#getNodeType()
     */
    public short getNodeType() {
        return this.nodeType;
    }

    /**
     * @see org.w3c.dom.Node#getOwnerDocument()
     */
    public Document getOwnerDocument() {
        return ownerDocument;
    }

    public DocumentImpl getDocument() {
        return ownerDocument;
    }

    public DocumentAtExist getDocumentAtExist() {
        return ownerDocument;
    }

    /**
     *  Set the owner document.
     *
     *@param  ownerDocument  The new ownerDocument value
     */
    public void setOwnerDocument(DocumentImpl ownerDocument) {
        this.ownerDocument = ownerDocument;
    }

    public int getDocId() {
        return ownerDocument.getDocId();
    }

    /**
     * @see org.w3c.dom.Node#getParentNode()
     */
    public Node getParentNode() {
        final NodeId parentId = nodeId.getParentId();
        if (parentId == NodeId.DOCUMENT_NODE)
            {return ownerDocument;}
        // Filter out the temporary nodes wrapper element
        if (parentId.getTreeLevel() == 1 && ((DocumentImpl)getOwnerDocument()).getCollection().isTempCollection())
            {return ownerDocument;}
        return ownerDocument.getNode(parentId);
    }

    public StoredNode getParentStoredNode() {
        final Node parent = getParentNode();
        return parent instanceof StoredNode ? (StoredNode) parent : null;
    }

    /**
     * @see org.w3c.dom.Node#getPreviousSibling()
     */
    public Node getPreviousSibling() {
        final StoredNode parent = getParentStoredNode();
        if (parent == null) {return null;}
        if (parent.isDirty()) {
            DBBroker broker = null;
            try {
                broker = ownerDocument.getBrokerPool().get(null);
                final EmbeddedXMLStreamReader reader = broker.getXMLStreamReader(parent, true);
                final int level = nodeId.getTreeLevel();
                StoredNode last = null;
                while (reader.hasNext()) {
                    final int status = reader.next();
                    final NodeId currentId = (NodeId) reader.getProperty(ExtendedXMLStreamReader.PROPERTY_NODE_ID);
                    if (status != XMLStreamConstants.END_ELEMENT && currentId.getTreeLevel() == level) {
                        if (currentId.equals(nodeId))
                            {return last;}
                        last = reader.getNode();
                    }
                }
            } catch (final IOException e) {
                LOG.error("Internal error while reading child nodes: " + e.getMessage(), e);
                //TODO : throw exception -pb
            } catch (final XMLStreamException e) {
                LOG.error("Internal error while reading child nodes: " + e.getMessage(), e);
              //TODO : throw exception -pb
            } catch (final EXistException e) {
                LOG.error("Internal error while reading child nodes: " + e.getMessage(), e);
              //TODO : throw exception -pb
            } finally {
                ownerDocument.getBrokerPool().release(broker);
            }
            return null;
        }
        final NodeId firstChild = parent.getNodeId().newChild();
        if (nodeId.equals(firstChild))
            {return null;}
        final NodeId siblingId = nodeId.precedingSibling();
        return ownerDocument.getNode(siblingId);
    }

    /**
     * @see org.w3c.dom.Node#getNextSibling()
     */
    public Node getNextSibling() {
        if (nodeId.getTreeLevel() == 2 && ((DocumentImpl)getOwnerDocument()).getCollection().isTempCollection())
            {return null;}
        final StoredNode parent = getParentStoredNode();
        if (parent == null) {return null;}
        if (parent.isDirty()) {
            DBBroker broker = null;
            try {
                broker = ownerDocument.getBrokerPool().get(null);
                final EmbeddedXMLStreamReader reader = broker.getXMLStreamReader(parent, true);
                final int level = nodeId.getTreeLevel();
                while (reader.hasNext()) {
                    final int status = reader.next();
                    final NodeId currentId = (NodeId) reader.getProperty(ExtendedXMLStreamReader.PROPERTY_NODE_ID);
                    if (status != XMLStreamConstants.END_ELEMENT && currentId.getTreeLevel() == level) {
                        if (currentId.compareTo(nodeId) > 0)
                            {return reader.getNode();}
                    }
                }
            } catch (final IOException e) {
                LOG.error("Internal error while reading child nodes: " + e.getMessage(), e);
                //TODO : throw exception -pb
            } catch (final XMLStreamException e) {
                LOG.error("Internal error while reading child nodes: " + e.getMessage(), e);
              //TODO : throw exception -pb
            } catch (final EXistException e) {
                LOG.error("Internal error while reading child nodes: " + e.getMessage(), e);
              //TODO : throw exception -pb
            } finally {
                ownerDocument.getBrokerPool().release(broker);
            }
            return null;
        }
        final NodeId siblingId = nodeId.nextSibling();
        return ownerDocument.getNode(siblingId);
    }

    protected StoredNode getLastNode(StoredNode node) {
        if (!node.hasChildNodes())
            {return node;}
        DBBroker broker = null;
        try {
            broker = ownerDocument.getBrokerPool().get(null);
            final EmbeddedXMLStreamReader reader = broker.getXMLStreamReader(node, true);
            while (reader.hasNext()) {
                reader.next();
            }
            return reader.getPreviousNode();
        } catch (final IOException e) {
            LOG.error("Internal error while reading child nodes: " + e.getMessage(), e);
          //TODO : throw exception -pb
        } catch (final XMLStreamException e) {
            LOG.error("Internal error while reading child nodes: " + e.getMessage(), e);
          //TODO : throw exception -pb
        } catch (final EXistException e) {
            LOG.error("Internal error while reading child nodes: " + e.getMessage(), e);
          //TODO : throw exception -pb
        } finally {
            ownerDocument.getBrokerPool().release(broker);
        }
        return null;
    }

    protected StoredNode getLastNode(Iterator<StoredNode> iterator, StoredNode node) {
        if (!node.hasChildNodes())
            {return node;}
        final int children = node.getChildCount();
        StoredNode next = null;
        for (int i = 0; i < children; i++) {
            next = iterator.next();
            //Recursivity helps taversing...
            next = getLastNode(iterator, next);
        }
        return next;
    }

    public NodePath getPath() {
        final NodePath path = new NodePath();
        if (getNodeType() == Node.ELEMENT_NODE)
            {path.addComponent(getQName());}
        NodeImpl parent = (NodeImpl)getParentNode();
        while (parent != null && parent.getNodeType() != Node.DOCUMENT_NODE) {
            path.addComponentAtStart(parent.getQName());
            parent = (NodeImpl)parent.getParentNode();
        }
        return path;
    }

    public NodePath getPath(NodePath parentPath) {
        if (getNodeType() == Node.ELEMENT_NODE)
            {parentPath.addComponent(getQName());}
        return parentPath;
    }

    @Override
    public String toString() {
        final StringBuilder buf = new StringBuilder();
        buf.append(nodeId.toString());
        buf.append('\t');
        buf.append(getQName());
        return buf.toString();
    }

    public String toString(boolean top) {
        return toString();
    }

    /**
     * Release all memory resources hold by this node.
     */
    public void release() {
        ownerDocument = null;
        clear();
        NodePool.getInstance().returnNode(this);
    }

    public boolean accept(NodeVisitor visitor) {
        DBBroker broker = null;
        try {
            broker = ownerDocument.getBrokerPool().get(null);
            final Iterator<StoredNode> iterator = broker.getNodeIterator(this);
            iterator.next();
            return accept(iterator, visitor);
        } catch (final EXistException e) {
            LOG.error("Exception while reading node: " + e.getMessage(), e);
            //TODO : throw exception -pb
        } finally {
            ownerDocument.getBrokerPool().release(broker);
        }
        return false;
    }

    public boolean accept(Iterator<StoredNode> iterator, NodeVisitor visitor) {
        return visitor.visit(this);
    }

    public int getNodeNumber() {
        return 0; //TODO: find a value for node number
    }

    @Deprecated
    private final static class PreviousSiblingVisitor implements NodeVisitor {

        private StoredNode current;
        private StoredNode last = null;
       
        public PreviousSiblingVisitor(StoredNode current) {
            this.current = current;
        }

        public boolean visit(StoredNode node) {
            if (node.nodeId.equals(current.nodeId))
                {return false;}
            if (node.nodeId.getTreeLevel() == current.nodeId.getTreeLevel())
                {last = node;}
            return true;
        }
    }

    @Override
    public int compareTo(Object other) {
        if( !(other instanceof StoredNode)) {
            return(Constants.INFERIOR);
        }
        final StoredNode n = (StoredNode)other;
        if(n.ownerDocument == ownerDocument) {
            return nodeId.compareTo(n.nodeId);
        } else if(ownerDocument.getDocId() < n.ownerDocument.getDocId()) {
            return(Constants.INFERIOR);
        } else {
            return(Constants.SUPERIOR);
        }
    }
}
TOP

Related Classes of org.exist.dom.StoredNode$PreviousSiblingVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.