Search in sources :

Example 1 with QPropertyDefinition

use of org.apache.jackrabbit.spi.QPropertyDefinition in project jackrabbit by apache.

the class VersionManagerImplRestore method internalRestoreFrozen.

/**
     * Restores the properties and child nodes from the frozen state.
     *
     * @param state state to restore
     * @param freeze the frozen node
     * @param vsel version selector
     * @param restored set of restored versions
     * @param removeExisting remove existing flag
     * @param copy if <code>true</code> a pure copy is performed
     * @throws RepositoryException if an error occurs
     * @throws ItemStateException if an error occurs
     */
protected void internalRestoreFrozen(NodeStateEx state, InternalFrozenNode freeze, VersionSelector vsel, Set<InternalVersion> restored, boolean removeExisting, boolean copy) throws RepositoryException, ItemStateException {
    // check uuid
    if (state.getEffectiveNodeType().includesNodeType(NameConstants.MIX_REFERENCEABLE)) {
        if (!state.getNodeId().equals(freeze.getFrozenId())) {
            String msg = "Unable to restore version of " + safeGetJCRPath(state) + ". UUID changed.";
            log.error(msg);
            throw new ItemExistsException(msg);
        }
    }
    // check primary type
    if (!freeze.getFrozenPrimaryType().equals(state.getState().getNodeTypeName())) {
        // todo: implement
        String msg = "Unable to restore version of " + safeGetJCRPath(state) + ". PrimaryType change not supported yet.";
        log.error(msg);
        throw new UnsupportedRepositoryOperationException(msg);
    }
    // adjust mixins
    state.setMixins(freeze.getFrozenMixinTypes());
    // For each property P present on F (other than jcr:frozenPrimaryType,
    // jcr:frozenMixinTypes and jcr:frozenUuid): 
    // - If P has an OPV of COPY or VERSION then F/P is copied to N/P,
    //   replacing any existing N/P.
    // - F will never have a property with an OPV of IGNORE, INITIALIZE, COMPUTE
    //   or ABORT (see 15.2 Check-In: Creating a Version).
    Set<Name> propNames = new HashSet<Name>();
    PropertyState[] props = freeze.getFrozenProperties();
    for (PropertyState prop : props) {
        // don't restore jcr:activity
        Name name = prop.getName();
        if (!name.equals(NameConstants.JCR_ACTIVITY)) {
            state.copyFrom(prop);
            propNames.add(name);
        }
    }
    // remove properties that do not exist in the frozen representation
    for (PropertyState prop : state.getProperties()) {
        Name propName = prop.getName();
        if (!propNames.contains(propName)) {
            int opv = state.getDefinition(prop).getOnParentVersion();
            if (opv == OnParentVersionAction.COPY || opv == OnParentVersionAction.VERSION || opv == OnParentVersionAction.ABORT) {
                state.removeProperty(propName);
            } else if (opv == OnParentVersionAction.INITIALIZE) {
                InternalValue[] values = computeAutoValues(state, state.getDefinition(prop), true);
                if (values != null) {
                    state.setPropertyValues(propName, prop.getType(), values, prop.isMultiValued());
                }
            } else if (opv == OnParentVersionAction.COMPUTE) {
                InternalValue[] values = computeAutoValues(state, state.getDefinition(prop), false);
                if (values != null) {
                    state.setPropertyValues(propName, prop.getType(), values, prop.isMultiValued());
                }
            }
        }
    }
    // add 'auto-create' properties that do not exist yet
    for (QPropertyDefinition def : state.getEffectiveNodeType().getAutoCreatePropDefs()) {
        if (!state.hasProperty(def.getName())) {
            InternalValue[] values = computeAutoValues(state, def, true);
            if (values != null) {
                state.setPropertyValues(def.getName(), def.getRequiredType(), values, def.isMultiple());
            }
        }
    }
    // For each child node C present on N but not on F:
    // - If C has an OPV of COPY, VERSION or ABORT then N/C is removed.
    //   Note that while a node with a child item of OPV ABORT cannot be
    //   versioned, it is legal for a previously versioned node to have such
    //   a child item added to it and then for it to be restored to the state
    //   that it had before that item was added, as this step indicates.
    // - If C has an OPV of IGNORE then no change is made to N/C.
    // - If C has an OPV of INITIALIZE then N/C is re-initialized as if it
    //   were newly created, as defined in its node type.
    // - If C has an OPV of COMPUTE then N/C may be re-initialized according
    //   to an implementation-specific mechanism.
    LinkedList<ChildNodeEntry> toDelete = new LinkedList<ChildNodeEntry>();
    for (ChildNodeEntry entry : state.getState().getChildNodeEntries()) {
        if (!freeze.hasFrozenChildNode(entry.getName(), entry.getIndex())) {
            NodeStateEx child = state.getNode(entry.getName(), entry.getIndex());
            int opv = child.getDefinition().getOnParentVersion();
            if (copy || opv == OnParentVersionAction.COPY || opv == OnParentVersionAction.VERSION || opv == OnParentVersionAction.ABORT) {
                toDelete.addFirst(entry);
            } else if (opv == OnParentVersionAction.INITIALIZE) {
                log.warn("OPV.INITIALIZE not supported yet on restore of existing child nodes: " + safeGetJCRPath(child));
            } else if (opv == OnParentVersionAction.COMPUTE) {
                log.warn("OPV.COMPUTE not supported yet on restore of existing child nodes: " + safeGetJCRPath(child));
            }
        }
    }
    for (ChildNodeEntry entry : toDelete) {
        state.removeNode(entry.getName(), entry.getIndex());
    }
    // need to sync with state manager
    state.store();
    // create a map that contains a int->NodeStateEx mapping for each child name
    Map<Name, Map<Integer, NodeStateEx>> entryToNodeStateExMapping = new HashMap<Name, Map<Integer, NodeStateEx>>();
    for (ChildNodeEntry entry : state.getState().getChildNodeEntries()) {
        Map<Integer, NodeStateEx> id2stateMap = entryToNodeStateExMapping.get(entry.getName());
        if (id2stateMap == null) {
            id2stateMap = new HashMap<Integer, NodeStateEx>();
        }
        id2stateMap.put(entry.getIndex(), state.getNode(entry.getName(), entry.getIndex()));
        entryToNodeStateExMapping.put(entry.getName(), id2stateMap);
    }
    //   COMPUTE or ABORT (see 15.2 Check-In: Creating a Version).
    for (ChildNodeEntry entry : freeze.getFrozenChildNodes()) {
        InternalFreeze child = freeze.getFrozenChildNode(entry.getName(), entry.getIndex());
        NodeStateEx restoredChild = null;
        if (child instanceof InternalFrozenNode) {
            // - If C has an OPV of COPY or VERSION:
            //   - B is true, then F/C and its subgraph is copied to N/C, replacing
            //     any existing N/C and its subgraph and any node in the workspace
            //     with the same identifier as C or a node in the subgraph of C is
            //     removed.
            //   - B is false, then F/C and its subgraph is copied to N/C, replacing
            //     any existing N/C and its subgraph unless there exists a node in the
            //     workspace with the same identifier as C, or a node in the subgraph
            //     of C, in which case an ItemExistsException is thrown , all
            //     changes made by the restore are rolled back leaving N unchanged.
            InternalFrozenNode f = (InternalFrozenNode) child;
            // if node is present, remove it
            Map<Integer, NodeStateEx> id2stateMap = entryToNodeStateExMapping.get(entry.getName());
            if (id2stateMap != null && id2stateMap.containsKey(entry.getIndex())) {
                state.removeNode(id2stateMap.get(entry.getIndex()));
            }
            // check for existing
            if (f.getFrozenId() != null) {
                if (stateMgr.hasItemState(f.getFrozenId())) {
                    NodeStateEx existing = state.getNode(f.getFrozenId());
                    if (removeExisting) {
                        NodeStateEx parent = existing.getParent();
                        parent.removeNode(existing);
                        parent.store();
                    } else if (existing.getState().isShareable()) {
                        // if existing node is shareable, then clone it
                        restoredChild = state.moveFrom(existing, existing.getName(), true);
                    } else if (!existing.hasAncestor(state.getNodeId())) {
                        String msg = "Unable to restore node, item already exists " + "outside of restored tree: " + safeGetJCRPath(existing);
                        log.error(msg);
                        throw new ItemExistsException(msg);
                    }
                }
            }
            if (restoredChild == null) {
                restoredChild = state.addNode(f.getName(), f.getFrozenPrimaryType(), f.getFrozenId());
                restoredChild.setMixins(f.getFrozenMixinTypes());
            }
            internalRestoreFrozen(restoredChild, f, vsel, restored, removeExisting, true);
        } else if (child instanceof InternalFrozenVersionHistory) {
            //   Each child node C of N where C has an OPV of VERSION and C is
            //   mix:versionable, is represented in F not as a copy of N/C but as
            //   special node containing a reference to the version history of
            //   C. On restore, the following occurs:
            //   - If the workspace currently has an already existing node corresponding
            //     to C's version history and the removeExisting flag of the restore is
            //     set to true, then that instance of C becomes the child of the restored N.
            //   - If the workspace currently has an already existing node corresponding
            //     to C's version history and the removeExisting flag of the restore is
            //     set to false then an ItemExistsException is thrown.
            //   - If the workspace does not have an instance of C then one is restored from
            //     C's version history:
            //     - If the restore was initiated through a restoreByLabel where L is
            //       the specified label and there is a version of C with the label L then
            //       that version is restored.
            //     - If the version history of C does not contain a version with the label
            //       L or the restore was initiated by a method call that does not specify
            //       a label then the workspace in which the restore is being performed
            //       will determine which particular version of C will be restored. This
            //       determination depends on the configuration of the workspace and
            //       is outside the scope of this specification.
            InternalFrozenVersionHistory fh = (InternalFrozenVersionHistory) child;
            InternalVersionHistory vh = vMgr.getVersionHistory(fh.getVersionHistoryId());
            // get desired version from version selector
            InternalVersion v = vsel.select(vh);
            Name oldVersion = null;
            // check if representing versionable already exists somewhere
            NodeId nodeId = vh.getVersionableId();
            if (stateMgr.hasItemState(nodeId)) {
                restoredChild = state.getNode(nodeId);
                if (restoredChild.getParentId().equals(state.getNodeId())) {
                // if same parent, ignore
                } else if (removeExisting) {
                    NodeStateEx parent = restoredChild.getNode(restoredChild.getParentId());
                    state.moveFrom(restoredChild, fh.getName(), false);
                    parent.store();
                    // get old version name
                    oldVersion = getBaseVersion(restoredChild).getName();
                } else {
                    // since we delete the OPV=Copy children beforehand, all
                    // found nodes must be outside of this tree
                    String msg = "Unable to restore node, item already exists " + "outside of restored tree: " + safeGetJCRPath(restoredChild);
                    log.error(msg);
                    throw new ItemExistsException(msg);
                }
            }
            // check existing version of item exists
            if (restoredChild == null) {
                if (v == null) {
                    // if version selector was unable to select version,
                    // choose the initial one
                    List<InternalVersion> vs = vh.getRootVersion().getSuccessors();
                    if (vs.isEmpty()) {
                        String msg = "Unable to select appropriate version for " + child.getName() + " using " + vsel;
                        log.error(msg);
                        throw new VersionException(msg);
                    }
                    v = vs.get(0);
                }
                InternalFrozenNode f = v.getFrozenNode();
                restoredChild = state.addNode(fh.getName(), f.getFrozenPrimaryType(), f.getFrozenId());
                restoredChild.setMixins(f.getFrozenMixinTypes());
            } else {
                if (v == null || oldVersion == null || v.getName().equals(oldVersion)) {
                    v = null;
                }
            }
            if (v != null) {
                try {
                    internalRestore(restoredChild, v, vsel, removeExisting);
                } catch (RepositoryException e) {
                    log.error("Error while restoring node: " + e);
                    log.error("  child path: " + restoredChild);
                    log.error("  selected version: " + v.getName());
                    StringBuilder avail = new StringBuilder();
                    for (Name name : vh.getVersionNames()) {
                        avail.append(name);
                        avail.append(", ");
                    }
                    log.error("  available versions: " + avail);
                    log.error("  versionselector: " + vsel);
                    throw e;
                }
                // add this version to set
                restored.add(v);
            }
        }
        if (restoredChild != null && state.getEffectiveNodeType().hasOrderableChildNodes()) {
            //   In a repository that supports orderable child nodes, the relative
            //   ordering of the set of child nodes C that are copied from F is
            //   preserved.
            // order at end
            ArrayList<ChildNodeEntry> list = new ArrayList<ChildNodeEntry>(state.getState().getChildNodeEntries());
            ChildNodeEntry toReorder = null;
            boolean isLast = true;
            for (ChildNodeEntry e : list) {
                if (e.getId().equals(restoredChild.getNodeId())) {
                    toReorder = e;
                } else if (toReorder != null) {
                    isLast = false;
                }
            }
            if (toReorder != null && !isLast) {
                list.remove(toReorder);
                list.add(toReorder);
                state.getState().setChildNodeEntries(list);
            }
        }
    }
}
Also used : UnsupportedRepositoryOperationException(javax.jcr.UnsupportedRepositoryOperationException) Name(org.apache.jackrabbit.spi.Name) QPropertyDefinition(org.apache.jackrabbit.spi.QPropertyDefinition) ChildNodeEntry(org.apache.jackrabbit.core.state.ChildNodeEntry) RepositoryException(javax.jcr.RepositoryException) InternalValue(org.apache.jackrabbit.core.value.InternalValue) PropertyState(org.apache.jackrabbit.core.state.PropertyState) ItemExistsException(javax.jcr.ItemExistsException) NodeId(org.apache.jackrabbit.core.id.NodeId) VersionException(javax.jcr.version.VersionException)

