}
// 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");
}
}
// mix:lockable: the mixin cannot be removed if the node is
// 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);
}
}