Search in sources :

Example 1 with ItemState

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

the class SimpleEventListener method equals.

/**
 * Check whether two iterators return the same item states, where "same"
 * means having the same <code>ItemId</code>
 * @param iter1 first iterator
 * @param iter2 second iterator
 * @return <code>true</code> if the two iterators are equal;
 *         <code>false</code> otherwise
 */
private static boolean equals(Iterator iter1, Iterator iter2) {
    for (; ; ) {
        if (!iter1.hasNext() && !iter2.hasNext()) {
            return true;
        }
        if (iter1.hasNext() && !iter2.hasNext()) {
            return false;
        }
        if (!iter1.hasNext() && iter2.hasNext()) {
            return false;
        }
        ItemState state1 = (ItemState) iter1.next();
        ItemState state2 = (ItemState) iter2.next();
        return state1.getId().equals(state2.getId());
    }
}
Also used : ItemState(org.apache.jackrabbit.core.state.ItemState)

Example 2 with ItemState

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

the class ItemRefreshOperation method perform.

public Object perform(SessionContext context) throws RepositoryException {
    if (keepChanges) {
        // maybe also have to reset stale ItemState instances
        return this;
    }
    SessionItemStateManager stateMgr = context.getItemStateManager();
    // Optimisation for the root node
    if (state.getParentId() == null) {
        stateMgr.disposeAllTransientItemStates();
        return this;
    }
    // list of transient items that should be discarded
    List<ItemState> transientStates = new ArrayList<ItemState>();
    // check status of this item's state
    if (state.isTransient()) {
        switch(state.getStatus()) {
            case ItemState.STATUS_STALE_DESTROYED:
                // add this item's state to the list
                transientStates.add(state);
                break;
            case ItemState.STATUS_EXISTING_MODIFIED:
                if (!state.getParentId().equals(state.getOverlayedState().getParentId())) {
                    throw new RepositoryException("Cannot refresh a moved item," + " try refreshing the parent: " + this);
                }
                transientStates.add(state);
                break;
            case ItemState.STATUS_NEW:
                throw new RepositoryException("Cannot refresh a new item: " + this);
            default:
                // log and ignore
                log.warn("Unexpected item state status {} of {}", state.getStatus(), this);
                break;
        }
    }
    if (state.isNode()) {
        // build list of 'new', 'modified' or 'stale' descendants
        for (ItemState transientState : stateMgr.getDescendantTransientItemStates(state.getId())) {
            switch(transientState.getStatus()) {
                case ItemState.STATUS_STALE_DESTROYED:
                case ItemState.STATUS_NEW:
                case ItemState.STATUS_EXISTING_MODIFIED:
                    // add new or modified state to the list
                    transientStates.add(transientState);
                    break;
                default:
                    // log and ignore
                    log.debug("unexpected state status ({})", transientState.getStatus());
                    break;
            }
        }
    }
    // process list of 'new', 'modified' or 'stale' transient states
    for (ItemState transientState : transientStates) {
        // dispose the transient state, it is no longer used;
        // this will indirectly (through stateDiscarded listener method)
        // either restore or permanently invalidate the wrapping Item instances
        stateMgr.disposeTransientItemState(transientState);
    }
    if (state.isNode()) {
        // as 'removed'); this will resurrect the removed items
        for (ItemState descendant : stateMgr.getDescendantTransientItemStatesInAttic(state.getId())) {
            // dispose the transient state; this will indirectly
            // (through stateDiscarded listener method) resurrect
            // the wrapping Item instances
            stateMgr.disposeTransientItemStateInAttic(descendant);
        }
    }
    return this;
}
Also used : ItemState(org.apache.jackrabbit.core.state.ItemState) ArrayList(java.util.ArrayList) RepositoryException(javax.jcr.RepositoryException) SessionItemStateManager(org.apache.jackrabbit.core.state.SessionItemStateManager)

Example 3 with ItemState

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

the class ItemSaveOperation method validateTransientItems.

/**
 * the following validations/checks are performed on transient items:
 *
 * for every transient item:
 * - if it is 'modified' or 'new' check the corresponding write permission.
 * - if it is 'removed' check the REMOVE permission
 *
 * for every transient node:
 * - if it is 'new' check that its node type satisfies the
 *   'required node type' constraint specified in its definition
 * - check if 'mandatory' child items exist
 *
 * for every transient property:
 * - check if the property value satisfies the value constraints
 *   specified in the property's definition
 *
 * note that the protected flag is checked in Node.addNode/Node.remove
 * (for adding/removing child entries of a node), in
 * Node.addMixin/removeMixin/setPrimaryType (for type changes on nodes)
 * and in Property.setValue (for properties to be modified).
 */