Example 2 with QPropertyDefinition

use of org.apache.jackrabbit.spi.QPropertyDefinition in project jackrabbit by apache.

the class WorkspaceImporter method conditionalAddProperty.

/**
     * Adds the the given property to a node unless the property already
     * exists.
     *
     * @param node the node to which the property is added
     * @param name name of the property
     * @param type property type (see {@link PropertyType})
     * @param multiple whether the property is multivalued
     * @param value initial value of the property, if it needs to be added
     * @throws RepositoryException if the property could not be added
     */
private void conditionalAddProperty(NodeState node, Name name, int type, boolean multiple, InternalValue value) throws RepositoryException {
    if (!node.hasPropertyName(name)) {
        QPropertyDefinition def = itemOps.findApplicablePropertyDefinition(name, type, multiple, node);
        PropertyState prop = itemOps.createPropertyState(node, name, type, def);
        prop.setValues(new InternalValue[] { value });
    }
}
Also used : QPropertyDefinition(org.apache.jackrabbit.spi.QPropertyDefinition) PropertyState(org.apache.jackrabbit.core.state.PropertyState)

Example 3 with QPropertyDefinition

use of org.apache.jackrabbit.spi.QPropertyDefinition in project jackrabbit by apache.

the class NodeTypeRegistryImpl method getEffectiveNodeType.

