Search in sources :

Example 1 with VersionHistoryInfo

use of org.apache.jackrabbit.core.version.VersionHistoryInfo in project jackrabbit by apache.

the class RepositoryChecker method checkVersionHistory.

private void checkVersionHistory(NodeState node) {
    String message = null;
    NodeId nid = node.getNodeId();
    boolean isVersioned = node.hasPropertyName(JCR_VERSIONHISTORY);
    NodeId vhid = null;
    try {
        String type = isVersioned ? "in-use" : "candidate";
        log.debug("Checking " + type + " version history of node {}", nid);
        String intro = "Removing references to an inconsistent " + type + " version history of node " + nid;
        message = intro + " (getting the VersionInfo)";
        VersionHistoryInfo vhi = versionManager.getVersionHistoryInfoForNode(node);
        if (vhi != null) {
            // get the version history's node ID as early as possible
            // so we can attempt a fixup even when the next call fails
            vhid = vhi.getVersionHistoryId();
        }
        message = intro + " (getting the InternalVersionHistory)";
        InternalVersionHistory vh = null;
        try {
            vh = versionManager.getVersionHistoryOfNode(nid);
        } catch (ItemNotFoundException ex) {
            // it's ok if we get here if the node didn't claim to be versioned
            if (isVersioned) {
                throw ex;
            }
        }
        if (vh == null) {
            if (isVersioned) {
                message = intro + "getVersionHistoryOfNode returned null";
                throw new InconsistentVersioningState(message);
            }
        } else {
            vhid = vh.getId();
            // additional checks, see JCR-3101
            message = intro + " (getting the version names failed)";
            Name[] versionNames = vh.getVersionNames();
            boolean seenRoot = false;
            for (Name versionName : versionNames) {
                seenRoot |= JCR_ROOTVERSION.equals(versionName);
                log.debug("Checking version history of node {}, version {}", nid, versionName);
                message = intro + " (getting version " + versionName + "  failed)";
                InternalVersion v = vh.getVersion(versionName);
                message = intro + "(frozen node of root version " + v.getId() + " missing)";
                if (null == v.getFrozenNode()) {
                    throw new InconsistentVersioningState(message);
                }
            }
            if (!seenRoot) {
                message = intro + " (root version is missing)";
                throw new InconsistentVersioningState(message);
            }
        }
    } catch (InconsistentVersioningState e) {
        log.info(message, e);
        NodeId nvhid = e.getVersionHistoryNodeId();
        if (nvhid != null) {
            if (vhid != null && !nvhid.equals(vhid)) {
                log.error("vhrid returned with InconsistentVersioningState does not match the id we already had: " + vhid + " vs " + nvhid);
            }
            vhid = nvhid;
        }
        removeVersionHistoryReferences(node, vhid);
    } catch (Exception e) {
        log.info(message, e);
        removeVersionHistoryReferences(node, vhid);
    }
}
Also used : VersionHistoryInfo(org.apache.jackrabbit.core.version.VersionHistoryInfo) InconsistentVersioningState(org.apache.jackrabbit.core.version.InconsistentVersioningState) NodeId(org.apache.jackrabbit.core.id.NodeId) InternalVersionHistory(org.apache.jackrabbit.core.version.InternalVersionHistory) RepositoryException(javax.jcr.RepositoryException) ItemStateException(org.apache.jackrabbit.core.state.ItemStateException) ItemNotFoundException(javax.jcr.ItemNotFoundException) ItemNotFoundException(javax.jcr.ItemNotFoundException) Name(org.apache.jackrabbit.spi.Name) InternalVersion(org.apache.jackrabbit.core.version.InternalVersion)

Example 2 with VersionHistoryInfo

use of org.apache.jackrabbit.core.version.VersionHistoryInfo in project jackrabbit by apache.

the class BatchedItemOperations method copyNodeState.

/**
 * Recursively copies the specified node state including its properties and
 * child nodes.
 *
 * @param srcState
 * @param srcPath
 * @param srcStateMgr
 * @param srcAccessMgr
 * @param destParentId
 * @param flag           one of
 *                       <ul>
 *                       <li><code>COPY</code></li>
 *                       <li><code>CLONE</code></li>
 *                       <li><code>CLONE_REMOVE_EXISTING</code></li>
 *                       </ul>
 * @param refTracker     tracks uuid mappings and processed reference properties
 * @return a deep copy of the given node state and its children
 * @throws RepositoryException if an error occurs
 */
