use of org.apache.jackrabbit.spi.QItemDefinition in project jackrabbit by apache.
the class BatchedItemOperations method checkAddNode.
//--------------------------------------< misc. high-level helper methods >
/**
* Checks if adding a child node called <code>nodeName</code> of node type
* <code>nodeTypeName</code> to the given parent node is allowed in the
* current context.
*
* @param parentState
* @param nodeName
* @param nodeTypeName
* @param options bit-wise OR'ed flags specifying the checks that should be
* performed; any combination of the following constants:
* <ul>
* <li><code>{@link #CHECK_ACCESS}</code>: make sure
* current session is granted read & write access on
* parent node</li>
* <li><code>{@link #CHECK_LOCK}</code>: make sure
* there's no foreign lock on parent node</li>
* <li><code>{@link #CHECK_CHECKED_OUT}</code>: make sure
* parent node is checked-out</li>
* <li><code>{@link #CHECK_CONSTRAINTS}</code>:
* make sure no node type constraints would be violated</li>
* <li><code>{@link #CHECK_HOLD}</code>: check for effective holds preventing the add operation</li>
* <li><code>{@link #CHECK_RETENTION}</code>: check for effective retention policy preventing the add operation</li>
* </ul>
* @throws ConstraintViolationException
* @throws AccessDeniedException
* @throws VersionException
* @throws LockException
* @throws ItemNotFoundException
* @throws ItemExistsException
* @throws RepositoryException
*/
public void checkAddNode(NodeState parentState, Name nodeName, Name nodeTypeName, int options) throws ConstraintViolationException, AccessDeniedException, VersionException, LockException, ItemNotFoundException, ItemExistsException, RepositoryException {
Path parentPath = hierMgr.getPath(parentState.getNodeId());
if ((options & CHECK_LOCK) == CHECK_LOCK) {
// make sure there's no foreign lock on parent node
verifyUnlocked(parentPath);
}
if ((options & CHECK_CHECKED_OUT) == CHECK_CHECKED_OUT) {
// make sure parent node is checked-out
verifyCheckedOut(parentPath);
}
if ((options & CHECK_ACCESS) == CHECK_ACCESS) {
AccessManager accessMgr = context.getAccessManager();
// make sure current session is granted read access on parent node
if (!accessMgr.isGranted(parentPath, Permission.READ)) {
throw new ItemNotFoundException(safeGetJCRPath(parentState.getNodeId()));
}
// make sure current session is granted write access on parent node
if (!accessMgr.isGranted(parentPath, nodeName, Permission.ADD_NODE)) {
throw new AccessDeniedException(safeGetJCRPath(parentState.getNodeId()) + ": not allowed to add child node");
}
// specified node type (and ev. mixins)
if (!accessMgr.isGranted(parentPath, nodeName, Permission.NODE_TYPE_MNGMT)) {
throw new AccessDeniedException(safeGetJCRPath(parentState.getNodeId()) + ": not allowed to add child node");
}
}
if ((options & CHECK_CONSTRAINTS) == CHECK_CONSTRAINTS) {
QItemDefinition parentDef = context.getItemManager().getDefinition(parentState).unwrap();
// make sure parent node is not protected
if (parentDef.isProtected()) {
throw new ConstraintViolationException(safeGetJCRPath(parentState.getNodeId()) + ": cannot add child node to protected parent node");
}
// make sure there's an applicable definition for new child node
EffectiveNodeType entParent = getEffectiveNodeType(parentState);
entParent.checkAddNodeConstraints(nodeName, nodeTypeName, context.getNodeTypeRegistry());
QNodeDefinition newNodeDef = findApplicableNodeDefinition(nodeName, nodeTypeName, parentState);
// check for name collisions
if (parentState.hasChildNodeEntry(nodeName)) {
// there's already a node with that name...
// get definition of existing conflicting node
ChildNodeEntry entry = parentState.getChildNodeEntry(nodeName, 1);
NodeState conflictingState;
NodeId conflictingId = entry.getId();
try {
conflictingState = (NodeState) stateMgr.getItemState(conflictingId);
} catch (ItemStateException ise) {
String msg = "internal error: failed to retrieve state of " + safeGetJCRPath(conflictingId);
log.debug(msg);
throw new RepositoryException(msg, ise);
}
QNodeDefinition conflictingTargetDef = context.getItemManager().getDefinition(conflictingState).unwrap();
// check same-name sibling setting of both target and existing node
if (!conflictingTargetDef.allowsSameNameSiblings() || !newNodeDef.allowsSameNameSiblings()) {
throw new ItemExistsException("cannot add child node '" + nodeName.getLocalName() + "' to " + safeGetJCRPath(parentState.getNodeId()) + ": colliding with same-named existing node");
}
}
}
RetentionRegistry retentionReg = context.getSessionImpl().getRetentionRegistry();
if ((options & CHECK_HOLD) == CHECK_HOLD) {
if (retentionReg.hasEffectiveHold(parentPath, false)) {
throw new RepositoryException("Unable to add node. Parent is affected by a hold.");
}
}
if ((options & CHECK_RETENTION) == CHECK_RETENTION) {
if (retentionReg.hasEffectiveRetention(parentPath, false)) {
throw new RepositoryException("Unable to add node. Parent is affected by a retention.");
}
}
}
use of org.apache.jackrabbit.spi.QItemDefinition in project jackrabbit by apache.
the class BatchedItemOperations method checkRemoveNode.
/**
* Checks if removing the given target node from the specifed parent
* is allowed in the current context.
*
* @param targetState
* @param parentId
* @param options bit-wise OR'ed flags specifying the checks that should be
* performed; any combination of the following constants:
* <ul>
* <li><code>{@link #CHECK_ACCESS}</code>: make sure
* current session is granted read access on parent
* and remove privilege on target node</li>
* <li><code>{@link #CHECK_LOCK}</code>: make sure
* there's no foreign lock on parent node</li>
* <li><code>{@link #CHECK_CHECKED_OUT}</code>: make sure
* parent node is checked-out</li>
* <li><code>{@link #CHECK_CONSTRAINTS}</code>:
* make sure no node type constraints would be violated</li>
* <li><code>{@link #CHECK_REFERENCES}</code>:
* make sure no references exist on target node</li>
* <li><code>{@link #CHECK_HOLD}</code>: check for effective holds preventing the add operation</li>
* <li><code>{@link #CHECK_RETENTION}</code>: check for effective retention policy preventing the add operation</li>
* </ul>
* @throws ConstraintViolationException
* @throws AccessDeniedException
* @throws VersionException
* @throws LockException
* @throws ItemNotFoundException
* @throws ReferentialIntegrityException
* @throws RepositoryException
*/
public void checkRemoveNode(NodeState targetState, NodeId parentId, int options) throws ConstraintViolationException, AccessDeniedException, VersionException, LockException, ItemNotFoundException, ReferentialIntegrityException, RepositoryException {
if (targetState.getParentId() == null) {
// root or orphaned node
throw new ConstraintViolationException("cannot remove root node");
}
Path targetPath = hierMgr.getPath(targetState.getNodeId());
NodeState parentState = getNodeState(parentId);
Path parentPath = hierMgr.getPath(parentId);
if ((options & CHECK_LOCK) == CHECK_LOCK) {
// make sure there's no foreign lock on parent node
verifyUnlocked(parentPath);
}
if ((options & CHECK_CHECKED_OUT) == CHECK_CHECKED_OUT) {
// make sure parent node is checked-out
verifyCheckedOut(parentPath);
}
if ((options & CHECK_ACCESS) == CHECK_ACCESS) {
try {
AccessManager accessMgr = context.getAccessManager();
// make sure current session is granted read access on parent node
if (!accessMgr.isGranted(targetPath, Permission.READ)) {
throw new PathNotFoundException(safeGetJCRPath(targetPath));
}
// make sure current session is allowed to remove target node
if (!accessMgr.isGranted(targetPath, Permission.REMOVE_NODE)) {
throw new AccessDeniedException(safeGetJCRPath(targetPath) + ": not allowed to remove node");
}
} catch (ItemNotFoundException infe) {
String msg = "internal error: failed to check access rights for " + safeGetJCRPath(targetPath);
log.debug(msg);
throw new RepositoryException(msg, infe);
}
}
if ((options & CHECK_CONSTRAINTS) == CHECK_CONSTRAINTS) {
QItemDefinition parentDef = context.getItemManager().getDefinition(parentState).unwrap();
if (parentDef.isProtected()) {
throw new ConstraintViolationException(safeGetJCRPath(parentId) + ": cannot remove child node of protected parent node");
}
QItemDefinition targetDef = context.getItemManager().getDefinition(targetState).unwrap();
if (targetDef.isMandatory()) {
throw new ConstraintViolationException(safeGetJCRPath(targetPath) + ": cannot remove mandatory node");
}
if (targetDef.isProtected()) {
throw new ConstraintViolationException(safeGetJCRPath(targetPath) + ": cannot remove protected node");
}
}
if ((options & CHECK_REFERENCES) == CHECK_REFERENCES) {
EffectiveNodeType ent = getEffectiveNodeType(targetState);
if (ent.includesNodeType(NameConstants.MIX_REFERENCEABLE)) {
NodeId targetId = targetState.getNodeId();
if (stateMgr.hasNodeReferences(targetId)) {
try {
NodeReferences refs = stateMgr.getNodeReferences(targetId);
if (refs.hasReferences()) {
throw new ReferentialIntegrityException(safeGetJCRPath(targetPath) + ": cannot remove node with references");
}
} catch (ItemStateException ise) {
String msg = "internal error: failed to check references on " + safeGetJCRPath(targetPath);
log.error(msg, ise);
throw new RepositoryException(msg, ise);
}
}
}
}
RetentionRegistry retentionReg = context.getSessionImpl().getRetentionRegistry();
if ((options & CHECK_HOLD) == CHECK_HOLD) {
if (retentionReg.hasEffectiveHold(targetPath, true)) {
throw new RepositoryException("Unable to perform removal. Node is affected by a hold.");
}
}
if ((options & CHECK_RETENTION) == CHECK_RETENTION) {
if (retentionReg.hasEffectiveRetention(targetPath, true)) {
throw new RepositoryException("Unable to perform removal. Node is affected by a retention.");
}
}
}
use of org.apache.jackrabbit.spi.QItemDefinition in project jackrabbit by apache.
the class EffectiveNodeType method create.
/**
* Package private factory method.
* <p>
* Creates an effective node type representation of a node type definition.
* Note that the definitions of all referenced node types must be contained
* in <code>ntdCache</code>.
*
* @param ntd node type definition
* @param entCache cache of already-built effective node types
* @param ntdCache cache of node type definitions, used to resolve dependencies
* @return an effective node type representation of the given node type definition.
* @throws NodeTypeConflictException if the node type definition is invalid,
* e.g. due to ambiguous child definitions.
* @throws NoSuchNodeTypeException if a node type reference (e.g. a supertype)
* could not be resolved.
*/
static EffectiveNodeType create(QNodeTypeDefinition ntd, EffectiveNodeTypeCache entCache, Map<Name, QNodeTypeDefinition> ntdCache) throws NodeTypeConflictException, NoSuchNodeTypeException {
// create empty effective node type instance
EffectiveNodeType ent = new EffectiveNodeType();
Name ntName = ntd.getName();
// prepare new instance
ent.mergedNodeTypes.add(ntName);
ent.allNodeTypes.add(ntName);
// 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> itemDefs = new HashSet<QItemDefinition>();
QNodeDefinition[] cnda = ntd.getChildNodeDefs();
for (QNodeDefinition aCnda : cnda) {
// this node type definition
if (itemDefs.contains(aCnda)) {
// conflict
String msg;
if (aCnda.definesResidual()) {
msg = ntName + " contains ambiguous residual child node definitions";
} else {
msg = ntName + " contains ambiguous definitions for child node named " + aCnda.getName();
}
log.debug(msg);
throw new NodeTypeConflictException(msg);
} else {
itemDefs.add(aCnda);
}
if (aCnda.definesResidual()) {
// residual node definition
ent.unnamedItemDefs.add(aCnda);
} else {
// named node definition
Name name = aCnda.getName();
List<QItemDefinition> defs = ent.namedItemDefs.get(name);
if (defs == null) {
defs = new ArrayList<QItemDefinition>();
ent.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 def : defs) {
if (aCnda.isAutoCreated() || def.isAutoCreated()) {
// conflict
String msg = "There are more than one 'auto-create' item definitions for '" + name + "' in node type '" + ntName + "'";
log.debug(msg);
throw new NodeTypeConflictException(msg);
}
}
}
defs.add(aCnda);
}
}
QPropertyDefinition[] pda = ntd.getPropertyDefs();
for (QPropertyDefinition aPda : pda) {
// this node type definition
if (itemDefs.contains(aPda)) {
// conflict
String msg;
if (aPda.definesResidual()) {
msg = ntName + " contains ambiguous residual property definitions";
} else {
msg = ntName + " contains ambiguous definitions for property named " + aPda.getName();
}
log.debug(msg);
throw new NodeTypeConflictException(msg);
} else {
itemDefs.add(aPda);
}
if (aPda.definesResidual()) {
// residual property definition
ent.unnamedItemDefs.add(aPda);
} else {
// named property definition
Name name = aPda.getName();
List<QItemDefinition> defs = ent.namedItemDefs.get(name);
if (defs == null) {
defs = new ArrayList<QItemDefinition>();
ent.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 def : defs) {
if (aPda.isAutoCreated() || def.isAutoCreated()) {
// conflict
String msg = "There are more than one 'auto-create' item definitions for '" + name + "' in node type '" + ntName + "'";
log.debug(msg);
throw new NodeTypeConflictException(msg);
}
}
}
defs.add(aPda);
}
}
// resolve supertypes recursively
Name[] supertypes = ntd.getSupertypes();
if (supertypes.length > 0) {
EffectiveNodeType base = NodeTypeRegistry.getEffectiveNodeType(supertypes, entCache, ntdCache);
ent.internalMerge(base, true);
}
// resolve 'orderable child nodes' attribute value (JCR-1947)
if (ntd.hasOrderableChildNodes()) {
ent.orderableChildNodes = true;
} else {
Name[] nta = ent.getInheritedNodeTypes();
for (Name aNta : nta) {
QNodeTypeDefinition def = ntdCache.get(aNta);
if (def.hasOrderableChildNodes()) {
ent.orderableChildNodes = true;
break;
}
}
}
// resolve 'primary item' attribute value (JCR-1947)
if (ntd.getPrimaryItemName() != null) {
ent.primaryItemName = ntd.getPrimaryItemName();
} else {
Name[] nta = ent.getInheritedNodeTypes();
for (Name aNta : nta) {
QNodeTypeDefinition def = ntdCache.get(aNta);
if (def.getPrimaryItemName() != null) {
ent.primaryItemName = def.getPrimaryItemName();
break;
}
}
}
// we're done
return ent;
}
use of org.apache.jackrabbit.spi.QItemDefinition in project jackrabbit by apache.
the class EffectiveNodeType method getNamedNodeDefs.
public QNodeDefinition[] getNamedNodeDefs(Name name) {
List<QItemDefinition> list = namedItemDefs.get(name);
if (list == null || list.size() == 0) {
return QNodeDefinition.EMPTY_ARRAY;
}
ArrayList<QNodeDefinition> defs = new ArrayList<QNodeDefinition>(list.size());
for (QItemDefinition def : list) {
if (def.definesNode()) {
defs.add((QNodeDefinition) def);
}
}
if (defs.size() == 0) {
return QNodeDefinition.EMPTY_ARRAY;
}
return defs.toArray(new QNodeDefinition[defs.size()]);
}
use of org.apache.jackrabbit.spi.QItemDefinition in project jackrabbit by apache.
the class EffectiveNodeType method internalMerge.
/**
* Internal helper method which merges another <code>EffectiveNodeType</code>
* instance with <i>this</i> instance.
* <p>
* Warning: This instance might be in an inconsistent state if an exception
* is thrown.
*
* @param other
* @param supertype true if the merge is a result of inheritance, i.e. <code>other</code>
* represents one or more supertypes of this instance; otherwise false, i.e.
* the merge is the result of an explicit aggregation
* @throws NodeTypeConflictException
*/
private synchronized void internalMerge(EffectiveNodeType other, boolean supertype) throws NodeTypeConflictException {
Name[] nta = other.getAllNodeTypes();
int includedCount = 0;
for (Name aNta : nta) {
if (includesNodeType(aNta)) {
// redundant node type
log.debug("node type '" + aNta + "' is already contained.");
includedCount++;
}
}
if (includedCount == nta.length) {
// total overlap, ignore
return;
}
// named item definitions
QItemDefinition[] defs = other.getNamedItemDefs();
for (QItemDefinition def : defs) {
if (includesNodeType(def.getDeclaringNodeType())) {
// ignore redundant definitions
continue;
}
Name name = def.getName();
List<QItemDefinition> existingDefs = namedItemDefs.get(name);
if (existingDefs != null) {
if (existingDefs.size() > 0) {
// there already exists at least one definition with that name
for (QItemDefinition existingDef : existingDefs) {
// make sure none of them is auto-create
if (def.isAutoCreated() || existingDef.isAutoCreated()) {
// conflict
String msg = "The item definition for '" + name + "' in node type '" + def.getDeclaringNodeType() + "' conflicts with node type '" + existingDef.getDeclaringNodeType() + "': name collision with auto-create definition";
log.debug(msg);
throw new NodeTypeConflictException(msg);
}
// check ambiguous definitions
if (def.definesNode() == existingDef.definesNode()) {
if (!def.definesNode()) {
// property definition
QPropertyDefinition pd = (QPropertyDefinition) def;
QPropertyDefinition epd = (QPropertyDefinition) existingDef;
// compare type & multiValued flag
if (pd.getRequiredType() == epd.getRequiredType() && pd.isMultiple() == epd.isMultiple()) {
// conflict
String msg = "The property definition for '" + name + "' in node type '" + def.getDeclaringNodeType() + "' conflicts with node type '" + existingDef.getDeclaringNodeType() + "': ambiguous property definition";
log.debug(msg);
throw new NodeTypeConflictException(msg);
}
} else {
// child node definition
// conflict
String msg = "The child node definition for '" + name + "' in node type '" + def.getDeclaringNodeType() + "' conflicts with node type '" + existingDef.getDeclaringNodeType() + "': ambiguous child node definition";
log.debug(msg);
throw new NodeTypeConflictException(msg);
}
}
}
}
} else {
existingDefs = new ArrayList<QItemDefinition>();
namedItemDefs.put(name, existingDefs);
}
existingDefs.add(def);
}
// residual item definitions
defs = other.getUnnamedItemDefs();
for (QItemDefinition def : defs) {
if (includesNodeType(def.getDeclaringNodeType())) {
// ignore redundant definitions
continue;
}
for (QItemDefinition existing : unnamedItemDefs) {
// compare with existing definition
if (def.definesNode() == existing.definesNode()) {
if (!def.definesNode()) {
// property definition
QPropertyDefinition pd = (QPropertyDefinition) def;
QPropertyDefinition epd = (QPropertyDefinition) existing;
// compare type & multiValued flag
if (pd.getRequiredType() == epd.getRequiredType() && pd.isMultiple() == epd.isMultiple()) {
// conflict
String msg = "A property definition in node type '" + def.getDeclaringNodeType() + "' conflicts with node type '" + existing.getDeclaringNodeType() + "': ambiguous residual property definition";
log.debug(msg);
throw new NodeTypeConflictException(msg);
}
} else {
// child node definition
QNodeDefinition nd = (QNodeDefinition) def;
QNodeDefinition end = (QNodeDefinition) existing;
// compare required & default primary types
if (Arrays.equals(nd.getRequiredPrimaryTypes(), end.getRequiredPrimaryTypes()) && (nd.getDefaultPrimaryType() == null ? end.getDefaultPrimaryType() == null : nd.getDefaultPrimaryType().equals(end.getDefaultPrimaryType()))) {
// conflict
String msg = "A child node definition in node type '" + def.getDeclaringNodeType() + "' conflicts with node type '" + existing.getDeclaringNodeType() + "': ambiguous residual child node definition";
log.debug(msg);
throw new NodeTypeConflictException(msg);
}
}
}
}
unnamedItemDefs.add(def);
}
allNodeTypes.addAll(Arrays.asList(nta));
if (supertype) {
// implicit merge as result of inheritance
// add other merged node types as supertypes
nta = other.getMergedNodeTypes();
inheritedNodeTypes.addAll(Arrays.asList(nta));
// add supertypes of other merged node types as supertypes
nta = other.getInheritedNodeTypes();
inheritedNodeTypes.addAll(Arrays.asList(nta));
} else {
// explicit merge
// merge with other merged node types
nta = other.getMergedNodeTypes();
mergedNodeTypes.addAll(Arrays.asList(nta));
// add supertypes of other merged node types as supertypes
nta = other.getInheritedNodeTypes();
inheritedNodeTypes.addAll(Arrays.asList(nta));
}
// update 'orderable child nodes' attribute value (JCR-1947)
if (other.hasOrderableChildNodes()) {
orderableChildNodes = true;
}
// update 'primary item' attribute value (JCR-1947)
if (primaryItemName == null && other.getPrimaryItemName() != null) {
primaryItemName = other.getPrimaryItemName();
}
}
Aggregations