Search in sources :

Example 11 with ChildNodeEntry

use of org.apache.jackrabbit.core.state.ChildNodeEntry in project jackrabbit by apache.

the class ItemSaveOperation method perform.

public Object perform(SessionContext context) throws RepositoryException {
    SessionItemStateManager stateMgr = context.getItemStateManager();
    /**
         * build list of transient (i.e. new & modified) states that
         * should be persisted
         */
    Collection<ItemState> dirty;
    try {
        dirty = getTransientStates(context.getItemStateManager());
    } catch (ConcurrentModificationException e) {
        String msg = "Concurrent modification; session is closed";
        log.error(msg, e);
        context.getSessionImpl().logout();
        throw e;
    }
    if (dirty.size() == 0) {
        // no transient items, nothing to do here
        return this;
    }
    /**
         * build list of transient descendants in the attic
         * (i.e. those marked as 'removed')
         */
    Collection<ItemState> removed = getRemovedStates(context.getItemStateManager());
    // All affected item states. The keys are used to look up whether
    // an item is affected, and the values are iterated through below
    Map<ItemId, ItemState> affected = new HashMap<ItemId, ItemState>(dirty.size() + removed.size());
    for (ItemState state : dirty) {
        affected.put(state.getId(), state);
    }
    for (ItemState state : removed) {
        affected.put(state.getId(), state);
    }
    /**
         * make sure that this save operation is totally 'self-contained'
         * and independent; items within the scope of this save operation
         * must not have 'external' dependencies;
         * (e.g. moving a node requires that the target node including both
         * old and new parents are saved)
         */
    for (ItemState transientState : affected.values()) {
        if (transientState.isNode()) {
            NodeState nodeState = (NodeState) transientState;
            Set<NodeId> dependentIDs = new HashSet<NodeId>();
            if (nodeState.hasOverlayedState()) {
                NodeState overlayedState = (NodeState) nodeState.getOverlayedState();
                NodeId oldParentId = overlayedState.getParentId();
                NodeId newParentId = nodeState.getParentId();
                if (oldParentId != null) {
                    if (newParentId == null) {
                        // to dependencies
                        if (overlayedState.isShareable()) {
                            dependentIDs.addAll(overlayedState.getSharedSet());
                        } else {
                            dependentIDs.add(oldParentId);
                        }
                    } else {
                        if (!oldParentId.equals(newParentId)) {
                            // node has been moved to a new location,
                            // add old and new parent to dependencies
                            dependentIDs.add(oldParentId);
                            dependentIDs.add(newParentId);
                        } else {
                            // the node has been renamed (JCR-1034)
                            if (!affected.containsKey(newParentId) && stateMgr.hasTransientItemState(newParentId)) {
                                try {
                                    NodeState parent = (NodeState) stateMgr.getTransientItemState(newParentId);
                                    // check parent's renamed child node entries
                                    for (ChildNodeEntry cne : parent.getRenamedChildNodeEntries()) {
                                        if (cne.getId().equals(nodeState.getId())) {
                                            // node has been renamed,
                                            // add parent to dependencies
                                            dependentIDs.add(newParentId);
                                        }
                                    }
                                } catch (ItemStateException ise) {
                                    // should never get here
                                    log.warn("failed to retrieve transient state: " + newParentId, ise);
                                }
                            }
                        }
                    }
                }
            }
            // removed child node entries
            for (ChildNodeEntry cne : nodeState.getRemovedChildNodeEntries()) {
                dependentIDs.add(cne.getId());
            }
            // added child node entries
            for (ChildNodeEntry cne : nodeState.getAddedChildNodeEntries()) {
                dependentIDs.add(cne.getId());
            }
            // are within the scope of this save operation
            for (NodeId id : dependentIDs) {
                if (!affected.containsKey(id)) {
                    // otherwise ignore them
                    if (stateMgr.hasTransientItemState(id) || stateMgr.hasTransientItemStateInAttic(id)) {
                        // need to save dependency as well
                        String msg = context.getItemManager().safeGetJCRPath(id) + " needs to be saved as well.";
                        log.debug(msg);
                        throw new ConstraintViolationException(msg);
                    }
                }
            }
        }
    }
    // validate access and node type constraints
    // (this will also validate child removals)
    validateTransientItems(context, dirty, removed);
    // start the update operation
    try {
        stateMgr.edit();
    } catch (IllegalStateException e) {
        throw new RepositoryException("Unable to start edit operation", e);
    }
    boolean succeeded = false;
    try {
        // process transient items marked as 'removed'
        removeTransientItems(context.getItemStateManager(), removed);
        // process transient items that have change in mixins
        processShareableNodes(context.getRepositoryContext().getNodeTypeRegistry(), dirty);
        // initialize version histories for new nodes (might generate new transient state)
        if (initVersionHistories(context, dirty)) {
            // re-build the list of transient states because the previous call
            // generated new transient state
            dirty = getTransientStates(context.getItemStateManager());
        }
        // process 'new' or 'modified' transient states
        persistTransientItems(context.getItemManager(), dirty);
        // item state which is not referenced by any node instance.
        for (ItemState transientState : dirty) {
            // dispose the transient state, it is no longer used
            stateMgr.disposeTransientItemState(transientState);
        }
        // end update operation
        stateMgr.update();
        // update operation succeeded
        succeeded = true;
    } catch (StaleItemStateException e) {
        throw new InvalidItemStateException("Unable to update a stale item: " + this, e);
    } catch (ItemStateException e) {
        throw new RepositoryException("Unable to update item: " + this, e);
    } finally {
        if (!succeeded) {
            // update operation failed, cancel all modifications
            stateMgr.cancel();
            // JCR-288: if an exception has been thrown during
            // update() the transient changes have already been
            // applied by persistTransientItems() and we need to
            // restore transient state, i.e. undo the effect of
            // persistTransientItems()
            restoreTransientItems(context, dirty);
        }
    }
    // items in store().
    for (ItemState transientState : removed) {
        // dispose the transient state, it is no longer used
        stateMgr.disposeTransientItemStateInAttic(transientState);
    }
    return this;
}
Also used : ConcurrentModificationException(java.util.ConcurrentModificationException) NodeState(org.apache.jackrabbit.core.state.NodeState) HashMap(java.util.HashMap) InvalidItemStateException(javax.jcr.InvalidItemStateException) ChildNodeEntry(org.apache.jackrabbit.core.state.ChildNodeEntry) RepositoryException(javax.jcr.RepositoryException) ItemId(org.apache.jackrabbit.core.id.ItemId) InvalidItemStateException(javax.jcr.InvalidItemStateException) ItemStateException(org.apache.jackrabbit.core.state.ItemStateException) StaleItemStateException(org.apache.jackrabbit.core.state.StaleItemStateException) StaleItemStateException(org.apache.jackrabbit.core.state.StaleItemStateException) ItemState(org.apache.jackrabbit.core.state.ItemState) NodeId(org.apache.jackrabbit.core.id.NodeId) ConstraintViolationException(javax.jcr.nodetype.ConstraintViolationException) SessionItemStateManager(org.apache.jackrabbit.core.state.SessionItemStateManager) HashSet(java.util.HashSet)