private NodeState copyNodeState(NodeState srcState, Path srcPath, ItemStateManager srcStateMgr, AccessManager srcAccessMgr, NodeId destParentId, int flag, ReferenceChangeTracker refTracker) throws RepositoryException {
    NodeState newState;
    try {
        NodeId id = null;
        EffectiveNodeType ent = getEffectiveNodeType(srcState);
        boolean referenceable = ent.includesNodeType(NameConstants.MIX_REFERENCEABLE);
        boolean versionable = ent.includesNodeType(NameConstants.MIX_SIMPLE_VERSIONABLE);
        boolean fullVersionable = ent.includesNodeType(NameConstants.MIX_VERSIONABLE);
        boolean shareable = ent.includesNodeType(NameConstants.MIX_SHAREABLE);
        switch(flag) {
            case COPY:
                /* if this node is shareable and another node in the same shared set
                     * has been already been copied and given a new uuid, use this one
                     * (see section 14.5 of the specification)
                     */
                if (shareable && refTracker.getMappedId(srcState.getNodeId()) != null) {
                    NodeId newId = refTracker.getMappedId(srcState.getNodeId());
                    NodeState sharedState = (NodeState) stateMgr.getItemState(newId);
                    sharedState.addShare(destParentId);
                    return sharedState;
                }
                break;
            case CLONE:
                if (!referenceable) {
                    // non-referenceable node: always create new node id
                    break;
                }
                // use same uuid as source node
                id = srcState.getNodeId();
                if (stateMgr.hasItemState(id)) {
                    if (shareable) {
                        NodeState sharedState = (NodeState) stateMgr.getItemState(id);
                        sharedState.addShare(destParentId);
                        return sharedState;
                    }
                    // node with this uuid already exists
                    throw new ItemExistsException(safeGetJCRPath(id));
                }
                break;
            case CLONE_REMOVE_EXISTING:
                if (!referenceable) {
                    // non-referenceable node: always create new node id
                    break;
                }
                // use same uuid as source node
                id = srcState.getNodeId();
                if (stateMgr.hasItemState(id)) {
                    NodeState existingState = (NodeState) stateMgr.getItemState(id);
                    // or an ancestor thereof
                    if (id.equals(destParentId) || hierMgr.isAncestor(id, destParentId)) {
                        String msg = "cannot remove node " + safeGetJCRPath(srcPath) + " because it is an ancestor of the destination";
                        log.debug(msg);
                        throw new RepositoryException(msg);
                    }
                    // check if existing can be removed
                    // (access rights, locking & versioning status,
                    // node type constraints and retention/hold)
                    checkRemoveNode(existingState, CHECK_ACCESS | CHECK_LOCK | CHECK_CHECKED_OUT | CHECK_CONSTRAINTS | CHECK_HOLD | CHECK_RETENTION);
                    // do remove existing
                    removeNodeState(existingState);
                }
                break;
            default:
                throw new IllegalArgumentException("unknown flag for copying node state: " + flag);
        }
        newState = stateMgr.createNew(id, srcState.getNodeTypeName(), destParentId);
        id = newState.getNodeId();
        if (flag == COPY && referenceable) {
            // remember uuid mapping
            refTracker.mappedId(srcState.getNodeId(), id);
        }
        // copy node state
        newState.setMixinTypeNames(srcState.getMixinTypeNames());
        if (shareable) {
            // initialize shared set
            newState.addShare(destParentId);
        }
        // copy child nodes
        for (ChildNodeEntry entry : srcState.getChildNodeEntries()) {
            Path srcChildPath = PathFactoryImpl.getInstance().create(srcPath, entry.getName(), true);
            if (!srcAccessMgr.isGranted(srcChildPath, Permission.READ)) {
                continue;
            }
            NodeId nodeId = entry.getId();
            NodeState srcChildState = (NodeState) srcStateMgr.getItemState(nodeId);
            /**
             * If child is shareble and its UUID has already been remapped,
             * then simply add a reference to the state with that remapped
             * UUID instead of copying the whole subtree.
             */
            if (srcChildState.isShareable()) {
                NodeId mappedId = refTracker.getMappedId(srcChildState.getNodeId());
                if (mappedId != null) {
                    if (stateMgr.hasItemState(mappedId)) {
                        NodeState destState = (NodeState) stateMgr.getItemState(mappedId);
                        if (!destState.isShareable()) {
                            String msg = "Remapped child (" + safeGetJCRPath(srcPath) + ") is not shareable.";
                            throw new ItemStateException(msg);
                        }
                        if (!destState.addShare(id)) {
                            String msg = "Unable to add share to node: " + id;
                            throw new ItemStateException(msg);
                        }
                        stateMgr.store(destState);
                        newState.addChildNodeEntry(entry.getName(), mappedId);
                        continue;
                    }
                }
            }
            // recursive copying of child node
            NodeState newChildState = copyNodeState(srcChildState, srcChildPath, srcStateMgr, srcAccessMgr, id, flag, refTracker);
            // store new child node
            stateMgr.store(newChildState);
            // add new child node entry to new node
            newState.addChildNodeEntry(entry.getName(), newChildState.getNodeId());
        }
        // init version history if needed
        VersionHistoryInfo history = null;
        if (versionable && flag == COPY) {
            NodeId copiedFrom = null;
            if (fullVersionable) {
                // base version of copied versionable node is reference value of
                // the histories jcr:copiedFrom property
                PropertyId propId = new PropertyId(srcState.getNodeId(), NameConstants.JCR_BASEVERSION);
                PropertyState prop = (PropertyState) srcStateMgr.getItemState(propId);
                copiedFrom = prop.getValues()[0].getNodeId();
            }
            InternalVersionManager manager = session.getInternalVersionManager();
            history = manager.getVersionHistory(session, newState, copiedFrom);
        }
        // copy properties
        for (Name propName : srcState.getPropertyNames()) {
            Path propPath = PathFactoryImpl.getInstance().create(srcPath, propName, true);
            PropertyId propId = new PropertyId(srcState.getNodeId(), propName);
            if (!srcAccessMgr.canRead(propPath, propId)) {
                continue;
            }
            PropertyState srcChildState = (PropertyState) srcStateMgr.getItemState(propId);
            /**
             * special handling required for properties with special semantics
             * (e.g. those defined by mix:referenceable, mix:versionable,
             * mix:lockable, et.al.)
             *
             * todo FIXME delegate to 'node type instance handler'
             */
            QPropertyDefinition def = ent.getApplicablePropertyDef(srcChildState.getName(), srcChildState.getType(), srcChildState.isMultiValued());
            if (NameConstants.MIX_LOCKABLE.equals(def.getDeclaringNodeType())) {
                // skip properties defined by mix:lockable
                continue;
            }
            PropertyState newChildState = copyPropertyState(srcChildState, id, propName, def);
            if (history != null) {
                if (fullVersionable) {
                    if (propName.equals(NameConstants.JCR_VERSIONHISTORY)) {
                        // jcr:versionHistory
                        InternalValue value = InternalValue.create(history.getVersionHistoryId());
                        newChildState.setValues(new InternalValue[] { value });
                    } else if (propName.equals(NameConstants.JCR_BASEVERSION) || propName.equals(NameConstants.JCR_PREDECESSORS)) {
                        // jcr:baseVersion or jcr:predecessors
                        InternalValue value = InternalValue.create(history.getRootVersionId());
                        newChildState.setValues(new InternalValue[] { value });
                    } else if (propName.equals(NameConstants.JCR_ISCHECKEDOUT)) {
                        // jcr:isCheckedOut
                        newChildState.setValues(new InternalValue[] { InternalValue.create(true) });
                    }
                } else {
                    // version history when we see the jcr:isCheckedOut
                    if (propName.equals(NameConstants.JCR_ISCHECKEDOUT)) {
                        // jcr:isCheckedOut
                        newChildState.setValues(new InternalValue[] { InternalValue.create(true) });
                    }
                }
            }
            if (newChildState.getType() == PropertyType.REFERENCE || newChildState.getType() == PropertyType.WEAKREFERENCE) {
                refTracker.processedReference(newChildState);
            }
            // store new property
            stateMgr.store(newChildState);
            // add new property entry to new node
            newState.addPropertyName(propName);
        }
        return newState;
    } catch (ItemStateException ise) {
        String msg = "internal error: failed to copy state of " + srcState.getNodeId();
        log.debug(msg);
        throw new RepositoryException(msg, ise);
    }
}
Also used : Path(org.apache.jackrabbit.spi.Path) VersionHistoryInfo(org.apache.jackrabbit.core.version.VersionHistoryInfo) NodeState(org.apache.jackrabbit.core.state.NodeState) ChildNodeEntry(org.apache.jackrabbit.core.state.ChildNodeEntry) RepositoryException(javax.jcr.RepositoryException) InternalValue(org.apache.jackrabbit.core.value.InternalValue) NoSuchItemStateException(org.apache.jackrabbit.core.state.NoSuchItemStateException) ItemStateException(org.apache.jackrabbit.core.state.ItemStateException) PropertyId(org.apache.jackrabbit.core.id.PropertyId) PropertyState(org.apache.jackrabbit.core.state.PropertyState) Name(org.apache.jackrabbit.spi.Name) EffectiveNodeType(org.apache.jackrabbit.core.nodetype.EffectiveNodeType) ItemExistsException(javax.jcr.ItemExistsException) QPropertyDefinition(org.apache.jackrabbit.spi.QPropertyDefinition) NodeId(org.apache.jackrabbit.core.id.NodeId) InternalVersionManager(org.apache.jackrabbit.core.version.InternalVersionManager)