private void validateTransientItems(SessionContext context, Iterable<ItemState> dirty, Iterable<ItemState> removed) throws RepositoryException {
    SessionImpl session = context.getSessionImpl();
    ItemManager itemMgr = context.getItemManager();
    SessionItemStateManager stateMgr = context.getItemStateManager();
    AccessManager accessMgr = context.getAccessManager();
    NodeTypeManagerImpl ntMgr = context.getNodeTypeManager();
    // walk through list of dirty transient items and validate each
    for (ItemState itemState : dirty) {
        ItemDefinition def;
        if (itemState.isNode()) {
            def = itemMgr.getDefinition((NodeState) itemState);
        } else {
            def = itemMgr.getDefinition((PropertyState) itemState);
        }
        /* check permissions for non-protected items. protected items are
               only added through API methods which need to assert that
               permissions are not violated.
             */
        if (!def.isProtected()) {
            /* detect the effective set of modification:
                   - new added node -> add_node perm on the child
                   - new property added -> set_property permission
                   - property modified -> set_property permission
                   - modified nodes can be ignored for changes only included
                     child-item addition or removal or changes of protected
                     properties such as mixin-types which are covered separately
                   note: removed items are checked later on.
                   note: reordering of child nodes has been covered upfront as
                         this information isn't available here.
                */
            Path path = stateMgr.getHierarchyMgr().getPath(itemState.getId());
            boolean isGranted = true;
            if (itemState.isNode()) {
                if (itemState.getStatus() == ItemState.STATUS_NEW) {
                    isGranted = accessMgr.isGranted(path, Permission.ADD_NODE);
                }
            // else: modified node (see comment above)
            } else {
                // modified or new property: set_property permission
                isGranted = accessMgr.isGranted(path, Permission.SET_PROPERTY);
            }
            if (!isGranted) {
                String msg = itemMgr.safeGetJCRPath(path) + ": not allowed to add or modify item";
                log.debug(msg);
                throw new AccessDeniedException(msg);
            }
        }
        if (itemState.isNode()) {
            // the transient item is a node
            NodeState nodeState = (NodeState) itemState;
            ItemId id = nodeState.getNodeId();
            NodeDefinition nodeDef = (NodeDefinition) def;
            // primary type
            NodeTypeImpl pnt = ntMgr.getNodeType(nodeState.getNodeTypeName());
            // effective node type (primary type incl. mixins)
            EffectiveNodeType ent = getEffectiveNodeType(context.getRepositoryContext().getNodeTypeRegistry(), nodeState);
            /**
             * if the transient node was added (i.e. if it is 'new') or if
             * its primary type has changed, check its node type against the
             * required node type in its definition
             */
            boolean primaryTypeChanged = nodeState.getStatus() == ItemState.STATUS_NEW;
            if (!primaryTypeChanged) {
                NodeState overlaid = (NodeState) nodeState.getOverlayedState();
                if (overlaid != null) {
                    Name newName = nodeState.getNodeTypeName();
                    Name oldName = overlaid.getNodeTypeName();
                    primaryTypeChanged = !newName.equals(oldName);
                }
            }
            if (primaryTypeChanged) {
                for (NodeType ntReq : nodeDef.getRequiredPrimaryTypes()) {
                    Name ntName = ((NodeTypeImpl) ntReq).getQName();
                    if (!(pnt.getQName().equals(ntName) || pnt.isDerivedFrom(ntName))) {
                        /**
                         * the transient node's primary node type does not
                         * satisfy the 'required primary types' constraint
                         */
                        String msg = itemMgr.safeGetJCRPath(id) + " must be of node type " + ntReq.getName();
                        log.debug(msg);
                        throw new ConstraintViolationException(msg);
                    }
                }
            }
            // mandatory child properties
            for (QPropertyDefinition pd : ent.getMandatoryPropDefs()) {
                if (pd.getDeclaringNodeType().equals(NameConstants.MIX_VERSIONABLE) || pd.getDeclaringNodeType().equals(NameConstants.MIX_SIMPLE_VERSIONABLE)) {
                    /**
                     * todo FIXME workaround for mix:versionable:
                     * the mandatory properties are initialized at a
                     * later stage and might not exist yet
                     */
                    continue;
                }
                String msg = itemMgr.safeGetJCRPath(id) + ": mandatory property " + pd.getName() + " does not exist";
                if (!nodeState.hasPropertyName(pd.getName())) {
                    log.debug(msg);
                    throw new ConstraintViolationException(msg);
                } else {
                    /*
                        there exists a property with the mandatory-name.
                        make sure the property really has the expected mandatory
                        property definition (and not another non-mandatory def,
                        such as e.g. multivalued residual instead of single-value
                        mandatory, named def).
                        */
                    PropertyId pi = new PropertyId(nodeState.getNodeId(), pd.getName());
                    ItemData childData = itemMgr.getItemData(pi, null, false);
                    if (!childData.getDefinition().isMandatory()) {
                        throw new ConstraintViolationException(msg);
                    }
                }
            }
            // mandatory child nodes
            for (QItemDefinition cnd : ent.getMandatoryNodeDefs()) {
                String msg = itemMgr.safeGetJCRPath(id) + ": mandatory child node " + cnd.getName() + " does not exist";
                if (!nodeState.hasChildNodeEntry(cnd.getName())) {
                    log.debug(msg);
                    throw new ConstraintViolationException(msg);
                } else {
                    /*
                        there exists a child node with the mandatory-name.
                        make sure the node really has the expected mandatory
                        node definition.
                        */
                    boolean hasMandatoryChild = false;
                    for (ChildNodeEntry cne : nodeState.getChildNodeEntries(cnd.getName())) {
                        ItemData childData = itemMgr.getItemData(cne.getId(), null, false);
                        if (childData.getDefinition().isMandatory()) {
                            hasMandatoryChild = true;
                            break;
                        }
                    }
                    if (!hasMandatoryChild) {
                        throw new ConstraintViolationException(msg);
                    }
                }
            }
        } else {
            // the transient item is a property
            PropertyState propState = (PropertyState) itemState;
            ItemId propId = propState.getPropertyId();
            org.apache.jackrabbit.spi.commons.nodetype.PropertyDefinitionImpl propDef = (org.apache.jackrabbit.spi.commons.nodetype.PropertyDefinitionImpl) def;
            /**
             * check value constraints
             * (no need to check value constraints of protected properties
             * as those are set by the implementation only, i.e. they
             * cannot be set by the user through the api)
             */
            if (!def.isProtected()) {
                String[] constraints = propDef.getValueConstraints();
                if (constraints != null) {
                    InternalValue[] values = propState.getValues();
                    try {
                        EffectiveNodeType.checkSetPropertyValueConstraints(propDef.unwrap(), values);
                    } catch (RepositoryException e) {
                        // repack exception for providing more verbose error message
                        String msg = itemMgr.safeGetJCRPath(propId) + ": " + e.getMessage();
                        log.debug(msg);
                        throw new ConstraintViolationException(msg);
                    }
                    /**
                     * need to manually check REFERENCE value constraints
                     * as this requires a session (target node needs to
                     * be checked)
                     */
                    if (constraints.length > 0 && (propDef.getRequiredType() == PropertyType.REFERENCE || propDef.getRequiredType() == PropertyType.WEAKREFERENCE)) {
                        for (InternalValue internalV : values) {
                            boolean satisfied = false;
                            String constraintViolationMsg = null;
                            try {
                                NodeId targetId = internalV.getNodeId();
                                if (propDef.getRequiredType() == PropertyType.WEAKREFERENCE && !itemMgr.itemExists(targetId)) {
                                    // target of weakref doesn;t exist, skip
                                    continue;
                                }
                                Node targetNode = session.getNodeById(targetId);
                                /**
                                 * constraints are OR-ed, i.e. at least one
                                 * has to be satisfied
                                 */
                                for (String constrNtName : constraints) {
                                    /**
                                     * a [WEAK]REFERENCE value constraint specifies
                                     * the name of the required node type of
                                     * the target node
                                     */
                                    if (targetNode.isNodeType(constrNtName)) {
                                        satisfied = true;
                                        break;
                                    }
                                }
                                if (!satisfied) {
                                    NodeType[] mixinNodeTypes = targetNode.getMixinNodeTypes();
                                    String[] targetMixins = new String[mixinNodeTypes.length];
                                    for (int j = 0; j < mixinNodeTypes.length; j++) {
                                        targetMixins[j] = mixinNodeTypes[j].getName();
                                    }
                                    String targetMixinsString = Text.implode(targetMixins, ", ");
                                    String constraintsString = Text.implode(constraints, ", ");
                                    constraintViolationMsg = itemMgr.safeGetJCRPath(propId) + ": is constraint to [" + constraintsString + "] but references [primaryType=" + targetNode.getPrimaryNodeType().getName() + ", mixins=" + targetMixinsString + "]";
                                }
                            } catch (RepositoryException re) {
                                String msg = itemMgr.safeGetJCRPath(propId) + ": failed to check " + ((propDef.getRequiredType() == PropertyType.REFERENCE) ? "REFERENCE" : "WEAKREFERENCE") + " value constraint";
                                log.debug(msg);
                                throw new ConstraintViolationException(msg, re);
                            }
                            if (!satisfied) {
                                log.debug(constraintViolationMsg);
                                throw new ConstraintViolationException(constraintViolationMsg);
                            }
                        }
                    }
                }
            }
        /**
         * no need to check the protected flag as this is checked
         * in PropertyImpl.setValue(Value)
         */
        }
    }
    // walk through list of removed transient items and check REMOVE permission
    for (ItemState itemState : removed) {
        QItemDefinition def;
        try {
            if (itemState.isNode()) {
                def = itemMgr.getDefinition((NodeState) itemState).unwrap();
            } else {
                def = itemMgr.getDefinition((PropertyState) itemState).unwrap();
            }
        } catch (ConstraintViolationException e) {
            // of a mixin (see also JCR-2130 & JCR-2408)
            continue;
        }
        if (!def.isProtected()) {
            Path path = stateMgr.getAtticAwareHierarchyMgr().getPath(itemState.getId());
            // check REMOVE permission
            int permission = (itemState.isNode()) ? Permission.REMOVE_NODE : Permission.REMOVE_PROPERTY;
            if (!accessMgr.isGranted(path, permission)) {
                String msg = itemMgr.safeGetJCRPath(path) + ": not allowed to remove item";
                log.debug(msg);
                throw new AccessDeniedException(msg);
            }
        }
    }
}
Also used : AccessManager(org.apache.jackrabbit.core.security.AccessManager) AccessDeniedException(javax.jcr.AccessDeniedException) NodeState(org.apache.jackrabbit.core.state.NodeState) NodeTypeImpl(org.apache.jackrabbit.core.nodetype.NodeTypeImpl) Node(javax.jcr.Node) QItemDefinition(org.apache.jackrabbit.spi.QItemDefinition) ItemDefinition(javax.jcr.nodetype.ItemDefinition) NodeDefinition(javax.jcr.nodetype.NodeDefinition) ItemId(org.apache.jackrabbit.core.id.ItemId) Name(org.apache.jackrabbit.spi.Name) QPropertyDefinition(org.apache.jackrabbit.spi.QPropertyDefinition) ConstraintViolationException(javax.jcr.nodetype.ConstraintViolationException) NodeTypeManagerImpl(org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl) Path(org.apache.jackrabbit.spi.Path) ChildNodeEntry(org.apache.jackrabbit.core.state.ChildNodeEntry) RepositoryException(javax.jcr.RepositoryException) QItemDefinition(org.apache.jackrabbit.spi.QItemDefinition) InternalValue(org.apache.jackrabbit.core.value.InternalValue) PropertyState(org.apache.jackrabbit.core.state.PropertyState) PropertyId(org.apache.jackrabbit.core.id.PropertyId) EffectiveNodeType(org.apache.jackrabbit.core.nodetype.EffectiveNodeType) ItemState(org.apache.jackrabbit.core.state.ItemState) NodeType(javax.jcr.nodetype.NodeType) EffectiveNodeType(org.apache.jackrabbit.core.nodetype.EffectiveNodeType) NodeId(org.apache.jackrabbit.core.id.NodeId) SessionItemStateManager(org.apache.jackrabbit.core.state.SessionItemStateManager)

