use of org.apache.jackrabbit.core.id.PropertyId 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.id.PropertyId in project jackrabbit by apache.
the class LockManagerImpl method removeLockProperties.
/**
*
* @param node
* @throws RepositoryException
*/
protected void removeLockProperties(NodeImpl node) throws RepositoryException {
boolean success = false;
SessionImpl editingSession = (SessionImpl) node.getSession();
WorkspaceImpl wsp = (WorkspaceImpl) editingSession.getWorkspace();
UpdatableItemStateManager stateMgr = wsp.getItemStateManager();
try {
acquireLockPropertiesLock();
// add properties to content
if (stateMgr.inEditMode()) {
throw new RepositoryException("Unable to remove lock properties.");
}
stateMgr.edit();
try {
NodeId nodeId = node.getNodeId();
NodeState nodeState = (NodeState) stateMgr.getItemState(nodeId);
if (nodeState.hasPropertyName(NameConstants.JCR_LOCKOWNER)) {
PropertyState propState = (PropertyState) stateMgr.getItemState(new PropertyId(nodeId, NameConstants.JCR_LOCKOWNER));
nodeState.removePropertyName(NameConstants.JCR_LOCKOWNER);
stateMgr.destroy(propState);
stateMgr.store(nodeState);
}
if (nodeState.hasPropertyName(NameConstants.JCR_LOCKISDEEP)) {
PropertyState propState = (PropertyState) stateMgr.getItemState(new PropertyId(nodeId, NameConstants.JCR_LOCKISDEEP));
nodeState.removePropertyName(NameConstants.JCR_LOCKISDEEP);
stateMgr.destroy(propState);
stateMgr.store(nodeState);
}
stateMgr.update();
success = true;
} catch (ItemStateException e) {
throw new RepositoryException("Error while removing lock.", e);
} finally {
if (!success) {
// failed to set lock meta-data content, cleanup
stateMgr.cancel();
}
}
} finally {
releaseLockPropertiesLock();
}
}
use of org.apache.jackrabbit.core.id.PropertyId in project jackrabbit by apache.
the class LockManagerImpl method writeLockProperties.
/**
* Add the lock related properties to the target node.
*
* @param node
* @param lockOwner
* @param isDeep
*/
protected void writeLockProperties(NodeImpl node, String lockOwner, boolean isDeep) throws RepositoryException {
boolean success = false;
SessionImpl editingSession = (SessionImpl) node.getSession();
WorkspaceImpl wsp = (WorkspaceImpl) editingSession.getWorkspace();
UpdatableItemStateManager stateMgr = wsp.getItemStateManager();
try {
acquireLockPropertiesLock();
if (stateMgr.inEditMode()) {
throw new RepositoryException("Unable to write lock properties.");
}
stateMgr.edit();
try {
// add properties to content
NodeId nodeId = node.getNodeId();
NodeState nodeState = (NodeState) stateMgr.getItemState(nodeId);
PropertyState propState;
if (!nodeState.hasPropertyName(NameConstants.JCR_LOCKOWNER)) {
propState = stateMgr.createNew(NameConstants.JCR_LOCKOWNER, nodeId);
propState.setType(PropertyType.STRING);
propState.setMultiValued(false);
} else {
propState = (PropertyState) stateMgr.getItemState(new PropertyId(nodeId, NameConstants.JCR_LOCKOWNER));
}
propState.setValues(new InternalValue[] { InternalValue.create(lockOwner) });
nodeState.addPropertyName(NameConstants.JCR_LOCKOWNER);
stateMgr.store(nodeState);
if (!nodeState.hasPropertyName(NameConstants.JCR_LOCKISDEEP)) {
propState = stateMgr.createNew(NameConstants.JCR_LOCKISDEEP, nodeId);
propState.setType(PropertyType.BOOLEAN);
propState.setMultiValued(false);
} else {
propState = (PropertyState) stateMgr.getItemState(new PropertyId(nodeId, NameConstants.JCR_LOCKISDEEP));
}
propState.setValues(new InternalValue[] { InternalValue.create(isDeep) });
nodeState.addPropertyName(NameConstants.JCR_LOCKISDEEP);
stateMgr.store(nodeState);
stateMgr.update();
success = true;
} catch (ItemStateException e) {
throw new RepositoryException("Error while creating lock.", e);
} finally {
if (!success) {
// failed to set lock meta-data content, cleanup
stateMgr.cancel();
try {
unlock(node);
} catch (RepositoryException e) {
// cleanup failed
log.error("error while cleaning up after failed lock attempt", e);
}
}
}
} finally {
releaseLockPropertiesLock();
}
}
use of org.apache.jackrabbit.core.id.PropertyId in project jackrabbit by apache.
the class SharedItemStateManager method createInstance.
/**
* Create a new property state instance
*
* @param propName property name
* @param parentId parent Id
* @return new property state instance
*/
private PropertyState createInstance(Name propName, NodeId parentId) {
PropertyState state = persistMgr.createNew(new PropertyId(parentId, propName));
state.setStatus(ItemState.STATUS_NEW);
state.setContainer(this);
return state;
}
use of org.apache.jackrabbit.core.id.PropertyId in project jackrabbit by apache.
the class NodeStateMerger method conflicts.
/**
*
* @param state The state of the node to be saved.
* @param addedMixins The added mixins to be used for testing
* @param ctx
* @param compareToOverlayed
* @return true if a conflict can be determined, false otherwise.
*/
private static boolean conflicts(NodeState state, Set<Name> addedMixins, MergeContext ctx, boolean compareToOverlayed) {
try {
// if the mixin defines residual item definitions -> return false.
for (Name mixinName : addedMixins) {
EffectiveNodeType ent = ctx.getEffectiveNodeType(mixinName);
if (ent.getUnnamedItemDefs().length > 0) {
// easily determine conflicts
return false;
}
NodeState overlayed = (NodeState) state.getOverlayedState();
for (ChildNodeEntry cne : state.getChildNodeEntries()) {
if (ent.getNamedNodeDefs(cne.getName()).length > 0) {
if (ctx.isAdded(cne.getId()) || isAutoCreated(cne, ent)) {
if (!compareToOverlayed || overlayed.hasChildNodeEntry(cne.getName())) {
return true;
}
}
// else: neither added nor autocreated in 'state' .
}
// else: child node not defined by the added mixin type
}
for (Name propName : state.getPropertyNames()) {
if (ent.getNamedPropDefs(propName).length > 0) {
PropertyId pid = new PropertyId(state.getNodeId(), propName);
if (ctx.isAdded(pid) || isAutoCreated(propName, ent)) {
if (!compareToOverlayed || overlayed.hasPropertyName(propName)) {
return true;
}
}
// else: neither added nor autocreated in 'state'
}
// else: property not defined by added mixin
}
}
} catch (NoSuchNodeTypeException e) {
// unable to determine collision
return true;
}
// no conflict detected
return false;
}
Aggregations