/**
     * @see EffectiveNodeTypeProvider#getEffectiveNodeType(QNodeTypeDefinition, Map)
     */
public EffectiveNodeType getEffectiveNodeType(QNodeTypeDefinition ntd, Map<Name, QNodeTypeDefinition> ntdMap) throws ConstraintViolationException, NoSuchNodeTypeException {
    TreeSet<Name> mergedNodeTypes = new TreeSet<Name>();
    TreeSet<Name> inheritedNodeTypes = new TreeSet<Name>();
    TreeSet<Name> allNodeTypes = new TreeSet<Name>();
    Map<Name, List<QItemDefinition>> namedItemDefs = new HashMap<Name, List<QItemDefinition>>();
    List<QItemDefinition> unnamedItemDefs = new ArrayList<QItemDefinition>();
    Set<Name> supportedMixins = null;
    Name ntName = ntd.getName();
    // prepare new instance
    mergedNodeTypes.add(ntName);
    allNodeTypes.add(ntName);
    Name[] smixins = ntd.getSupportedMixinTypes();
    if (smixins != null) {
        supportedMixins = new HashSet<Name>();
        supportedMixins.addAll(Arrays.asList(smixins));
    }
    // map of all item definitions (maps id to definition)
    // used to effectively detect ambiguous child definitions where
    // ambiguity is defined in terms of definition identity
    Set<QItemDefinition> itemDefIds = new HashSet<QItemDefinition>();
    for (QNodeDefinition nd : ntd.getChildNodeDefs()) {
        // this node type definition
        if (itemDefIds.contains(nd)) {
            // conflict
            String msg;
            if (nd.definesResidual()) {
                msg = ntName + " contains ambiguous residual child node definitions";
            } else {
                msg = ntName + " contains ambiguous definitions for child node named " + nd.getName();
            }
            log.debug(msg);
            throw new ConstraintViolationException(msg);
        } else {
            itemDefIds.add(nd);
        }
        if (nd.definesResidual()) {
            // residual node definition
            unnamedItemDefs.add(nd);
        } else {
            // named node definition
            Name name = nd.getName();
            List<QItemDefinition> defs = namedItemDefs.get(name);
            if (defs == null) {
                defs = new ArrayList<QItemDefinition>();
                namedItemDefs.put(name, defs);
            }
            if (defs.size() > 0) {
                /**
                     * there already exists at least one definition with that
                     * name; make sure none of them is auto-create
                     */
                for (QItemDefinition qDef : defs) {
                    if (nd.isAutoCreated() || qDef.isAutoCreated()) {
                        // conflict
                        String msg = "There are more than one 'auto-create' item definitions for '" + name + "' in node type '" + ntName + "'";
                        log.debug(msg);
                        throw new ConstraintViolationException(msg);
                    }
                }
            }
            defs.add(nd);
        }
    }
    for (QPropertyDefinition pd : ntd.getPropertyDefs()) {
        // this node type definition
        if (itemDefIds.contains(pd)) {
            // conflict
            String msg;
            if (pd.definesResidual()) {
                msg = ntName + " contains ambiguous residual property definitions";
            } else {
                msg = ntName + " contains ambiguous definitions for property named " + pd.getName();
            }
            log.debug(msg);
            throw new ConstraintViolationException(msg);
        } else {
            itemDefIds.add(pd);
        }
        if (pd.definesResidual()) {
            // residual property definition
            unnamedItemDefs.add(pd);
        } else {
            // named property definition
            Name name = pd.getName();
            List<QItemDefinition> defs = namedItemDefs.get(name);
            if (defs == null) {
                defs = new ArrayList<QItemDefinition>();
                namedItemDefs.put(name, defs);
            }
            if (defs.size() > 0) {
                /**
                     * there already exists at least one definition with that
                     * name; make sure none of them is auto-create
                     */
                for (QItemDefinition qDef : defs) {
                    if (pd.isAutoCreated() || qDef.isAutoCreated()) {
                        // conflict
                        String msg = "There are more than one 'auto-create' item definitions for '" + name + "' in node type '" + ntName + "'";
                        log.debug(msg);
                        throw new ConstraintViolationException(msg);
                    }
                }
            }
            defs.add(pd);
        }
    }
    // create empty effective node type instance
    EffectiveNodeTypeImpl ent = new EffectiveNodeTypeImpl(mergedNodeTypes, inheritedNodeTypes, allNodeTypes, namedItemDefs, unnamedItemDefs, supportedMixins);
    // resolve supertypes recursively
    Name[] supertypes = ntd.getSupertypes();
    if (supertypes.length > 0) {
        EffectiveNodeTypeImpl effSuperType = (EffectiveNodeTypeImpl) getEffectiveNodeType(supertypes, ntdMap);
        ent.internalMerge(effSuperType, true);
    }
    return ent;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) QItemDefinition(org.apache.jackrabbit.spi.QItemDefinition) QNodeDefinition(org.apache.jackrabbit.spi.QNodeDefinition) Name(org.apache.jackrabbit.spi.Name) TreeSet(java.util.TreeSet) QPropertyDefinition(org.apache.jackrabbit.spi.QPropertyDefinition) ConstraintViolationException(javax.jcr.nodetype.ConstraintViolationException) ArrayList(java.util.ArrayList) List(java.util.List) HashSet(java.util.HashSet)