Example 4 with ItemState

use of org.apache.jackrabbit.core.state.ItemState 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 5 with ItemState

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

the class ConsistencyCheck method checkIndexConsistency.

private void checkIndexConsistency() throws IOException {
    log.info("Checking index consistency");
    // Ids of multiple nodes in the index
    Set<NodeId> multipleEntries = new HashSet<NodeId>();
    CachingMultiIndexReader reader = index.getIndexReader();
    try {
        for (int i = 0; i < reader.maxDoc(); i++) {
            if (i > 10 && i % (reader.maxDoc() / 5) == 0) {
                long progress = Math.round((100.0 * (float) i) / ((float) reader.maxDoc() * 2f));
                log.info("progress: " + progress + "%");
            }
            if (reader.isDeleted(i)) {
                continue;
            }
            Document d = reader.document(i, FieldSelectors.UUID);
            NodeId id = new NodeId(d.get(FieldNames.UUID));
            if (!isIgnored(id)) {
                boolean nodeExists = nodeIds.containsKey(id);
                if (nodeExists) {
                    Boolean alreadyIndexed = nodeIds.put(id, Boolean.TRUE);
                    if (alreadyIndexed) {
                        multipleEntries.add(id);
                    }
                } else {
                    errors.add(new NodeDeleted(id));
                }
            }
        }
    } finally {
        reader.release();
    }
    // create multiple entries errors
    for (NodeId id : multipleEntries) {
        errors.add(new MultipleEntries(id));
    }
    reader = index.getIndexReader();
    try {
        // run through documents again and check parent
        for (int i = 0; i < reader.maxDoc(); i++) {
            if (i > 10 && i % (reader.maxDoc() / 5) == 0) {
                long progress = Math.round((100.0 * (float) i) / ((float) reader.maxDoc() * 2f));
                log.info("progress: " + (progress + 50) + "%");
            }
            if (reader.isDeleted(i)) {
                continue;
            }
            Document d = reader.document(i, FieldSelectors.UUID_AND_PARENT);
            NodeId id = new NodeId(d.get(FieldNames.UUID));
            if (!nodeIds.containsKey(id) || isIgnored(id)) {
                // this node is ignored or was already marked for deletion
                continue;
            }
            String parent = d.get(FieldNames.PARENT);
            if (parent == null || parent.isEmpty()) {
                continue;
            }
            final NodeId parentId = new NodeId(parent);
            boolean parentExists = nodeIds.containsKey(parentId);
            boolean parentIndexed = parentExists && nodeIds.get(parentId);
            if (parentIndexed) {
                continue;
            } else if (id.equals(RepositoryImpl.SYSTEM_ROOT_NODE_ID) && parentId.equals(RepositoryImpl.ROOT_NODE_ID)) {
                // special case for the /jcr:system node
                continue;
            }
            // parent is missing from index
            if (parentExists) {
                errors.add(new MissingAncestor(id, parentId));
            } else {
                try {
                    final ItemState itemState = stateMgr.getItemState(id);
                    if (parentId.equals(itemState.getParentId())) {
                        // orphaned node
                        errors.add(new UnknownParent(id, parentId));
                    } else {
                        errors.add(new WrongParent(id, parentId, itemState.getParentId()));
                    }
                } catch (ItemStateException ignored) {
                }
            }
        }
    } finally {
        reader.release();
    }
}
Also used : Document(org.apache.lucene.document.Document) NoSuchItemStateException(org.apache.jackrabbit.core.state.NoSuchItemStateException) ItemStateException(org.apache.jackrabbit.core.state.ItemStateException) ItemState(org.apache.jackrabbit.core.state.ItemState) NodeId(org.apache.jackrabbit.core.id.NodeId) HashSet(java.util.HashSet)

