Package org.apache.jackrabbit.core.version

Source Code of org.apache.jackrabbit.core.version.NodeStateEx

/*
* 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.jackrabbit.core.version;

import org.apache.jackrabbit.core.NodeId;
import org.apache.jackrabbit.core.PropertyId;
import org.apache.jackrabbit.core.PropertyImpl;
import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
import org.apache.jackrabbit.core.nodetype.NodeDef;
import org.apache.jackrabbit.core.nodetype.NodeTypeConflictException;
import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
import org.apache.jackrabbit.core.nodetype.PropDef;
import org.apache.jackrabbit.core.state.ItemState;
import org.apache.jackrabbit.core.state.ItemStateException;
import org.apache.jackrabbit.core.state.NodeState;
import org.apache.jackrabbit.core.state.PropertyState;
import org.apache.jackrabbit.core.state.UpdatableItemStateManager;
import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.name.QName;
import org.apache.jackrabbit.uuid.UUID;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.jcr.RepositoryException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.NoSuchNodeTypeException;

/**
* This Class provides some basic node operations directly on the node state.
*/
public class NodeStateEx {

    /**
     * the underlying persistent state
     */
    private NodeState nodeState;

    /**
     * the state manager
     */
    private final UpdatableItemStateManager stateMgr;

    /**
     * the node type registry for resolving item defs
     */
    private final NodeTypeRegistry ntReg;

    /**
     * the cached name
     */
    private QName name;

    /**
     * Creates a new persistent node
     *
     * @param stateMgr
     * @param nodeState
     */
    public NodeStateEx(UpdatableItemStateManager stateMgr,
                       NodeTypeRegistry ntReg,
                       NodeState nodeState, QName name) {
        this.nodeState = nodeState;
        this.ntReg = ntReg;
        this.stateMgr = stateMgr;
        this.name = name;
    }


    /**
     * returns the name of this node
     *
     * @return the name of this node
     */
    public QName getName() {
        if (name == null) {
            try {
                NodeId parentId = nodeState.getParentId();
                NodeState parent = (NodeState) stateMgr.getItemState(parentId);
                name = parent.getChildNodeEntry(nodeState.getNodeId()).getName();
            } catch (ItemStateException e) {
                // should never occurr
                throw new IllegalStateException(e.toString());
            }
        }
        return name;
    }

    /**
     * Returns the id of this node.
     *
     * @return the id of this node.
     */
    public NodeId getNodeId() {
        return nodeState.getNodeId();
    }

    /**
     * Returns the parent id of this node
     *
     * @return the parent id of this node
     */
    public NodeId getParentId() {
        return nodeState.getParentId();
    }

    /**
     * Returns the underlaying node state.
     * @return the underlaying node state.
     */
    public NodeState getState() {
        return nodeState;
    }

    /**
     * Returns the properties of this node
     *
     * @return the properties of this node
     */
    public PropertyState[] getProperties() throws ItemStateException {
        Set set = nodeState.getPropertyNames();
        PropertyState[] props = new PropertyState[set.size()];
        int i = 0;
        for (Iterator iter = set.iterator(); iter.hasNext();) {
            QName propName = (QName) iter.next();
            PropertyId propId = new PropertyId(nodeState.getNodeId(), propName);
            props[i++] = (PropertyState) stateMgr.getItemState(propId);
        }
        return props;
    }

    /**
     * Checks if the given property exists
     *
     * @param name
     * @return <code>true</code> if the given property exists.
     */
    public boolean hasProperty(QName name) {
        PropertyId propId = new PropertyId(nodeState.getNodeId(), name);
        return stateMgr.hasItemState(propId);
    }

    /**
     * Returns the values of the given property of <code>null</code>
     *
     * @param name
     * @return the values of the given property.
     */
    public InternalValue[] getPropertyValues(QName name) {
        PropertyId propId = new PropertyId(nodeState.getNodeId(), name);
        try {
            PropertyState ps = (PropertyState) stateMgr.getItemState(propId);
            return ps.getValues();
        } catch (ItemStateException e) {
            return null;
        }
    }

    /**
     * Returns the value of the given property or <code>null</code>
     *
     * @param name
     * @return the value of the given property.
     */
    public InternalValue getPropertyValue(QName name) {
        PropertyId propId = new PropertyId(nodeState.getNodeId(), name);
        try {
            PropertyState ps = (PropertyState) stateMgr.getItemState(propId);
            return ps.getValues()[0];
        } catch (ItemStateException e) {
            return null;
        }
    }