Example 4 with QPropertyDefinition

use of org.apache.jackrabbit.spi.QPropertyDefinition in project jackrabbit by apache.

the class ItemDefinitionProviderImpl method getMatchingPropDef.

private static QPropertyDefinition getMatchingPropDef(QPropertyDefinition[] defs, int type) {
    QPropertyDefinition match = null;
    for (int i = 0; i < defs.length; i++) {
        QItemDefinition qDef = defs[i];
        if (!qDef.definesNode()) {
            QPropertyDefinition pd = (QPropertyDefinition) qDef;
            int reqType = pd.getRequiredType();
            // match type
            if (reqType == PropertyType.UNDEFINED || type == PropertyType.UNDEFINED || reqType == type) {
                if (match == null) {
                    match = pd;
                } else {
                    // the one we've already got
                    if (match.getRequiredType() != pd.getRequiredType()) {
                        if (match.getRequiredType() == PropertyType.UNDEFINED) {
                            // found better match
                            match = pd;
                        }
                    } else {
                        if (match.isMultiple() && !pd.isMultiple()) {
                            // found better match
                            match = pd;
                        }
                    }
                }
                if (match.getRequiredType() != PropertyType.UNDEFINED && !match.isMultiple()) {
                    // found best possible match, get outta here
                    return match;
                }
            }
        }
    }
    return match;
}
Also used : QPropertyDefinition(org.apache.jackrabbit.spi.QPropertyDefinition) QItemDefinition(org.apache.jackrabbit.spi.QItemDefinition)

