in jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java [570:781]
public void begin() throws ItemStateException, ReferentialIntegrityException {
shared = new ChangeLog();
virtualNodeReferences = new ChangeLog[virtualProviders.length];
// let listener know about change
try {
eventChannel.updateCreated(this);
} catch (ClusterException e) {
throw new ItemStateException(e.getMessage(), e);
}
try {
writeLock = acquireWriteLock(local);
} finally {
if (writeLock == null) {
eventChannel.updateCancelled(this);
}
}
boolean succeeded = false;
try {
if (usesReferences) {
// Update node references based on modifications in change
// log (added/modified/removed REFERENCE properties)
updateReferences();
}
// If enabled, check whether reference targets
// exist/were not removed
if (checkReferences) {
checkReferentialIntegrity();
}
/**
* prepare the events. this needs to be after the referential
* integrity check, since another transaction could have modified
* the states.
*/
try {
events = factory.createEventStateCollection();
} catch (RepositoryException e) {
String msg = "Unable to create event state collection.";
log.error(msg);
throw new ItemStateException(msg, e);
}
/**
* Reconnect all items contained in the change log to their
* respective shared item and add the shared items to a
* new change log.
*/
for (ItemState state : local.modifiedStates()) {
state.connect(getItemState(state.getId()));
if (state.isStale()) {
boolean merged = false;
if (state.isNode()) {
NodeStateMerger.MergeContext context =
new NodeStateMerger.MergeContext() {
public boolean isAdded(ItemId id) {
try {
ItemState is = local.get(id);
return is != null
&& is.getStatus() == ItemState.STATUS_NEW;
} catch (NoSuchItemStateException e) {
return false;
}
}
public boolean isDeleted(ItemId id) {
return local.deleted(id);
}
public boolean isModified(ItemId id) {
return local.isModified(id);
}
public boolean allowsSameNameSiblings(NodeId id) {
try {
NodeState ns = getNodeState(id);
NodeState parent = getNodeState(ns.getParentId());
Name name = parent.getChildNodeEntry(id).getName();
EffectiveNodeType ent = ntReg.getEffectiveNodeType(
parent.getNodeTypeName(),
parent.getMixinTypeNames());
QNodeDefinition def = ent.getApplicableChildNodeDef(name, ns.getNodeTypeName(), ntReg);
return def != null ? def.allowsSameNameSiblings() : false;
} catch (Exception e) {
log.warn("Unable to get node definition", e);
return false;
}
}
public EffectiveNodeType getEffectiveNodeType(Name ntName) throws NoSuchNodeTypeException {
return ntReg.getEffectiveNodeType(ntName);
}
public NodeState getNodeState(NodeId id)
throws ItemStateException {
if (local.has(id)) {
return (NodeState) local.get(id);
} else {
return (NodeState) getItemState(id);
}
}
};
merged = NodeStateMerger.merge((NodeState) state, context);
}
if (!merged) {
String msg = state.getId() + " has been modified externally";
log.debug(msg);
throw new StaleItemStateException(msg);
}
// merge succeeded, fall through
}
// update modification count (will be persisted as well)
state.getOverlayedState().touch();
shared.modified(state.getOverlayedState());
}
Iterator<ItemState> deleted = local.deletedStates().iterator();
while (deleted.hasNext()) {
ItemState state = deleted.next();
try {
state.connect(getItemState(state.getId()));
if (state.isStale()) {
String msg = state.getId() + " has been modified externally";
log.debug(msg);
throw new StaleItemStateException(msg);
}
shared.deleted(state.getOverlayedState());
} catch (NoSuchItemStateException e) {
// item state was already deleted externally
deleted.remove();
}
}
for (ItemState state : local.addedStates()) {
if (state.isNode() && state.getStatus() != ItemState.STATUS_NEW) {
// another node with same id had been created
// in the meantime, probably caused by mid-air collision
// of concurrent versioning operations (JCR-2272)
String msg = state.getId()
+ " has been created externally (status "
+ state.getStatus() + ")";
log.debug(msg);
throw new StaleItemStateException(msg);
}
state.connect(createInstance(state));
shared.added(state.getOverlayedState());
}
// filter out virtual node references for later processing
// (see comment above)
for (NodeReferences refs : local.modifiedRefs()) {
boolean virtual = false;
NodeId id = refs.getTargetId();
for (int i = 0; i < virtualProviders.length; i++) {
if (virtualProviders[i].hasItemState(id)) {
ChangeLog virtualRefs = virtualNodeReferences[i];
if (virtualRefs == null) {
virtualRefs = new ChangeLog();
virtualNodeReferences[i] = virtualRefs;
}
virtualRefs.modified(refs);
virtual = true;
break;
}
}
if (!virtual) {
// if target of node reference does not lie in a virtual
// space, add to modified set of normal provider.
shared.modified(refs);
}
}
checkAddedChildNodes();
/* create event states */
events.createEventStates(rootNodeId, local, SharedItemStateManager.this);
// let listener know about change
try {
eventChannel.updatePrepared(this);
} catch (ClusterException e) {
throw new ItemStateException(e.getMessage(), e);
}
if (VALIDATE_HIERARCHY) {
log.debug("Validating change-set hierarchy");
try {
validateHierarchy(local);
} catch (ItemStateException e) {
throw e;
} catch (RepositoryException e) {
throw new ItemStateException("Invalid hierarchy", e);
}
}
/* Push all changes from the local items to the shared items */
local.push();
succeeded = true;
} finally {
if (!succeeded) {
cancel();
}
}
}