    /**
     * Sets the property value
     *
     * @param name
     * @param value
     * @throws RepositoryException
     */
    public void setPropertyValue(QName name, InternalValue value)
            throws RepositoryException {
        setPropertyValues(name, value.getType(), new InternalValue[]{value}, false);
    }

    /**
     * Sets the property values
     *
     * @param name
     * @param type
     * @param values
     * @throws RepositoryException
     */
    public void setPropertyValues(QName name, int type, InternalValue[] values)
            throws RepositoryException {
        setPropertyValues(name, type, values, true);
    }

    /**
     * Sets the property values
     *
     * @param name
     * @param type
     * @param values
     * @throws RepositoryException
     */
    public void setPropertyValues(QName name, int type, InternalValue[] values, boolean multiple)
            throws RepositoryException {

        PropertyState prop = getOrCreatePropertyState(name, type, multiple);
        prop.setValues(values);
    }


    /**
     * Retrieves or creates a new property state as child property of this node
     *
     * @param name
     * @param type
     * @param multiValued
     * @return the property state
     * @throws RepositoryException
     */
    private PropertyState getOrCreatePropertyState(QName name, int type, boolean multiValued)
            throws RepositoryException {

        PropertyId propId = new PropertyId(nodeState.getNodeId(), name);
        if (stateMgr.hasItemState(propId)) {
            try {
                PropertyState propState = (PropertyState) stateMgr.getItemState(propId);
                // someone calling this method will always alter the property state, so set status to modified
                if (propState.getStatus() == ItemState.STATUS_EXISTING) {
                    propState.setStatus(ItemState.STATUS_EXISTING_MODIFIED);
                }
                // although this is not quite correct, we mark node as modified aswell
                if (nodeState.getStatus() == ItemState.STATUS_EXISTING) {
                    nodeState.setStatus(ItemState.STATUS_EXISTING_MODIFIED);
                }
                return propState;
            } catch (ItemStateException e) {
                throw new RepositoryException("Unable to create property: " + e.toString());
            }
        } else {
            PropertyState propState = stateMgr.createNew(name, nodeState.getNodeId());
            propState.setType(type);
            propState.setMultiValued(multiValued);

            PropDef pd = getEffectiveNodeType().getApplicablePropertyDef(name, type, multiValued);
            propState.setDefinitionId(pd.getId());

            // need to store nodestate
            nodeState.addPropertyName(name);
            if (nodeState.getStatus() == ItemState.STATUS_EXISTING) {
                nodeState.setStatus(ItemState.STATUS_EXISTING_MODIFIED);
            }
            return propState;
        }
    }

    /**
     * Returns the effective (i.e. merged and resolved) node type representation
     * of this node's primary and mixin node types.
     *
     * @return the effective node type
     * @throws RepositoryException
     */
    public EffectiveNodeType getEffectiveNodeType() throws RepositoryException {

        // build effective node type of mixins & primary type
        // existing mixin's
        HashSet set = new HashSet((nodeState).getMixinTypeNames());
        // primary type
        set.add(nodeState.getNodeTypeName());
        try {
            return ntReg.getEffectiveNodeType((QName[]) set.toArray(new QName[set.size()]));
        } catch (NodeTypeConflictException ntce) {
            String msg = "internal error: failed to build effective node type for node " + nodeState.getNodeId();
            throw new RepositoryException(msg, ntce);
        }
    }

    /**
     * checks if the given child node exists.
     *
     * @param name
     * @return <code>true</code> if the given child exists.
     */
    public boolean hasNode(QName name) {
        return nodeState.hasChildNodeEntry(name);
    }

    /**
     * removes the (first) child node with the given name.
     *
     * @param name
     * @return <code>true</code> if the child was removed
     * @throws RepositoryException
     */
    public boolean removeNode(QName name) throws RepositoryException {
        return removeNode(name, 1);
    }

