Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java (revision 793243) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/LocalItemStateManager.java Thu Aug 27 12:20:11 CEST 2009 @@ -407,11 +407,19 @@ try { local = changeLog.get(created.getId()); if (local != null) { + if (local.getOverlayedState() == created) { - // underlying state has been permanently created - local.pull(); - local.setStatus(ItemState.STATUS_EXISTING); - cache.cache(local); + // underlying state has been permanently created + local.pull(); + local.setStatus(ItemState.STATUS_EXISTING); + cache.cache(local); + } else { + // mid-air collision of concurrent item state creation + // with same id (JCR-2272) + if (local.getStatus() == ItemState.STATUS_NEW) { + local.setStatus(ItemState.STATUS_STALE_MODIFIED); - } + } + } + } } catch (NoSuchItemStateException e) { /* ignore */ } Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java (revision 803470) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java Thu Aug 27 15:38:58 CEST 2009 @@ -20,6 +20,7 @@ import java.util.HashMap; import java.util.List; import java.util.Set; +import java.util.Calendar; import javax.jcr.PropertyType; import javax.jcr.ReferentialIntegrityException; @@ -48,6 +49,7 @@ import org.apache.jackrabbit.core.virtual.VirtualItemStateProvider; import org.apache.jackrabbit.spi.Name; import org.apache.jackrabbit.spi.commons.name.NameConstants; +import org.apache.jackrabbit.JcrConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -631,7 +633,7 @@ return false; } NodeDef def = ntReg.getNodeDef(ns.getDefinitionId()); - return def != null ? def.allowsSameNameSiblings() : false; + return def != null && def.allowsSameNameSiblings(); } }; @@ -660,9 +662,69 @@ shared.deleted(state.getOverlayedState()); } for (ItemState state : local.addedStates()) { + if (state.isNode() && hasItemState(state.getId())) { + // node with same id already exists, + // probably caused by mid-air collision of + // concurrent versioning operations (JCR-2272) + if (state.getStatus() != ItemState.STATUS_NEW) { + String msg = state.getId() + " has been created externally"; + log.debug(msg); + throw new StaleItemStateException(msg); + } + + state.connect(getItemState(state.getId())); + // update modification count (will be persisted as well) + state.getOverlayedState().touch(); + 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) { + NodeState ns; + try { + if (local.has(id)) { + ns = (NodeState) local.get(id); + } else { + ns = (NodeState) getItemState(id); + } + } catch (ItemStateException e) { + return false; + } + NodeDef def = ntReg.getNodeDef(ns.getDefinitionId()); + return def != null && def.allowsSameNameSiblings(); + } + }; + + if (NodeStateMerger.merge((NodeState) state, context)) { + state.setStatus(ItemState.STATUS_EXISTING_MODIFIED); + shared.modified(state.getOverlayedState()); + } else { + String msg = state.getId() + " has been created externally"; + log.debug(msg); + throw new StaleItemStateException(msg); + } + + } else { - state.connect(createInstance(state)); - shared.added(state.getOverlayedState()); - } + state.connect(createInstance(state)); + shared.added(state.getOverlayedState()); + } + } // filter out virtual node references for later processing // (see comment above) Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NodeStateMerger.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NodeStateMerger.java (revision 792437) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NodeStateMerger.java Thu Aug 27 14:50:04 CEST 2009 @@ -69,8 +69,8 @@ * - either session moved node */ - // compare current transient state with externally modified - // overlayed state and determine what has been changed by whom + // compare current state with externally modified overlayed + // state and determine what has been changed by whom // child node entries order if (!state.getReorderedChildNodeEntries().isEmpty()) {