Example 12 with ChildNodeEntry

use of org.apache.jackrabbit.core.state.ChildNodeEntry in project jackrabbit by apache.

the class NodeImpl method setPrimaryType.

/**
     * {@inheritDoc}
     */
public void setPrimaryType(String nodeTypeName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException {
    // check state of this instance
    sanityCheck();
    // make sure this node is checked-out, neither protected nor locked and
    // the editing session has sufficient permission to change the primary type.
    int options = ItemValidator.CHECK_CHECKED_OUT | ItemValidator.CHECK_LOCK | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
    sessionContext.getItemValidator().checkModify(this, options, Permission.NODE_TYPE_MNGMT);
    final NodeState state = data.getNodeState();
    if (state.getParentId() == null) {
        String msg = "changing the primary type of the root node is not supported";
        log.debug(msg);
        throw new RepositoryException(msg);
    }
    Name ntName = sessionContext.getQName(nodeTypeName);
    if (ntName.equals(state.getNodeTypeName())) {
        log.debug("Node already has " + nodeTypeName + " as primary node type.");
        return;
    }
    NodeTypeManagerImpl ntMgr = sessionContext.getNodeTypeManager();
    NodeType nt = ntMgr.getNodeType(ntName);
    if (nt.isMixin()) {
        throw new ConstraintViolationException(nodeTypeName + ": not a primary node type.");
    } else if (nt.isAbstract()) {
        throw new ConstraintViolationException(nodeTypeName + ": is an abstract node type.");
    }
    // build effective node type of new primary type & existing mixin's
    // in order to detect conflicts
    NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
    EffectiveNodeType entNew, entOld, entAll;
    try {
        entNew = ntReg.getEffectiveNodeType(ntName);
        entOld = ntReg.getEffectiveNodeType(state.getNodeTypeName());
        // try to build new effective node type (will throw in case of conflicts)
        entAll = ntReg.getEffectiveNodeType(ntName, state.getMixinTypeNames());
    } catch (NodeTypeConflictException ntce) {
        throw new ConstraintViolationException(ntce.getMessage());
    }
    // get applicable definition for this node using new primary type
    QNodeDefinition nodeDef;
    try {
        NodeImpl parent = (NodeImpl) getParent();
        nodeDef = parent.getApplicableChildNodeDefinition(getQName(), ntName).unwrap();
    } catch (RepositoryException re) {
        String msg = this + ": no applicable definition found in parent node's node type";
        log.debug(msg);
        throw new ConstraintViolationException(msg, re);
    }
    if (!nodeDef.equals(itemMgr.getDefinition(state).unwrap())) {
        onRedefine(nodeDef);
    }
    Set<QItemDefinition> oldDefs = new HashSet<QItemDefinition>(Arrays.asList(entOld.getAllItemDefs()));
    Set<QItemDefinition> newDefs = new HashSet<QItemDefinition>(Arrays.asList(entNew.getAllItemDefs()));
    Set<QItemDefinition> allDefs = new HashSet<QItemDefinition>(Arrays.asList(entAll.getAllItemDefs()));
    // added child item definitions
    Set<QItemDefinition> addedDefs = new HashSet<QItemDefinition>(newDefs);
    addedDefs.removeAll(oldDefs);
    // referential integrity check
    boolean referenceableOld = entOld.includesNodeType(NameConstants.MIX_REFERENCEABLE);
    boolean referenceableNew = entNew.includesNodeType(NameConstants.MIX_REFERENCEABLE);
    if (referenceableOld && !referenceableNew) {
        // node would become non-referenceable;
        // make sure no references exist
        PropertyIterator iter = getReferences();
        if (iter.hasNext()) {
            throw new ConstraintViolationException("the new primary type cannot be set as it would render " + "this node 'non-referenceable' while it is still being " + "referenced through at least one property of type REFERENCE");
        }
    }
    // do the actual modifications in content as mandated by the new primary type
    // modify the state of this node
    NodeState thisState = (NodeState) getOrCreateTransientItemState();
    thisState.setNodeTypeName(ntName);
    // set jcr:primaryType property
    internalSetProperty(NameConstants.JCR_PRIMARYTYPE, InternalValue.create(ntName));
    // walk through properties and child nodes and change definition as necessary
    // use temp set to avoid ConcurrentModificationException
    HashSet<Name> set = new HashSet<Name>(thisState.getPropertyNames());
    for (Name propName : set) {
        try {
            PropertyState propState = (PropertyState) stateMgr.getItemState(new PropertyId(thisState.getNodeId(), propName));
            if (!allDefs.contains(itemMgr.getDefinition(propState).unwrap())) {
                // redefine property if possible
                try {
                    PropertyImpl prop = (PropertyImpl) itemMgr.getItem(propState.getId());
                    if (prop.getDefinition().isProtected()) {
                        // remove 'orphaned' protected properties immediately
                        removeChildProperty(propName);
                        continue;
                    }
                    PropertyDefinitionImpl pdi = getApplicablePropertyDefinition(propName, propState.getType(), propState.isMultiValued(), false);
                    if (pdi.getRequiredType() != PropertyType.UNDEFINED && pdi.getRequiredType() != propState.getType()) {
                        // value conversion required
                        if (propState.isMultiValued()) {
                            // convert value
                            Value[] values = ValueHelper.convert(prop.getValues(), pdi.getRequiredType(), getSession().getValueFactory());
                            // redefine property
                            prop.onRedefine(pdi.unwrap());
                            // set converted values
                            prop.setValue(values);
                        } else {
                            // convert value
                            Value value = ValueHelper.convert(prop.getValue(), pdi.getRequiredType(), getSession().getValueFactory());
                            // redefine property
                            prop.onRedefine(pdi.unwrap());
                            // set converted values
                            prop.setValue(value);
                        }
                    } else {
                        // redefine property
                        prop.onRedefine(pdi.unwrap());
                    }
                    // update collection of added definitions
                    addedDefs.remove(pdi.unwrap());
                } catch (ValueFormatException vfe) {
                    // value conversion failed, remove it
                    removeChildProperty(propName);
                } catch (ConstraintViolationException cve) {
                    // no suitable definition found for this property,
                    // remove it
                    removeChildProperty(propName);
                }
            }
        } catch (ItemStateException ise) {
            String msg = propName + ": failed to retrieve property state";
            log.error(msg, ise);
            throw new RepositoryException(msg, ise);
        }
    }
    // use temp array to avoid ConcurrentModificationException
    ArrayList<ChildNodeEntry> list = new ArrayList<ChildNodeEntry>(thisState.getChildNodeEntries());
    // start from tail to avoid problems with same-name siblings
    for (int i = list.size() - 1; i >= 0; i--) {
        ChildNodeEntry entry = list.get(i);
        try {
            NodeState nodeState = (NodeState) stateMgr.getItemState(entry.getId());
            if (!allDefs.contains(itemMgr.getDefinition(nodeState).unwrap())) {
                // redefine node if possible
                try {
                    NodeImpl node = (NodeImpl) itemMgr.getItem(nodeState.getId());
                    if (node.getDefinition().isProtected()) {
                        // remove 'orphaned' protected child node immediately
                        removeChildNode(entry.getId());
                        continue;
                    }
                    NodeDefinitionImpl ndi = getApplicableChildNodeDefinition(entry.getName(), nodeState.getNodeTypeName());
                    // redefine node
                    node.onRedefine(ndi.unwrap());
                    // update collection of added definitions
                    addedDefs.remove(ndi.unwrap());
                } catch (ConstraintViolationException cve) {
                    // no suitable definition found for this child node,
                    // remove it
                    removeChildNode(entry.getId());
                }
            }
        } catch (ItemStateException ise) {
            String msg = entry.getName() + ": failed to retrieve node state";
            log.error(msg, ise);
            throw new RepositoryException(msg, ise);
        }
    }
    // type and at the same time were not present with the old nt
    for (QItemDefinition def : addedDefs) {
        if (def.isAutoCreated()) {
            if (def.definesNode()) {
                NodeDefinitionImpl ndi = ntMgr.getNodeDefinition((QNodeDefinition) def);
                createChildNode(def.getName(), (NodeTypeImpl) ndi.getDefaultPrimaryType(), null);
            } else {
                PropertyDefinitionImpl pdi = ntMgr.getPropertyDefinition((QPropertyDefinition) def);
                createChildProperty(pdi.unwrap().getName(), pdi.getRequiredType(), pdi);
            }
        }
    }
}
Also used : NodeState(org.apache.jackrabbit.core.state.NodeState) NodeTypeConflictException(org.apache.jackrabbit.core.nodetype.NodeTypeConflictException) ArrayList(java.util.ArrayList) Name(org.apache.jackrabbit.spi.Name) NodeDefinitionImpl(org.apache.jackrabbit.spi.commons.nodetype.NodeDefinitionImpl) ConstraintViolationException(javax.jcr.nodetype.ConstraintViolationException) NodeTypeManagerImpl(org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl) HashSet(java.util.HashSet) ChildNodeEntry(org.apache.jackrabbit.core.state.ChildNodeEntry) PropertyIterator(javax.jcr.PropertyIterator) PropertyDefinitionImpl(org.apache.jackrabbit.spi.commons.nodetype.PropertyDefinitionImpl) RepositoryException(javax.jcr.RepositoryException) QNodeDefinition(org.apache.jackrabbit.spi.QNodeDefinition) QItemDefinition(org.apache.jackrabbit.spi.QItemDefinition) PropertyState(org.apache.jackrabbit.core.state.PropertyState) PropertyId(org.apache.jackrabbit.core.id.PropertyId) InvalidItemStateException(javax.jcr.InvalidItemStateException) ItemStateException(org.apache.jackrabbit.core.state.ItemStateException) EffectiveNodeType(org.apache.jackrabbit.core.nodetype.EffectiveNodeType) EffectiveNodeType(org.apache.jackrabbit.core.nodetype.EffectiveNodeType) NodeType(javax.jcr.nodetype.NodeType) Value(javax.jcr.Value) InternalValue(org.apache.jackrabbit.core.value.InternalValue) ValueFormatException(javax.jcr.ValueFormatException) NodeTypeRegistry(org.apache.jackrabbit.core.nodetype.NodeTypeRegistry)

Example 13 with ChildNodeEntry

use of org.apache.jackrabbit.core.state.ChildNodeEntry in project jackrabbit by apache.

the class NodeImpl method addNode.

/**
     * Same as <code>{@link Node#addNode(String, String)}</code> except that
     * this method takes <code>Name</code> arguments instead of
     * <code>String</code>s and has an additional <code>uuid</code> argument.
     * <p>
     * <b>Important Notice:</b> This method is for internal use only! Passing
     * already assigned uuid's might lead to unexpected results and
     * data corruption in the worst case.
     *
     * @param nodeName     name of the new node
     * @param nodeTypeName name of the new node's node type or <code>null</code>
     *                     if it should be determined automatically
     * @param id           id of the new node or <code>null</code> if a new
     *                     id should be assigned
     * @return the newly added node
     * @throws RepositoryException if the node can not added
     */
// FIXME: This method should not be public
public synchronized NodeImpl addNode(Name nodeName, Name nodeTypeName, NodeId id) throws RepositoryException {
    // check state of this instance
    sanityCheck();
    Path nodePath = PathFactoryImpl.getInstance().create(getPrimaryPath(), nodeName, true);
    // Check the explicitly specified node type (if any)
    NodeTypeImpl nt = null;
    if (nodeTypeName != null) {
        nt = sessionContext.getNodeTypeManager().getNodeType(nodeTypeName);
        if (nt.isMixin()) {
            throw new ConstraintViolationException("Unable to add a node with a mixin node type: " + sessionContext.getJCRName(nodeTypeName));
        } else if (nt.isAbstract()) {
            throw new ConstraintViolationException("Unable to add a node with an abstract node type: " + sessionContext.getJCRName(nodeTypeName));
        } else {
            // adding a node with explicit specifying the node type name
            // requires the editing session to have nt_management privilege.
            sessionContext.getAccessManager().checkPermission(nodePath, Permission.NODE_TYPE_MNGMT);
        }
    }
    // Get the applicable child node definition for this node.
    NodeDefinitionImpl def;
    try {
        def = getApplicableChildNodeDefinition(nodeName, nodeTypeName);
    } catch (RepositoryException e) {
        throw new ConstraintViolationException("No child node definition for " + sessionContext.getJCRName(nodeName) + " found in " + this, e);
    }
    // Use default node type from child node definition if needed
    if (nt == null) {
        nt = (NodeTypeImpl) def.getDefaultPrimaryType();
    }
    // check the new name
    NodeNameNormalizer.check(nodeName);
    // check for name collisions
    NodeState thisState = data.getNodeState();
    ChildNodeEntry cne = thisState.getChildNodeEntry(nodeName, 1);
    if (cne != null) {
        // check same-name sibling setting of new node
        if (!def.allowsSameNameSiblings()) {
            throw new ItemExistsException("This node already exists: " + itemMgr.safeGetJCRPath(nodePath));
        }
        // check same-name sibling setting of existing node
        NodeImpl existing = itemMgr.getNode(cne.getId(), getNodeId());
        if (!existing.getDefinition().allowsSameNameSiblings()) {
            throw new ItemExistsException("Same-name siblings not allowed for " + existing);
        }
    }
    // check protected flag of parent (i.e. this) node and retention/hold
    // make sure this node is checked-out and not locked by another session.
    int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_CHECKED_OUT | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD | ItemValidator.CHECK_RETENTION;
    sessionContext.getItemValidator().checkModify(this, options, Permission.NONE);
    // now do create the child node
    return createChildNode(nodeName, nt, id);
}
Also used : Path(org.apache.jackrabbit.spi.Path) NodeDefinitionImpl(org.apache.jackrabbit.spi.commons.nodetype.NodeDefinitionImpl) NodeTypeImpl(org.apache.jackrabbit.core.nodetype.NodeTypeImpl) NodeState(org.apache.jackrabbit.core.state.NodeState) ItemExistsException(javax.jcr.ItemExistsException) ChildNodeEntry(org.apache.jackrabbit.core.state.ChildNodeEntry) ConstraintViolationException(javax.jcr.nodetype.ConstraintViolationException) RepositoryException(javax.jcr.RepositoryException)

Example 14 with ChildNodeEntry

use of org.apache.jackrabbit.core.state.ChildNodeEntry in project jackrabbit by apache.

the class HierarchyManagerImpl method resolvePath.

//-------------------------------------------------------< implementation >
/**
     * Internal implementation that iteratively resolves a path into an item.
     *
     * @param elements path elements
     * @param next index of next item in <code>elements</code> to inspect
     * @param id id of item at path <code>elements[0]</code>..<code>elements[next - 1]</code>
     * @param typesAllowed one of <code>RETURN_ANY</code>, <code>RETURN_NODE</code>
     *                     or <code>RETURN_PROPERTY</code>
     * @return id or <code>null</code>
     * @throws ItemStateException if an intermediate item state is not found
     * @throws MalformedPathException if building an intermediate path fails
     */
protected ItemId resolvePath(Path.Element[] elements, int next, ItemId id, int typesAllowed) throws ItemStateException, MalformedPathException {
    PathBuilder builder = new PathBuilder();
    for (int i = 0; i < next; i++) {
        builder.addLast(elements[i]);
    }
    for (int i = next; i < elements.length; i++) {
        Path.Element elem = elements[i];
        NodeId parentId = (NodeId) id;
        id = null;
        Name name = elem.getName();
        int index = elem.getIndex();
        if (index == 0) {
            index = 1;
        }
        int typeExpected = typesAllowed;
        if (i < elements.length - 1) {
            // intermediate items must always be nodes
            typeExpected = RETURN_NODE;
        }
        NodeState parentState = (NodeState) getItemState(parentId);
        if ((typeExpected & RETURN_NODE) != 0) {
            ChildNodeEntry nodeEntry = getChildNodeEntry(parentState, name, index);
            if (nodeEntry != null) {
                id = nodeEntry.getId();
            }
        }
        if (id == null && (typeExpected & RETURN_PROPERTY) != 0) {
            if (parentState.hasPropertyName(name) && (index <= 1)) {
                // property
                id = new PropertyId(parentState.getNodeId(), name);
            }
        }
        if (id == null) {
            break;
        }
        builder.addLast(elements[i]);
        pathResolved(id, builder);
    }
    return id;
}
Also used : Path(org.apache.jackrabbit.spi.Path) PathBuilder(org.apache.jackrabbit.spi.commons.name.PathBuilder) NodeState(org.apache.jackrabbit.core.state.NodeState) ChildNodeEntry(org.apache.jackrabbit.core.state.ChildNodeEntry) NodeId(org.apache.jackrabbit.core.id.NodeId) Name(org.apache.jackrabbit.spi.Name) PropertyId(org.apache.jackrabbit.core.id.PropertyId)

Example 15 with ChildNodeEntry

use of org.apache.jackrabbit.core.state.ChildNodeEntry in project jackrabbit by apache.

the class NodeImpl method replaceChildNode.

/**
     * Replaces the child node with the specified <code>id</code>
     * by a new child node with the same id and specified <code>nodeName</code>,
     * <code>nodeTypeName</code> and <code>mixinNames</code>.
     *
     * @param id           id of the child node to be replaced
     * @param nodeName     name of the new node
     * @param nodeTypeName name of the new node's node type
     * @param mixinNames   name of the new node's mixin types
     *
     * @return the new child node replacing the existing child
     * @throws ItemNotFoundException
     * @throws NoSuchNodeTypeException
     * @throws VersionException
     * @throws ConstraintViolationException
     * @throws LockException
     * @throws RepositoryException
     */
public synchronized NodeImpl replaceChildNode(NodeId id, Name nodeName, Name nodeTypeName, Name[] mixinNames) throws ItemNotFoundException, NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException {
    // check state of this instance
    sanityCheck();
    Node existing = (Node) itemMgr.getItem(id);
    // 'replace' is actually a 'remove existing/add new' operation;
    // this unfortunately changes the order of this node's
    // child node entries (JCR-1055);
    // => backup list of child node entries beforehand in order
    // to restore it afterwards
    NodeState state = data.getNodeState();
    ChildNodeEntry cneExisting = state.getChildNodeEntry(id);
    if (cneExisting == null) {
        throw new ItemNotFoundException(this + ": no child node entry with id " + id);
    }
    List<ChildNodeEntry> cneList = new ArrayList<ChildNodeEntry>(state.getChildNodeEntries());
    // remove existing
    existing.remove();
    // create new child node
    NodeImpl node = addNode(nodeName, nodeTypeName, id);
    if (mixinNames != null) {
        for (Name mixinName : mixinNames) {
            node.addMixin(mixinName);
        }
    }
    // fetch <code>state</code> again, as it changed while removing child
    state = data.getNodeState();
    // restore list of child node entries (JCR-1055)
    if (cneExisting.getName().equals(nodeName)) {
        // restore original child node list
        state.setChildNodeEntries(cneList);
    } else {
        // replace child node entry with different name
        // but preserving original position
        state.removeAllChildNodeEntries();
        for (ChildNodeEntry cne : cneList) {
            if (cne.getId().equals(id)) {
                // replace entry with different name
                state.addChildNodeEntry(nodeName, id);
            } else {
                state.addChildNodeEntry(cne.getName(), cne.getId());
            }
        }
    }
    return node;
}
Also used : NodeState(org.apache.jackrabbit.core.state.NodeState) JackrabbitNode(org.apache.jackrabbit.api.JackrabbitNode) Node(javax.jcr.Node) ChildNodeEntry(org.apache.jackrabbit.core.state.ChildNodeEntry) ArrayList(java.util.ArrayList) ItemNotFoundException(javax.jcr.ItemNotFoundException) Name(org.apache.jackrabbit.spi.Name)

Aggregations

ChildNodeEntry (org.apache.jackrabbit.core.state.ChildNodeEntry)44 NodeState (org.apache.jackrabbit.core.state.NodeState)34 RepositoryException (javax.jcr.RepositoryException)25 NodeId (org.apache.jackrabbit.core.id.NodeId)23 Name (org.apache.jackrabbit.spi.Name)22 ItemStateException (org.apache.jackrabbit.core.state.ItemStateException)19 PropertyState (org.apache.jackrabbit.core.state.PropertyState)13 Path (org.apache.jackrabbit.spi.Path)12 ItemNotFoundException (javax.jcr.ItemNotFoundException)11 ConstraintViolationException (javax.jcr.nodetype.ConstraintViolationException)11 PropertyId (org.apache.jackrabbit.core.id.PropertyId)11 EffectiveNodeType (org.apache.jackrabbit.core.nodetype.EffectiveNodeType)10 ArrayList (java.util.ArrayList)9 ItemExistsException (javax.jcr.ItemExistsException)9 NoSuchItemStateException (org.apache.jackrabbit.core.state.NoSuchItemStateException)9 InvalidItemStateException (javax.jcr.InvalidItemStateException)7 HashSet (java.util.HashSet)6 NodeTypeImpl (org.apache.jackrabbit.core.nodetype.NodeTypeImpl)5 InternalValue (org.apache.jackrabbit.core.value.InternalValue)5 QNodeDefinition (org.apache.jackrabbit.spi.QNodeDefinition)5