    /**
     * removes the child node with the given name and 1-based index
     *
     * @param name
     * @param index
     * @return <code>true</code> if the child was removed.
     * @throws RepositoryException
     */
    public boolean removeNode(QName name, int index) throws RepositoryException {
        try {
            NodeState.ChildNodeEntry entry = nodeState.getChildNodeEntry(name, index);
            if (entry == null) {
                return false;
            } else {
                removeNode(entry.getId());
                nodeState.removeChildNodeEntry(name, index);
                nodeState.setStatus(ItemState.STATUS_EXISTING_MODIFIED);
                return true;
            }
        } catch (ItemStateException e) {
            throw new RepositoryException(e);
        }
    }

    /**
     * removes recursively the node with the given id
     *
     * @param id
     * @throws ItemStateException
     */
    private void removeNode(NodeId id) throws ItemStateException {
        NodeState state = (NodeState) stateMgr.getItemState(id);

        // remove properties
        Iterator iter = state.getPropertyNames().iterator();
        while (iter.hasNext()) {
            QName name = (QName) iter.next();
            PropertyId propId = new PropertyId(id, name);
            PropertyState propState = (PropertyState) stateMgr.getItemState(propId);
            stateMgr.destroy(propState);
        }
        state.removeAllPropertyNames();

        // remove child nodes
        iter = state.getChildNodeEntries().iterator();
        while (iter.hasNext()) {
            NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) iter.next();
            removeNode(entry.getId());
        }
        state.removeAllChildNodeEntries();

