// 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 ((NameConstants.MIX_REFERENCEABLE.equals(mixinName)
|| mixin.isDerivedFrom(NameConstants.MIX_REFERENCEABLE))
&& !entResulting.includesNodeType(NameConstants.MIX_REFERENCEABLE)) {
// removing this mixin would effectively remove mix:referenceable:
// make sure no references exist
PropertyIterator iter = getReferences();
if (iter.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)
&& isLocked()) {
throw new ConstraintViolationException(mixinName + " can not be removed: the node is locked.");
}
NodeState thisState = (NodeState) 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 the 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);
}
}