Example 5 with QPropertyDefinition

use of org.apache.jackrabbit.spi.QPropertyDefinition in project jackrabbit by apache.

the class NodeTypeManagerImpl method getPropertyDefinition.

/**
     * Retrieve the <code>PropertyDefinition</code> for the given
     * <code>QPropertyDefinition</code>.
     *
     * @param def
     * @return
     */
@Override
public PropertyDefinition getPropertyDefinition(QPropertyDefinition def) {
    synchronized (pdCache) {
        PropertyDefinition pdi = pdCache.get(def);
        if (pdi == null) {
            pdi = new PropertyDefinitionImpl(def, this, getNamePathResolver(), valueFactory);
            pdCache.put(def, pdi);
        }
        return pdi;
    }
}
Also used : PropertyDefinitionImpl(org.apache.jackrabbit.spi.commons.nodetype.PropertyDefinitionImpl) QPropertyDefinition(org.apache.jackrabbit.spi.QPropertyDefinition) PropertyDefinition(javax.jcr.nodetype.PropertyDefinition)

Aggregations

QPropertyDefinition (org.apache.jackrabbit.spi.QPropertyDefinition)81 Name (org.apache.jackrabbit.spi.Name)32 ConstraintViolationException (javax.jcr.nodetype.ConstraintViolationException)22 QNodeDefinition (org.apache.jackrabbit.spi.QNodeDefinition)19 RepositoryException (javax.jcr.RepositoryException)14 QValue (org.apache.jackrabbit.spi.QValue)12 QItemDefinition (org.apache.jackrabbit.spi.QItemDefinition)9 QValueConstraint (org.apache.jackrabbit.spi.QValueConstraint)9 ArrayList (java.util.ArrayList)8 Value (javax.jcr.Value)7 InternalValue (org.apache.jackrabbit.core.value.InternalValue)7 ItemExistsException (javax.jcr.ItemExistsException)6 NodeId (org.apache.jackrabbit.core.id.NodeId)6 PropertyDefinition (javax.jcr.nodetype.PropertyDefinition)5 EffectiveNodeType (org.apache.jackrabbit.core.nodetype.EffectiveNodeType)5 PropertyState (org.apache.jackrabbit.core.state.PropertyState)5 QNodeTypeDefinition (org.apache.jackrabbit.spi.QNodeTypeDefinition)5 ValueConstraint (org.apache.jackrabbit.spi.commons.nodetype.constraint.ValueConstraint)5 NodeState (org.apache.jackrabbit.core.state.NodeState)4 NameException (org.apache.jackrabbit.spi.commons.conversion.NameException)4