CoreChildNodeSupport.aj

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.axiom.core;

import org.apache.axiom.om.NodeUnavailableException;
import org.apache.axiom.om.OMException;
import org.apache.axiom.om.impl.builder.StAXBuilder;

public aspect CoreChildNodeSupport {
    private CoreParentNode CoreChildNode.owner;
    CoreChildNode CoreChildNode.nextSibling;
    CoreChildNode CoreChildNode.previousSibling;
    
    /**
     * Check if this node has a parent.
     * 
     * @return <code>true</code> if and only if this node currently has a parent
     */
    public final boolean CoreChildNode.coreHasParent() {
        return getFlag(Flags.HAS_PARENT);
    }
    
    /**
     * Get the parent of this node.
     * 
     * @return the parent of this node or <code>null</code> if this node doesn't have a parent
     */
    public final CoreParentNode CoreChildNode.coreGetParent() {
        return getFlag(Flags.HAS_PARENT) ? owner : null;
    }
    
    public final CoreElement CoreChildNode.coreGetParentElement() {
        return owner instanceof CoreElement ? (CoreElement)owner : null;
    }
    
    public void CoreChildNode.internalSetParent(CoreParentNode parent) {
        if (parent == null) {
            throw new IllegalArgumentException();
        }
        owner = parent;
        setFlag(Flags.HAS_PARENT, true);
    }
    
    public final void CoreChildNode.internalUnsetParent(CoreDocument newOwnerDocument) {
        owner = newOwnerDocument;
        setFlag(Flags.HAS_PARENT, false);
    }
    
    public final CoreNode CoreChildNode.getRootOrOwnerDocument() {
        if (owner == null) {
            return this;
        } else {
            return owner.getRootOrOwnerDocument();
        }
    }
    
    public final void CoreChildNode.coreSetOwnerDocument(CoreDocument document) {
        if (getFlag(Flags.HAS_PARENT)) {
            throw new IllegalStateException();
        }
        owner = document;
    }
    
    public final CoreChildNode CoreChildNode.coreGetNextSiblingIfAvailable() {
        return nextSibling;
    }

    public final void CoreChildNode.coreSetNextSibling(CoreChildNode nextSibling) {
        this.nextSibling = nextSibling;
    }
    
    public final CoreChildNode CoreChildNode.coreGetPreviousSibling() {
        return previousSibling;
    }
    
    public final CoreChildNode CoreChildNode.coreGetPreviousSibling(NodeFilter filter) {
        CoreChildNode sibling = coreGetPreviousSibling();
        while (sibling != null && !filter.accept(sibling)) {
            sibling = sibling.coreGetPreviousSibling();
        }
        return sibling;
    }
    
    public final void CoreChildNode.coreSetPreviousSibling(CoreChildNode previousSibling) {
        this.previousSibling = previousSibling;
    }
    
    public final CoreChildNode CoreChildNode.coreGetNextSibling() throws OMException {
        CoreChildNode nextSibling = coreGetNextSiblingIfAvailable();
        if (nextSibling == null) {
            CoreParentNode parent = coreGetParent();
            if (parent != null && parent.getBuilder() != null) {
                switch (parent.getState()) {
                    case CoreParentNode.DISCARDED:
                        ((StAXBuilder)parent.getBuilder()).debugDiscarded(parent);
                        throw new NodeUnavailableException();
                    case CoreParentNode.INCOMPLETE:
                        do {
                            parent.buildNext();
                        } while (parent.getState() == CoreParentNode.INCOMPLETE
                                && (nextSibling = coreGetNextSiblingIfAvailable()) == null);
                }
            }
        }
        return nextSibling;
    }

    public final CoreChildNode CoreChildNode.coreGetNextSibling(NodeFilter filter) {
        CoreChildNode sibling = coreGetNextSibling();
        while (sibling != null && !filter.accept(sibling)) {
            sibling = sibling.coreGetNextSibling();
        }
        return sibling;
    }
    
    public final void CoreChildNode.coreInsertSiblingAfter(CoreChildNode sibling) {
        CoreParentNode parent = coreGetParent();
        // TODO: don't use OMException here
        if (parent == null) {
            throw new OMException("Parent can not be null");
        } else if (this == sibling) {
            throw new OMException("Inserting self as the sibling is not allowed");
        }
        sibling.internalDetach(null, parent);
        CoreChildNode nextSibling = coreGetNextSibling();
        sibling.previousSibling = this;
        if (nextSibling == null) {
            parent.getContent(true).lastChild = sibling;
        } else {
            nextSibling.previousSibling = sibling;
        }
        sibling.nextSibling = nextSibling;
        this.nextSibling = sibling;
    }
    
    public final void CoreChildNode.coreInsertSiblingBefore(CoreChildNode sibling) {
        CoreParentNode parent = coreGetParent();
        // TODO: don't use OMException here
        if (parent == null) {
            throw new OMException("Parent can not be null");
        } else if (this == sibling) {
            throw new OMException("Inserting self as the sibling is not allowed");
        }
        sibling.internalDetach(null, parent);
        sibling.nextSibling = this;
        if (previousSibling == null) {
            parent.getContent(true).firstChild = sibling;
        } else {
            previousSibling.nextSibling = sibling;
        }
        sibling.previousSibling = previousSibling;
        previousSibling = sibling;
    }
    
    public final void CoreChildNode.coreInsertSiblingsBefore(CoreDocumentFragment fragment) {
        Content fragmentContent = fragment.getContent(false);
        if (fragmentContent == null || fragmentContent.firstChild == null) {
            // Fragment is empty; nothing to do
            return;
        }
        CoreParentNode parent = coreGetParent();
        // TODO: check parent != null
        CoreChildNode child = fragmentContent.firstChild;
        while (child != null) {
            child.internalSetParent(parent);
            child = child.nextSibling;
        }
        fragmentContent.lastChild.nextSibling = this;
        if (previousSibling == null) {
            parent.getContent(true).firstChild = fragmentContent.firstChild;
        } else {
            previousSibling.nextSibling = fragmentContent.firstChild;
        }
        fragmentContent.firstChild.previousSibling = previousSibling;
        previousSibling = fragmentContent.lastChild;
        fragmentContent.firstChild = null;
        fragmentContent.lastChild = null;
    }
    
    void CoreChildNode.beforeDetach() {}
    
    public final void CoreChildNode.coreDetach(Semantics semantics) {
        internalDetach(semantics, null);
    }
    
    final void CoreChildNode.internalDetach(Semantics semantics, CoreParentNode newParent) {
        CoreParentNode parent = coreGetParent();
        if (parent != null) {
            beforeDetach();
            if (previousSibling == null) {
                parent.getContent(true).firstChild = nextSibling;
            } else {
                previousSibling.nextSibling = nextSibling;
            }
            if (nextSibling == null) {
                parent.getContent(true).lastChild = previousSibling;
            } else {
                nextSibling.previousSibling = previousSibling;
            }
            nextSibling = null;
            previousSibling = null;
            if (newParent == null) {
                internalUnsetParent(semantics.getDetachPolicy().getNewOwnerDocument(parent));
            }
        }
        if (newParent != null) {
            internalSetParent(newParent);
        }
    }

    public final void CoreChildNode.coreReplaceWith(CoreChildNode newNode, Semantics semantics) {
        if (newNode == this) {
            return;
        }
        CoreParentNode parent = coreGetParent();
        if (parent != null) {
            newNode.internalDetach(null, parent);
            beforeDetach();
            if (previousSibling == null) {
                parent.getContent(true).firstChild = newNode;
            } else {
                previousSibling.nextSibling = newNode;
                newNode.previousSibling = previousSibling;
                previousSibling = null;
            }
            if (nextSibling == null) {
                parent.getContent(true).lastChild = newNode;
            } else {
                nextSibling.previousSibling = newNode;
                newNode.nextSibling = nextSibling;
                nextSibling = null;
            }
            internalUnsetParent(semantics.getDetachPolicy().getNewOwnerDocument(parent));
        }
    }

    public final <T> CoreNode CoreChildNode.coreClone(ClonePolicy<T> policy, T options, CoreParentNode targetParent) {
        return internalClone(policy, options, targetParent);
    }
}