// build effective node type of remaining mixin's & primary type
Set remainingMixins = new HashSet(((NodeState) state).getMixinTypeNames());
// remove name of target mixin
remainingMixins.remove(mixinName);
EffectiveNodeType entRemaining;
try {
// remaining mixin's
HashSet set = new HashSet(remainingMixins);
// primary type
set.add(primaryTypeName);
// build effective node type representing primary type including remaining mixin's
entRemaining = ntReg.getEffectiveNodeType((QName[]) set.toArray(new QName[set.size()]));
} catch (NodeTypeConflictException ntce) {
throw new ConstraintViolationException(ntce.getMessage());
}
/**
* 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 ((QName.MIX_REFERENCEABLE.equals(mixinName)
|| mixin.isDerivedFrom(QName.MIX_REFERENCEABLE))
&& !entRemaining.includesNodeType(QName.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");
}
}
// modify the state of this node
NodeState thisState = (NodeState) getOrCreateTransientItemState();
thisState.setMixinTypeNames(remainingMixins);
// set jcr:mixinTypes property
setMixinTypesProperty(remainingMixins);
// shortcut
if (mixin.getChildNodeDefinitions().length == 0
&& mixin.getPropertyDefinitions().length == 0) {
// the node type has neither property nor child node definitions,
// i.e. we're done
return;
}
// walk through properties and child nodes and remove those that have been
// defined by the specified mixin type
// use temp set to avoid ConcurrentModificationException
HashSet set = new HashSet(thisState.getPropertyNames());
for (Iterator iter = set.iterator(); iter.hasNext();) {
QName propName = (QName) iter.next();
PropertyImpl prop = (PropertyImpl) itemMgr.getItem(
new PropertyId(thisState.getNodeId(), propName));
// check if property has been defined by mixin type (or one of its supertypes)
NodeTypeImpl declaringNT = (NodeTypeImpl) prop.getDefinition().getDeclaringNodeType();
if (!entRemaining.includesNodeType(declaringNT.getQName())) {
// the remaining effective node type doesn't include the
// node type that declared this property, it is thus safe
// to remove it
removeChildProperty(propName);
}
}
// use temp array to avoid ConcurrentModificationException
ArrayList list = new ArrayList(thisState.getChildNodeEntries());
// start from tail to avoid problems with same-name siblings
for (int i = list.size() - 1; i >= 0; i--) {
NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) list.get(i);
NodeImpl node = (NodeImpl) itemMgr.getItem(entry.getId());
// check if node has been defined by mixin type (or one of its supertypes)
NodeTypeImpl declaringNT = (NodeTypeImpl) node.getDefinition().getDeclaringNodeType();
if (!entRemaining.includesNodeType(declaringNT.getQName())) {
// the remaining effective node type doesn't include the
// node type that declared this child node, it is thus safe
// to remove it
removeChildNode(entry.getName(), entry.getIndex());
}