Aggregations

ItemState (org.apache.jackrabbit.core.state.ItemState)26 RepositoryException (javax.jcr.RepositoryException)15 NodeId (org.apache.jackrabbit.core.id.NodeId)12 ItemStateException (org.apache.jackrabbit.core.state.ItemStateException)12 NoSuchItemStateException (org.apache.jackrabbit.core.state.NoSuchItemStateException)11 InvalidItemStateException (javax.jcr.InvalidItemStateException)8 ItemNotFoundException (javax.jcr.ItemNotFoundException)8 NodeState (org.apache.jackrabbit.core.state.NodeState)7 ItemId (org.apache.jackrabbit.core.id.ItemId)5 SessionItemStateManager (org.apache.jackrabbit.core.state.SessionItemStateManager)5 HashSet (java.util.HashSet)4 EffectiveNodeType (org.apache.jackrabbit.core.nodetype.EffectiveNodeType)4 ChildNodeEntry (org.apache.jackrabbit.core.state.ChildNodeEntry)4 ConstraintViolationException (javax.jcr.nodetype.ConstraintViolationException)3 PropertyId (org.apache.jackrabbit.core.id.PropertyId)3 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 LinkedHashSet (java.util.LinkedHashSet)2 AccessDeniedException (javax.jcr.AccessDeniedException)2 NodeTypeImpl (org.apache.jackrabbit.core.nodetype.NodeTypeImpl)2