Example 3 with VersionHistoryInfo

use of org.apache.jackrabbit.core.version.VersionHistoryInfo in project jackrabbit by apache.

the class WorkspaceImporter method postProcessNode.

/**
 * Post-process imported node (initialize properties with special
 * semantics etc.)
 *
 * @param node the node state
 * @throws RepositoryException if an error occurs
 */
protected void postProcessNode(NodeState node) throws RepositoryException {
    /**
     * special handling required for properties with special semantics
     * (e.g. those defined by mix:referenceable, mix:versionable,
     * mix:lockable, et.al.)
     *
     * todo FIXME delegate to 'node type instance handler'
     */
    EffectiveNodeType ent = itemOps.getEffectiveNodeType(node);
    if (ent.includesNodeType(NameConstants.MIX_SIMPLE_VERSIONABLE)) {
        /**
         * check if there's already a version history for that
         * node; this would e.g. be the case if a versionable node
         * had been exported, removed and re-imported with either
         * IMPORT_UUID_COLLISION_REMOVE_EXISTING or
         * IMPORT_UUID_COLLISION_REPLACE_EXISTING;
         * otherwise create a new version history
         */
        VersionHistoryInfo history = versionManager.getVersionHistory(session, node, null);
        InternalValue historyId = InternalValue.create(history.getVersionHistoryId());
        InternalValue versionId = InternalValue.create(history.getRootVersionId());
        // jcr:isCheckedOut
        conditionalAddProperty(node, NameConstants.JCR_ISCHECKEDOUT, PropertyType.BOOLEAN, false, InternalValue.create(true));
        // set extra properties only for full versionable nodes
        if (ent.includesNodeType(NameConstants.MIX_VERSIONABLE)) {
            // jcr:versionHistory
            conditionalAddProperty(node, NameConstants.JCR_VERSIONHISTORY, PropertyType.REFERENCE, false, historyId);
            // jcr:baseVersion
            conditionalAddProperty(node, NameConstants.JCR_BASEVERSION, PropertyType.REFERENCE, false, versionId);
            // jcr:predecessors
            conditionalAddProperty(node, NameConstants.JCR_PREDECESSORS, PropertyType.REFERENCE, true, versionId);
        }
    }
}
Also used : EffectiveNodeType(org.apache.jackrabbit.core.nodetype.EffectiveNodeType) VersionHistoryInfo(org.apache.jackrabbit.core.version.VersionHistoryInfo) InternalValue(org.apache.jackrabbit.core.value.InternalValue)

