use of org.apache.jackrabbit.core.nodetype.NodeTypeImpl 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);
}
}
}
}
use of org.apache.jackrabbit.core.nodetype.NodeTypeImpl in project jackrabbit by apache.
the class RemoveMixinOperation method perform.
public Object perform(SessionContext context) throws RepositoryException {
SessionImpl session = context.getSessionImpl();
ItemManager itemMgr = context.getItemManager();
SessionItemStateManager stateMgr = context.getItemStateManager();
context.getItemValidator().checkModify(node, CHECK_LOCK | CHECK_CHECKED_OUT | CHECK_CONSTRAINTS | CHECK_HOLD, Permission.NODE_TYPE_MNGMT);
// check if mixin is assigned
NodeState state = node.getNodeState();
if (!state.getMixinTypeNames().contains(mixinName)) {
throw new NoSuchNodeTypeException("Mixin " + context.getJCRName(mixinName) + " not included in " + node);
}
NodeTypeManagerImpl ntMgr = context.getNodeTypeManager();
NodeTypeRegistry ntReg = context.getNodeTypeRegistry();
// build effective node type of remaining mixin's & primary type
Set<Name> remainingMixins = new HashSet<Name>(state.getMixinTypeNames());
// remove name of target mixin
remainingMixins.remove(mixinName);
EffectiveNodeType entResulting;
try {
// build effective node type representing primary type
// including remaining mixin's
entResulting = ntReg.getEffectiveNodeType(state.getNodeTypeName(), remainingMixins);
} catch (NodeTypeConflictException e) {
throw new ConstraintViolationException(e.getMessage(), e);
}
// mix:referenceable needs special handling because it has
// special semantics:
// it can only be removed if there no more references to this node
NodeTypeImpl mixin = ntMgr.getNodeType(mixinName);
if (isReferenceable(mixin) && !entResulting.includesNodeType(MIX_REFERENCEABLE)) {
if (node.getReferences().hasNext()) {
throw new ConstraintViolationException(mixinName + " can not be removed:" + " the node is being referenced through at least" + " one property of type REFERENCE");
}
}
// currently locked even if the editing session is the lock holder.
if ((NameConstants.MIX_LOCKABLE.equals(mixinName) || mixin.isDerivedFrom(NameConstants.MIX_LOCKABLE)) && !entResulting.includesNodeType(NameConstants.MIX_LOCKABLE) && node.isLocked()) {
throw new ConstraintViolationException(mixinName + " can not be removed: the node is locked.");
}
NodeState thisState = (NodeState) node.getOrCreateTransientItemState();
// collect information about properties and nodes which require further
// action as a result of the mixin removal; we need to do this *before*
// actually changing the assigned mixin types, otherwise we wouldn't
// be able to retrieve the current definition of an item.
Map<PropertyId, PropertyDefinition> affectedProps = new HashMap<PropertyId, PropertyDefinition>();
Map<ChildNodeEntry, NodeDefinition> affectedNodes = new HashMap<ChildNodeEntry, NodeDefinition>();
try {
Set<Name> names = thisState.getPropertyNames();
for (Name propName : names) {
PropertyId propId = new PropertyId(thisState.getNodeId(), propName);
PropertyState propState = (PropertyState) stateMgr.getItemState(propId);
PropertyDefinition oldDef = itemMgr.getDefinition(propState);
// check if property has been defined by mixin type
// (or one of its supertypes)
NodeTypeImpl declaringNT = (NodeTypeImpl) oldDef.getDeclaringNodeType();
if (!entResulting.includesNodeType(declaringNT.getQName())) {
// the resulting effective node type doesn't include the
// node type that declared this property
affectedProps.put(propId, oldDef);
}
}
List<ChildNodeEntry> entries = thisState.getChildNodeEntries();
for (ChildNodeEntry entry : entries) {
NodeState nodeState = (NodeState) stateMgr.getItemState(entry.getId());
NodeDefinition oldDef = itemMgr.getDefinition(nodeState);
// check if node has been defined by mixin type
// (or one of its supertypes)
NodeTypeImpl declaringNT = (NodeTypeImpl) oldDef.getDeclaringNodeType();
if (!entResulting.includesNodeType(declaringNT.getQName())) {
// the resulting effective node type doesn't include the
// node type that declared this child node
affectedNodes.put(entry, oldDef);
}
}
} catch (ItemStateException e) {
throw new RepositoryException("Failed to determine effect of removing mixin " + context.getJCRName(mixinName), e);
}
// modify the state of this node
thisState.setMixinTypeNames(remainingMixins);
// set jcr:mixinTypes property
node.setMixinTypesProperty(remainingMixins);
// process affected nodes & properties:
// 1. try to redefine item based on the resulting
// new effective node type (see JCR-2130)
// 2. remove item if 1. fails
boolean success = false;
try {
for (Map.Entry<PropertyId, PropertyDefinition> entry : affectedProps.entrySet()) {
PropertyId id = entry.getKey();
PropertyImpl prop = (PropertyImpl) itemMgr.getItem(id);
PropertyDefinition oldDef = entry.getValue();
if (oldDef.isProtected()) {
// remove 'orphaned' protected properties immediately
node.removeChildProperty(id.getName());
continue;
}
// redefine property if possible (JCR-2130)
try {
PropertyDefinitionImpl newDef = node.getApplicablePropertyDefinition(id.getName(), prop.getType(), oldDef.isMultiple(), false);
if (newDef.getRequiredType() != PropertyType.UNDEFINED && newDef.getRequiredType() != prop.getType()) {
// value conversion required
if (oldDef.isMultiple()) {
// convert value
Value[] values = ValueHelper.convert(prop.getValues(), newDef.getRequiredType(), session.getValueFactory());
// redefine property
prop.onRedefine(newDef.unwrap());
// set converted values
prop.setValue(values);
} else {
// convert value
Value value = ValueHelper.convert(prop.getValue(), newDef.getRequiredType(), session.getValueFactory());
// redefine property
prop.onRedefine(newDef.unwrap());
// set converted values
prop.setValue(value);
}
} else {
// redefine property
prop.onRedefine(newDef.unwrap());
}
} catch (ValueFormatException vfe) {
// value conversion failed, remove it
node.removeChildProperty(id.getName());
} catch (ConstraintViolationException cve) {
// no suitable definition found for this property,
// remove it
node.removeChildProperty(id.getName());
}
}
for (ChildNodeEntry entry : affectedNodes.keySet()) {
NodeState nodeState = (NodeState) stateMgr.getItemState(entry.getId());
NodeImpl childNode = (NodeImpl) itemMgr.getItem(entry.getId());
NodeDefinition oldDef = affectedNodes.get(entry);
if (oldDef.isProtected()) {
// remove 'orphaned' protected child node immediately
node.removeChildNode(entry.getId());
continue;
}
// redefine node if possible (JCR-2130)
try {
NodeDefinitionImpl newDef = node.getApplicableChildNodeDefinition(entry.getName(), nodeState.getNodeTypeName());
// redefine node
childNode.onRedefine(newDef.unwrap());
} catch (ConstraintViolationException cve) {
// no suitable definition found for this child node,
// remove it
node.removeChildNode(entry.getId());
}
}
success = true;
} catch (ItemStateException e) {
throw new RepositoryException("Failed to clean up child items defined by removed mixin " + context.getJCRName(mixinName), e);
} finally {
if (!success) {
// TODO JCR-1914: revert any changes made so far
}
}
return this;
}
use of org.apache.jackrabbit.core.nodetype.NodeTypeImpl in project jackrabbit by apache.
the class NodeImpl method canAddMixin.
/**
* {@inheritDoc}
*/
public boolean canAddMixin(String mixinName) throws NoSuchNodeTypeException, RepositoryException {
// check state of this instance
sanityCheck();
Name ntName = sessionContext.getQName(mixinName);
NodeTypeManagerImpl ntMgr = sessionContext.getNodeTypeManager();
NodeTypeImpl mixin = ntMgr.getNodeType(ntName);
if (!mixin.isMixin()) {
return false;
}
int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_CHECKED_OUT | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
int permissions = Permission.NODE_TYPE_MNGMT;
// in addition.
if (NameConstants.MIX_VERSIONABLE.equals(ntName) || NameConstants.MIX_SIMPLE_VERSIONABLE.equals(ntName)) {
permissions |= Permission.VERSION_MNGMT;
}
if (!sessionContext.getItemValidator().canModify(this, options, permissions)) {
return false;
}
final Name primaryTypeName = data.getNodeState().getNodeTypeName();
NodeTypeImpl primaryType = ntMgr.getNodeType(primaryTypeName);
if (primaryType.isDerivedFrom(ntName)) {
// mixin already inherited -> addMixin is allowed but has no effect.
return true;
}
// build effective node type of mixins & primary type
// in order to detect conflicts
NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
EffectiveNodeType entExisting;
try {
// existing mixin's
Set<Name> mixins = new HashSet<Name>(data.getNodeState().getMixinTypeNames());
// build effective node type representing primary type including existing mixin's
entExisting = ntReg.getEffectiveNodeType(primaryTypeName, mixins);
if (entExisting.includesNodeType(ntName)) {
// addMixin would succeed without modifying the node.
return true;
}
// add new mixin
mixins.add(ntName);
// try to build new effective node type (will throw in case of conflicts)
ntReg.getEffectiveNodeType(primaryTypeName, mixins);
} catch (NodeTypeConflictException ntce) {
return false;
}
return true;
}
use of org.apache.jackrabbit.core.nodetype.NodeTypeImpl in project jackrabbit by apache.
the class NodeImpl method rename.
// -------------------------------------------------------< JackrabbitNode >
/**
* {@inheritDoc}
*/
public void rename(String newName) throws RepositoryException {
// check if this is the root node
if (getDepth() == 0) {
throw new RepositoryException("Cannot rename the root node");
}
Name qName;
try {
qName = sessionContext.getQName(newName);
} catch (NameException e) {
throw new RepositoryException("invalid node name: " + newName, e);
}
NodeImpl parent = (NodeImpl) getParent();
// check for name collisions
NodeImpl existing = null;
try {
existing = parent.getNode(qName);
// check same-name sibling setting of existing node
if (!existing.getDefinition().allowsSameNameSiblings()) {
throw new ItemExistsException("Same name siblings are not allowed: " + existing);
}
} catch (AccessDeniedException ade) {
// FIXME by throwing ItemExistsException we're disclosing too much information
throw new ItemExistsException();
} catch (ItemNotFoundException infe) {
// no name collision, fall through
}
// verify that parent node
// - is checked-out
// - is not protected neither by node type constraints nor by retention/hold
int options = ItemValidator.CHECK_CHECKED_OUT | ItemValidator.CHECK_LOCK | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD | ItemValidator.CHECK_RETENTION;
sessionContext.getItemValidator().checkRemove(parent, options, Permission.NONE);
sessionContext.getItemValidator().checkModify(parent, options, Permission.NONE);
// check constraints
// get applicable definition of renamed target node
NodeTypeImpl nt = (NodeTypeImpl) getPrimaryNodeType();
org.apache.jackrabbit.spi.commons.nodetype.NodeDefinitionImpl newTargetDef;
try {
newTargetDef = parent.getApplicableChildNodeDefinition(qName, nt.getQName());
} catch (RepositoryException re) {
String msg = safeGetJCRPath() + ": no definition found in parent node's node type for renamed node";
log.debug(msg);
throw new ConstraintViolationException(msg, re);
}
// necessarily have identical definitions
if (existing != null && !newTargetDef.allowsSameNameSiblings()) {
throw new ItemExistsException("Same name siblings not allowed: " + existing);
}
// check permissions:
// 1. on the parent node the session must have permission to manipulate the child-entries
AccessManager acMgr = sessionContext.getAccessManager();
if (!acMgr.isGranted(parent.getPrimaryPath(), qName, Permission.MODIFY_CHILD_NODE_COLLECTION)) {
String msg = "Not allowed to rename node " + safeGetJCRPath() + " to " + newName;
log.debug(msg);
throw new AccessDeniedException(msg);
}
// the primary node type on this node itself.
if (!nt.getName().equals(newTargetDef.getName()) && !(acMgr.isGranted(getPrimaryPath(), Permission.NODE_TYPE_MNGMT))) {
String msg = "Not allowed to rename node " + safeGetJCRPath() + " to " + newName;
log.debug(msg);
throw new AccessDeniedException(msg);
}
// change definition
onRedefine(newTargetDef.unwrap());
// delegate to parent
parent.renameChildNode(getNodeId(), qName, true);
}
use of org.apache.jackrabbit.core.nodetype.NodeTypeImpl in project jackrabbit by apache.
the class NodeImpl method addNode.
/**
* Same as <code>{@link Node#addNode(String, String)}</code> except that
* this method takes <code>Name</code> arguments instead of
* <code>String</code>s and has an additional <code>uuid</code> argument.
* <p>
* <b>Important Notice:</b> This method is for internal use only! Passing
* already assigned uuid's might lead to unexpected results and
* data corruption in the worst case.
*
* @param nodeName name of the new node
* @param nodeTypeName name of the new node's node type or <code>null</code>
* if it should be determined automatically
* @param id id of the new node or <code>null</code> if a new
* id should be assigned
* @return the newly added node
* @throws RepositoryException if the node can not added
*/
// FIXME: This method should not be public
public synchronized NodeImpl addNode(Name nodeName, Name nodeTypeName, NodeId id) throws RepositoryException {
// check state of this instance
sanityCheck();
Path nodePath = PathFactoryImpl.getInstance().create(getPrimaryPath(), nodeName, true);
// Check the explicitly specified node type (if any)
NodeTypeImpl nt = null;
if (nodeTypeName != null) {
nt = sessionContext.getNodeTypeManager().getNodeType(nodeTypeName);
if (nt.isMixin()) {
throw new ConstraintViolationException("Unable to add a node with a mixin node type: " + sessionContext.getJCRName(nodeTypeName));
} else if (nt.isAbstract()) {
throw new ConstraintViolationException("Unable to add a node with an abstract node type: " + sessionContext.getJCRName(nodeTypeName));
} else {
// adding a node with explicit specifying the node type name
// requires the editing session to have nt_management privilege.
sessionContext.getAccessManager().checkPermission(nodePath, Permission.NODE_TYPE_MNGMT);
}
}
// Get the applicable child node definition for this node.
NodeDefinitionImpl def;
try {
def = getApplicableChildNodeDefinition(nodeName, nodeTypeName);
} catch (RepositoryException e) {
throw new ConstraintViolationException("No child node definition for " + sessionContext.getJCRName(nodeName) + " found in " + this, e);
}
// Use default node type from child node definition if needed
if (nt == null) {
nt = (NodeTypeImpl) def.getDefaultPrimaryType();
}
// check the new name
NodeNameNormalizer.check(nodeName);
// check for name collisions
NodeState thisState = data.getNodeState();
ChildNodeEntry cne = thisState.getChildNodeEntry(nodeName, 1);
if (cne != null) {
// check same-name sibling setting of new node
if (!def.allowsSameNameSiblings()) {
throw new ItemExistsException("This node already exists: " + itemMgr.safeGetJCRPath(nodePath));
}
// check same-name sibling setting of existing node
NodeImpl existing = itemMgr.getNode(cne.getId(), getNodeId());
if (!existing.getDefinition().allowsSameNameSiblings()) {
throw new ItemExistsException("Same-name siblings not allowed for " + existing);
}
}
// check protected flag of parent (i.e. this) node and retention/hold
// make sure this node is checked-out and not locked by another session.
int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_CHECKED_OUT | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD | ItemValidator.CHECK_RETENTION;
sessionContext.getItemValidator().checkModify(this, options, Permission.NONE);
// now do create the child node
return createChildNode(nodeName, nt, id);
}
Aggregations