        // destroy the state itself
        stateMgr.destroy(state);
    }

    /**
     * removes the property with the given name
     *
     * @param name
     * @return <code>true</code> if the property was removed.
     * @throws RepositoryException
     */
    public boolean removeProperty(QName name) throws RepositoryException {
        try {
            if (!nodeState.hasPropertyName(name)) {
                return false;
            } else {
                PropertyId propId = new PropertyId(nodeState.getNodeId(), name);
                ItemState state = stateMgr.getItemState(propId);
                stateMgr.destroy(state);
                nodeState.removePropertyName(name);
                nodeState.setStatus(ItemState.STATUS_EXISTING_MODIFIED);
                return true;
            }
        } catch (ItemStateException e) {
            throw new RepositoryException(e);
        }
    }

    /**
     * retrieves the child node with the given name and 1-base index or
     * <code>null</code> if the node does not exist.
     *
     * @param name
     * @param index
     * @return the node state.
     * @throws RepositoryException
     */
    public NodeStateEx getNode(QName name, int index) throws RepositoryException {
        NodeState.ChildNodeEntry entry = nodeState.getChildNodeEntry(name, index);
        if (entry == null) {
            return null;
        }
        try {
            NodeState state = (NodeState) stateMgr.getItemState(entry.getId());
            return new NodeStateEx(stateMgr, ntReg, state, name);
        } catch (ItemStateException e) {
            throw new RepositoryException("Unable to getNode: " + e.toString());
        }
    }

    /**
     * Adds a new child node with the given name
     *
     * @param nodeName
     * @param nodeTypeName
     * @return the node state
     * @throws NoSuchNodeTypeException
     * @throws ConstraintViolationException
     * @throws RepositoryException
     */
    public NodeStateEx addNode(QName nodeName, QName nodeTypeName,
                               NodeId id, boolean referenceable)
            throws NoSuchNodeTypeException, ConstraintViolationException, RepositoryException {

        NodeStateEx node = createChildNode(nodeName, nodeTypeName, id);
        if (referenceable) {
            node.setPropertyValue(QName.JCR_UUID, InternalValue.create(node.getNodeId().getUUID().toString()));
        }
        return node;
    }

    /**
     * creates a new child node
     *
     * @param name
     * @param id
     * @return the newly created node.
     */
    private NodeStateEx createChildNode(QName name, QName nodeTypeName, NodeId id)
            throws RepositoryException {
        NodeId parentId = nodeState.getNodeId();
        // create a new node state
        if (id == null) {
            id = new NodeId(UUID.randomUUID());
        }
        NodeState state = stateMgr.createNew(id, nodeTypeName, parentId);

        NodeDef cnd =
                getEffectiveNodeType().getApplicableChildNodeDef(name, nodeTypeName, ntReg);
        state.setDefinitionId(cnd.getId());

        // create Node instance wrapping new node state
        NodeStateEx node = new NodeStateEx(stateMgr, ntReg, state, name);
        node.setPropertyValue(QName.JCR_PRIMARYTYPE, InternalValue.create(nodeTypeName));

        // add new child node entryn
        nodeState.addChildNodeEntry(name, id);
        if (nodeState.getStatus() == ItemState.STATUS_EXISTING) {
            nodeState.setStatus(ItemState.STATUS_EXISTING_MODIFIED);
        }
        return node;
    }

    /**
     * returns all child nodes
     *
     * @return the child nodes.
     * @throws RepositoryException
     */
    public NodeStateEx[] getChildNodes() throws RepositoryException {
        try {
            List entries = nodeState.getChildNodeEntries();
            NodeStateEx[] children = new NodeStateEx[entries.size()];
            for (int i = 0; i < entries.size(); i++) {
                NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) entries.get(i);
                NodeState state = (NodeState) stateMgr.getItemState(entry.getId());
                children[i] = new NodeStateEx(stateMgr, ntReg, state, entry.getName());
            }
            return children;
        } catch (ItemStateException e) {
            throw new RepositoryException(e);
        }
    }

    /**
     * stores the persistent state recursively
     *
     * @throws RepositoryException
     */
    public void store() throws RepositoryException {
        try {
            store(nodeState);
        } catch (ItemStateException e) {
            throw new RepositoryException(e);
        }
    }

    /**
     * stores the given persistent state recursively
     *
     * @param state
     * @throws ItemStateException
     */
    private void store(NodeState state)
            throws ItemStateException {

        if (state.getStatus() != ItemState.STATUS_EXISTING) {
            // first store all transient properties
            Set props = state.getPropertyNames();
            for (Iterator iter = props.iterator(); iter.hasNext();) {
                QName propName = (QName) iter.next();
                PropertyState pstate = (PropertyState) stateMgr.getItemState(
                        new PropertyId(state.getNodeId(), propName));
                if (pstate.getStatus() != ItemState.STATUS_EXISTING) {
                    stateMgr.store(pstate);
                }
            }
            // now store all child node entries
            List nodes = state.getChildNodeEntries();
            for (int i = 0; i < nodes.size(); i++) {
                NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) nodes.get(i);
                NodeState nstate = (NodeState) stateMgr.getItemState(entry.getId());
                store(nstate);
            }
            // and store itself
            stateMgr.store(state);
        }
    }

    /**
     * reloads the persistent state recursively
     *
     * @throws RepositoryException
     */
    public void reload() throws RepositoryException {
        try {
            reload(nodeState);
            // refetch nodestate if discarded
            nodeState = (NodeState) stateMgr.getItemState(nodeState.getNodeId());
        } catch (ItemStateException e) {
            throw new RepositoryException(e);
        }
    }

    /**
     * reloads the given persistent state recursively
     *
     * @param state
     * @throws ItemStateException
     */
    private void reload(NodeState state) throws ItemStateException {
        if (state.getStatus() != ItemState.STATUS_EXISTING) {
            // first discard all all transient properties
            Set props = state.getPropertyNames();
            for (Iterator iter = props.iterator(); iter.hasNext();) {
                QName propName = (QName) iter.next();
                PropertyState pstate = (PropertyState) stateMgr.getItemState(
                        new PropertyId(state.getNodeId(), propName));
                if (pstate.getStatus() != ItemState.STATUS_EXISTING) {
                    pstate.discard();
                }
            }
            // now reload all child node entries
            List nodes = state.getChildNodeEntries();
            for (int i = 0; i < nodes.size(); i++) {
                NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) nodes.get(i);
                NodeState nstate = (NodeState) stateMgr.getItemState(entry.getId());
                reload(nstate);
            }
            // and reload itself
            state.discard();
        }
    }

    /**
     * copies a property
     *
     * @param prop
     * @throws RepositoryException
     */
    public void copyFrom(PropertyImpl prop) throws RepositoryException {
        if (prop.getDefinition().isMultiple()) {
            InternalValue[] values = prop.internalGetValues();
            InternalValue[] copiedValues = new InternalValue[values.length];
            for (int i = 0; i < values.length; i++) {
                copiedValues[i] = values[i].createCopy();
            }
            setPropertyValues(prop.getQName(), prop.getType(), copiedValues);
        } else {
            setPropertyValue(prop.getQName(), prop.internalGetValue().createCopy());
        }
    }

}
TOP

Related Classes of org.apache.jackrabbit.core.version.NodeStateEx

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.