Example 4 with VersionHistoryInfo

use of org.apache.jackrabbit.core.version.VersionHistoryInfo in project jackrabbit by apache.

the class ItemSaveOperation method initVersionHistories.

/**
 * Initialises the version history of all new nodes of node type
 * <code>mix:versionable</code>.
 *
 * @param states
 * @return true if this call generated new transient state; otherwise false
 * @throws RepositoryException
 */
private boolean initVersionHistories(SessionContext context, Iterable<ItemState> states) throws RepositoryException {
    SessionImpl session = context.getSessionImpl();
    ItemManager itemMgr = context.getItemManager();
    // walk through list of transient items and search for new versionable nodes
    boolean createdTransientState = false;
    for (ItemState itemState : states) {
        if (itemState.isNode()) {
            NodeState nodeState = (NodeState) itemState;
            EffectiveNodeType nt = getEffectiveNodeType(context.getRepositoryContext().getNodeTypeRegistry(), nodeState);
            if (nt.includesNodeType(NameConstants.MIX_VERSIONABLE)) {
                if (!nodeState.hasPropertyName(NameConstants.JCR_VERSIONHISTORY)) {
                    NodeImpl node = (NodeImpl) itemMgr.getItem(itemState.getId(), false);
                    InternalVersionManager vMgr = session.getInternalVersionManager();
                    /**
                     * check if there's already a version history for that
                     * node; this would e.g. be the case if a versionable
                     * node had been exported, removed and re-imported with
                     * either IMPORT_UUID_COLLISION_REMOVE_EXISTING or
                     * IMPORT_UUID_COLLISION_REPLACE_EXISTING;
                     * otherwise create a new version history
                     */
                    VersionHistoryInfo history = vMgr.getVersionHistory(session, nodeState, null);
                    InternalValue historyId = InternalValue.create(history.getVersionHistoryId());
                    InternalValue versionId = InternalValue.create(history.getRootVersionId());
                    node.internalSetProperty(NameConstants.JCR_VERSIONHISTORY, historyId);
                    node.internalSetProperty(NameConstants.JCR_BASEVERSION, versionId);
                    node.internalSetProperty(NameConstants.JCR_ISCHECKEDOUT, InternalValue.create(true));
                    node.internalSetProperty(NameConstants.JCR_PREDECESSORS, new InternalValue[] { versionId });
                    createdTransientState = true;
                }
            } else if (nt.includesNodeType(NameConstants.MIX_SIMPLE_VERSIONABLE)) {
                // we need to check the version manager for an existing
                // version history, since simple versioning does not
                // expose it's reference in a property
                InternalVersionManager vMgr = session.getInternalVersionManager();
                vMgr.getVersionHistory(session, nodeState, null);
                // create isCheckedOutProperty if not already exists
                NodeImpl node = (NodeImpl) itemMgr.getItem(itemState.getId(), false);
                if (!nodeState.hasPropertyName(NameConstants.JCR_ISCHECKEDOUT)) {
                    node.internalSetProperty(NameConstants.JCR_ISCHECKEDOUT, InternalValue.create(true));
                    createdTransientState = true;
                }
            }
        }
    }
    return createdTransientState;
}
Also used : EffectiveNodeType(org.apache.jackrabbit.core.nodetype.EffectiveNodeType) VersionHistoryInfo(org.apache.jackrabbit.core.version.VersionHistoryInfo) NodeState(org.apache.jackrabbit.core.state.NodeState) ItemState(org.apache.jackrabbit.core.state.ItemState) InternalValue(org.apache.jackrabbit.core.value.InternalValue) InternalVersionManager(org.apache.jackrabbit.core.version.InternalVersionManager)

Aggregations

VersionHistoryInfo (org.apache.jackrabbit.core.version.VersionHistoryInfo)4 EffectiveNodeType (org.apache.jackrabbit.core.nodetype.EffectiveNodeType)3 InternalValue (org.apache.jackrabbit.core.value.InternalValue)3 RepositoryException (javax.jcr.RepositoryException)2 NodeId (org.apache.jackrabbit.core.id.NodeId)2 ItemStateException (org.apache.jackrabbit.core.state.ItemStateException)2 NodeState (org.apache.jackrabbit.core.state.NodeState)2 InternalVersionManager (org.apache.jackrabbit.core.version.InternalVersionManager)2 Name (org.apache.jackrabbit.spi.Name)2 ItemExistsException (javax.jcr.ItemExistsException)1 ItemNotFoundException (javax.jcr.ItemNotFoundException)1 PropertyId (org.apache.jackrabbit.core.id.PropertyId)1 ChildNodeEntry (org.apache.jackrabbit.core.state.ChildNodeEntry)1 ItemState (org.apache.jackrabbit.core.state.ItemState)1 NoSuchItemStateException (org.apache.jackrabbit.core.state.NoSuchItemStateException)1 PropertyState (org.apache.jackrabbit.core.state.PropertyState)1 InconsistentVersioningState (org.apache.jackrabbit.core.version.InconsistentVersioningState)1 InternalVersion (org.apache.jackrabbit.core.version.InternalVersion)1 InternalVersionHistory (org.apache.jackrabbit.core.version.InternalVersionHistory)1 Path (org.apache.jackrabbit.spi.Path)1