You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by tr...@apache.org on 2006/05/01 14:54:55 UTC
svn commit: r398589 - in /jackrabbit/trunk/jackrabbit/src:
main/java/org/apache/jackrabbit/core/version/
test/java/org/apache/jackrabbit/core/
Author: tripod
Date: Mon May 1 05:54:53 2006
New Revision: 398589
URL: http://svn.apache.org/viewcvs?rev=398589&view=rev
Log:
JCR-414 jcr:successors property not persisted correctly within a transaction
Modified:
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/InternalVersionHistoryImpl.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/InternalVersionImpl.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java
jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/XATest.java
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/InternalVersionHistoryImpl.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/InternalVersionHistoryImpl.java?rev=398589&r1=398588&r2=398589&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/InternalVersionHistoryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/InternalVersionHistoryImpl.java Mon May 1 05:54:53 2006
@@ -133,11 +133,14 @@
vMgr.versionCreated(v);
}
- // resolve successors and predecessors
- Iterator iter = versionCache.values().iterator();
- while (iter.hasNext()) {
- InternalVersionImpl v = (InternalVersionImpl) iter.next();
- v.resolvePredecessors();
+ // check for legacy version nodes that had 'virtual' jcr:successor property
+ if (rootVersion.getSuccessors().length==0 && versionCache.size()>1) {
+ // resolve successors and predecessors
+ Iterator iter = versionCache.values().iterator();
+ while (iter.hasNext()) {
+ InternalVersionImpl v = (InternalVersionImpl) iter.next();
+ v.legacyResolveSuccessors();
+ }
}
try {
@@ -183,8 +186,7 @@
InternalVersionImpl v = (InternalVersionImpl) tempVersionCache.remove(child.getNodeId());
if (v != null) {
v.clear();
- }
- if (v == null) {
+ } else {
v = new InternalVersionImpl(this, child, child.getName());
}
return v;
@@ -323,9 +325,6 @@
throw new ReferentialIntegrityException("Unable to remove version. At least once referenced.");
}
- // remove from persistance state
- node.removeNode(v.getName());
-
// unregister from labels
QName[] labels = v.internalGetLabels();
for (int i = 0; i < labels.length; i++) {
@@ -335,6 +334,9 @@
// detach from the version graph
v.internalDetach();
+ // remove from persistance state
+ node.removeNode(v.getName());
+
// and remove from history
versionCache.remove(v.getId());
vMgr.versionDestroyed(v);
@@ -430,11 +432,9 @@
NodeId versionId = new NodeId(UUID.randomUUID());
NodeStateEx vNode = node.addNode(name, QName.NT_VERSION, versionId, true);
- // initialize 'created' and 'predecessors'
+ // initialize 'created', 'predecessors' and 'successors'
vNode.setPropertyValue(QName.JCR_CREATED, InternalValue.create(Calendar.getInstance()));
vNode.setPropertyValues(QName.JCR_PREDECESSORS, PropertyType.REFERENCE, predecessors);
-
- // initialize 'empty' successors; their values are dynamically resolved
vNode.setPropertyValues(QName.JCR_SUCCESSORS, PropertyType.REFERENCE, InternalValue.EMPTY_ARRAY);
// checkin source node
@@ -442,11 +442,12 @@
// update version graph
InternalVersionImpl version = new InternalVersionImpl(this, vNode, name);
- version.resolvePredecessors();
- vMgr.versionCreated(version);
+ version.internalAttach();
// and store
node.store();
+
+ vMgr.versionCreated(version);
// update cache
versionCache.put(version.getId(), version);
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/InternalVersionImpl.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/InternalVersionImpl.java?rev=398589&r1=398588&r2=398589&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/InternalVersionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/InternalVersionImpl.java Mon May 1 05:54:53 2006
@@ -27,6 +27,7 @@
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashSet;
+import java.util.List;
/**
* Implements a <code>InternalVersion</code>
@@ -35,16 +36,6 @@
implements InternalVersion {
/**
- * the list/cache of predecessors (values == InternalVersion)
- */
- private ArrayList predecessors = new ArrayList();
-
- /**
- * the list of successors (values == InternalVersion)
- */
- private ArrayList successors = new ArrayList();
-
- /**
* the underlying persistance node of this version
*/
private NodeStateEx node;
@@ -143,22 +134,43 @@
* {@inheritDoc}
*/
public InternalVersion[] getSuccessors() {
- return (InternalVersionImpl[]) successors.toArray(new InternalVersionImpl[successors.size()]);
+ InternalValue[] values = node.getPropertyValues(QName.JCR_SUCCESSORS);
+ if (values != null) {
+ InternalVersion[] versions = new InternalVersion[values.length];
+ for (int i = 0; i < values.length; i++) {
+ NodeId vId = new NodeId((UUID) values[i].internalValue());
+ versions[i] = versionHistory.getVersion(vId);
+ }
+ return versions;
+ } else {
+ return new InternalVersion[0];
+ }
}
/**
* {@inheritDoc}
*/
public InternalVersion[] getPredecessors() {
- return (InternalVersionImpl[]) predecessors.toArray(new InternalVersionImpl[predecessors.size()]);
+ InternalValue[] values = node.getPropertyValues(QName.JCR_PREDECESSORS);
+ if (values != null) {
+ InternalVersion[] versions = new InternalVersion[values.length];
+ for (int i = 0; i < values.length; i++) {
+ NodeId vId = new NodeId((UUID) values[i].internalValue());
+ versions[i] = versionHistory.getVersion(vId);
+ }
+ return versions;
+ } else {
+ return new InternalVersion[0];
+ }
}
/**
* {@inheritDoc}
*/
public boolean isMoreRecent(InternalVersion v) {
- for (int i = 0; i < predecessors.size(); i++) {
- InternalVersion pred = (InternalVersion) predecessors.get(i);
+ InternalVersion[] preds = getPredecessors();
+ for (int i = 0; i < preds.length; i++) {
+ InternalVersion pred = preds[i];
if (pred.equals(v) || pred.isMoreRecent(v)) {
return true;
}
@@ -195,51 +207,28 @@
}
/**
- * resolves the predecessors property and indirectly adds it self to their
- * successor list.
- */
- void resolvePredecessors() {
- InternalValue[] values = node.getPropertyValues(QName.JCR_PREDECESSORS);
- if (values != null) {
- for (int i = 0; i < values.length; i++) {
- NodeId vId = new NodeId((UUID) values[i].internalValue());
- InternalVersionImpl v = (InternalVersionImpl) versionHistory.getVersion(vId);
- predecessors.add(v);
- v.addSuccessor(this);
- }
- }
- }
-
- /**
* Clear the list of predecessors/successors and the label cache.
*/
void clear() {
- successors.clear();
- predecessors.clear();
labelCache = null;
}
/**
- * adds a successor version to the internal cache
- *
- * @param successor
- */
- private void addSuccessor(InternalVersion successor) {
- successors.add(successor);
- }
-
- /**
- * stores the internal predecessor cache to the persistance node
+ * stores the given successors or predecessors to the persistance node
*
* @throws RepositoryException
*/
- private void storePredecessors() throws RepositoryException {
- InternalValue[] values = new InternalValue[predecessors.size()];
+ private void storeXCessors(List cessors, QName propname, boolean store)
+ throws RepositoryException {
+ InternalValue[] values = new InternalValue[cessors.size()];
for (int i = 0; i < values.length; i++) {
values[i] = InternalValue.create(
- ((InternalVersion) predecessors.get(i)).getId().getUUID());
+ ((InternalVersion) cessors.get(i)).getId().getUUID());
+ }
+ node.setPropertyValues(propname, PropertyType.STRING, values);
+ if (store) {
+ node.store();
}
- node.setPropertyValues(QName.JCR_PREDECESSORS, PropertyType.STRING, values);
}
/**
@@ -249,15 +238,15 @@
*/
void internalDetach() throws RepositoryException {
// detach this from all successors
- InternalVersionImpl[] succ = (InternalVersionImpl[]) getSuccessors();
+ InternalVersion[] succ = getSuccessors();
for (int i = 0; i < succ.length; i++) {
- succ[i].internalDetachPredecessor(this);
+ ((InternalVersionImpl) succ[i]).internalDetachPredecessor(this, true);
}
// detach cached successors from preds
- InternalVersionImpl[] preds = (InternalVersionImpl[]) getPredecessors();
+ InternalVersion[] preds = getPredecessors();
for (int i = 0; i < preds.length; i++) {
- preds[i].internalDetachSuccessor(this);
+ ((InternalVersionImpl) preds[i]).internalDetachSuccessor(this, true);
}
// clear properties
@@ -265,6 +254,35 @@
}
/**
+ * Attaches this version as successor to all predecessors. assuming that the
+ * predecessors are already set.
+ *
+ * @throws RepositoryException
+ */
+ void internalAttach() throws RepositoryException {
+ InternalVersion[] preds = getPredecessors();
+ for (int i = 0; i < preds.length; i++) {
+ ((InternalVersionImpl) preds[i]).internalAddSuccessor(this, true);
+ }
+ }
+
+ /**
+ * Adds a version to the set of successors.
+ *
+ * @param succ
+ * @param store
+ * @throws RepositoryException
+ */
+ private void internalAddSuccessor(InternalVersionImpl succ, boolean store)
+ throws RepositoryException {
+ List l = new ArrayList(Arrays.asList(getSuccessors()));
+ if (!l.contains(succ)) {
+ l.add(succ);
+ storeXCessors(l, QName.JCR_SUCCESSORS, store);
+ }
+ }
+
+ /**
* Removes the predecessor V of this predecessors list and adds all of Vs
* predecessors to it.
* <p/>
@@ -272,18 +290,15 @@
*
* @param v the successor to detach
*/
- private void internalDetachPredecessor(InternalVersionImpl v) throws RepositoryException {
+ private void internalDetachPredecessor(InternalVersionImpl v, boolean store)
+ throws RepositoryException {
// remove 'v' from predecessor list
- for (int i = 0; i < predecessors.size(); i++) {
- if (predecessors.get(i).equals(v)) {
- predecessors.remove(i);
- break;
- }
- }
+ List l = new ArrayList(Arrays.asList(getPredecessors()));
+ l.remove(v);
+
// attach v's predecessors
- predecessors.addAll(Arrays.asList(v.getPredecessors()));
- storePredecessors();
- node.store();
+ l.addAll(Arrays.asList(v.getPredecessors()));
+ storeXCessors(l, QName.JCR_PREDECESSORS, store);
}
/**
@@ -294,16 +309,15 @@
*
* @param v the successor to detach
*/
- private void internalDetachSuccessor(InternalVersionImpl v) {
+ private void internalDetachSuccessor(InternalVersionImpl v, boolean store)
+ throws RepositoryException {
// remove 'v' from successors list
- for (int i = 0; i < successors.size(); i++) {
- if (successors.get(i).equals(v)) {
- successors.remove(i);
- break;
- }
- }
+ List l = new ArrayList(Arrays.asList(getSuccessors()));
+ l.remove(v);
+
// attach v's successors
- successors.addAll(Arrays.asList(v.getSuccessors()));
+ l.addAll(Arrays.asList(v.getSuccessors()));
+ storeXCessors(l, QName.JCR_SUCCESSORS, store);
}
/**
@@ -365,5 +379,42 @@
*/
void invalidate() {
node.getState().discard();
+ }
+
+ /**
+ * Resolves jcr:successor properties that are missing.
+ *
+ * @throws RepositoryException
+ */
+ void legacyResolveSuccessors() throws RepositoryException {
+ InternalValue[] values = node.getPropertyValues(QName.JCR_PREDECESSORS);
+ if (values != null) {
+ for (int i = 0; i < values.length; i++) {
+ NodeId vId = new NodeId((UUID) values[i].internalValue());
+ InternalVersionImpl v = (InternalVersionImpl) versionHistory.getVersion(vId);
+ v.internalAddSuccessor(this, false);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof InternalVersionImpl) {
+ InternalVersionImpl v = (InternalVersionImpl) obj;
+ return v.getId().equals(getId());
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ return getId().hashCode();
}
}
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java?rev=398589&r1=398588&r2=398589&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionItemStateProvider.java Mon May 1 05:54:53 2006
@@ -18,16 +18,13 @@
import org.apache.commons.collections.map.ReferenceMap;
import org.apache.jackrabbit.core.ItemId;
import org.apache.jackrabbit.core.NodeId;
-import org.apache.jackrabbit.core.PropertyId;
import org.apache.jackrabbit.core.state.ItemState;
import org.apache.jackrabbit.core.state.ItemStateException;
import org.apache.jackrabbit.core.state.ItemStateListener;
import org.apache.jackrabbit.core.state.NoSuchItemStateException;
import org.apache.jackrabbit.core.state.NodeReferences;
import org.apache.jackrabbit.core.state.NodeReferencesId;
-import org.apache.jackrabbit.core.state.PropertyState;
import org.apache.jackrabbit.core.state.SharedItemStateManager;
-import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.core.virtual.VirtualItemStateProvider;
import org.apache.jackrabbit.core.virtual.VirtualNodeState;
import org.apache.jackrabbit.core.virtual.VirtualPropertyState;
@@ -122,41 +119,8 @@
// attach us as listener
item.addListener(this);
-
- // special check for successors
- if (item instanceof PropertyState) {
- PropertyState prop = (PropertyState) item;
- if (prop.getName().equals(QName.JCR_SUCCESSORS)) {
- try {
- InternalVersion v = vMgr.getVersion(prop.getParentId());
- if (v != null) {
- InternalVersion[] succs = v.getSuccessors();
- InternalValue[] succV = new InternalValue[succs.length];
- for (int i = 0; i < succs.length; i++) {
- succV[i] = InternalValue.create(succs[i].getId().getUUID());
- }
- prop.setValues(succV);
- }
- } catch (RepositoryException e) {
- log.warn("Unable to resolve jcr:successors property for " + id);
- }
- }
- }
}
return item;
- }
-
- /**
- * called by the version manager when a dynamic property needs to be
- * invalidated.
- *
- * @param id
- */
- synchronized void onPropertyChanged(PropertyId id) {
- ItemState item = (ItemState) items.get(id);
- if (item != null) {
- item.discard();
- }
}
/**
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java?rev=398589&r1=398588&r2=398589&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java Mon May 1 05:54:53 2006
@@ -267,16 +267,8 @@
escFactory.doSourced((SessionImpl) node.getSession(), new SourcedTarget(){
public Object run() throws RepositoryException {
String histUUID = node.getProperty(QName.JCR_VERSIONHISTORY).getString();
- InternalVersion version = checkin((InternalVersionHistoryImpl)
+ return checkin((InternalVersionHistoryImpl)
getVersionHistory(NodeId.valueOf(histUUID)), node);
-
- // invalidate predecessors successor properties
- InternalVersion[] preds = version.getPredecessors();
- for (int i = 0; i < preds.length; i++) {
- PropertyId propId = new PropertyId(preds[i].getId(), QName.JCR_SUCCESSORS);
- versProvider.onPropertyChanged(propId);
- }
- return version;
}
});
@@ -301,18 +293,9 @@
escFactory.doSourced((SessionImpl) history.getSession(), new SourcedTarget(){
public Object run() throws RepositoryException {
- AbstractVersion version = (AbstractVersion) historyImpl.getNode(name);
- InternalVersion[] preds = version.getInternalVersion().getPredecessors();
-
InternalVersionHistoryImpl vh = (InternalVersionHistoryImpl)
historyImpl.getInternalVersionHistory();
removeVersion(vh, name);
-
- // invalidate predecessors successor properties
- for (int i = 0; i < preds.length; i++) {
- PropertyId propId = new PropertyId(preds[i].getId(), QName.JCR_SUCCESSORS);
- versProvider.onPropertyChanged(propId);
- }
return null;
}
});
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java?rev=398589&r1=398588&r2=398589&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/XAVersionManager.java Mon May 1 05:54:53 2006
@@ -354,6 +354,16 @@
if (history.getVersionManager() != this) {
history = makeLocalCopy(history);
xaItems.put(history.getId(), history);
+ // also put 'successor' and 'predecessor' version items to xaItem sets
+ InternalVersion v = history.getVersion(name);
+ InternalVersion[] vs = v.getSuccessors();
+ for (int i=0; i<vs.length; i++) {
+ xaItems.put(vs[i].getId(), vs[i]);
+ }
+ vs = v.getPredecessors();
+ for (int i=0; i<vs.length; i++) {
+ xaItems.put(vs[i].getId(), vs[i]);
+ }
}
super.removeVersion(history, name);
}
Modified: jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/XATest.java
URL: http://svn.apache.org/viewcvs/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/XATest.java?rev=398589&r1=398588&r2=398589&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/XATest.java (original)
+++ jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/XATest.java Mon May 1 05:54:53 2006
@@ -22,11 +22,15 @@
import javax.jcr.ItemNotFoundException;
import javax.jcr.Session;
import javax.jcr.RepositoryException;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.observation.Event;
import javax.jcr.version.VersionException;
import javax.jcr.version.Version;
import javax.jcr.lock.Lock;
import javax.transaction.UserTransaction;
import javax.transaction.RollbackException;
+import java.io.PrintWriter;
+import java.io.PrintStream;
/**
* <code>XATest</code> contains the test cases for the methods
@@ -925,6 +929,195 @@
// expected
}
}
+
+ /**
+ * Tests a couple of checkin/restore/remove operations on different
+ * workspaces and different transactions.
+ *
+ * @throws Exception
+ */
+ public void testXAVersionsThoroughly() throws Exception {
+ Session s1 = superuser;
+ Session s2 = helper.getSuperuserSession(workspaceName);
+
+ // add node and save
+ Node n1 = testRootNode.addNode(nodeName1, testNodeType);
+ n1.addMixin(mixVersionable);
+ testRootNode.save();
+
+ if (!s2.itemExists(testRootNode.getPath())) {
+ s2.getRootNode().addNode(testRootNode.getName());
+ s2.save();
+ }
+ s2.getWorkspace().clone(s1.getWorkspace().getName(), n1.getPath(), n1.getPath(), true);
+ Node n2 = (Node) s2.getItem(n1.getPath());
+
+ //log.println("---------------------------------------");
+ String phase="init";
+
+ Version v1_1 = n1.getBaseVersion();
+ Version v2_1 = n2.getBaseVersion();
+
+ check(v1_1, phase, "jcr:rootVersion", 0);
+ check(v2_1, phase, "jcr:rootVersion", 0);
+
+ //log.println("--------checkout/checkin n1 (uncommitted)----------");
+ phase="checkin N1 uncomitted.";
+
+ UserTransaction tx = new UserTransactionImpl(s1);
+ tx.begin();
+
+ n1.checkout();
+ n1.checkin();
+
+ Version v1_2 = n1.getBaseVersion();
+
+ check(v1_1, phase, "jcr:rootVersion", 1);
+ check(v2_1, phase, "jcr:rootVersion", 0);
+ check(v1_2, phase, "1.0", 0);
+
+ //log.println("--------checkout/checkin n1 (comitted)----------");
+ phase="checkin N1 committed.";
+
+ tx.commit();
+
+ check(v1_1, phase, "jcr:rootVersion", 1);
+ check(v2_1, phase, "jcr:rootVersion", 1);
+ check(v1_2, phase, "1.0", 0);
+
+ //log.println("--------restore n2 (uncommitted) ----------");
+ phase="restore N2 uncommitted.";
+
+ tx = new UserTransactionImpl(s2);
+ tx.begin();
+
+ n2.restore("1.0", false);
+ Version v2_2 = n2.getBaseVersion();
+
+ check(v1_1, phase, "jcr:rootVersion", 1);
+ check(v2_1, phase, "jcr:rootVersion", 1);
+ check(v1_2, phase, "1.0", 0);
+ check(v2_2, phase, "1.0", 0);
+
+ //log.println("--------restore n2 (comitted) ----------");
+ phase="restore N2 committed.";
+
+ tx.commit();
+
+ check(v1_1, phase, "jcr:rootVersion", 1);
+ check(v2_1, phase, "jcr:rootVersion", 1);
+ check(v1_2, phase, "1.0", 0);
+ check(v2_2, phase, "1.0", 0);
+
+ //log.println("--------checkout/checkin n2 (uncommitted) ----------");
+ phase="checkin N2 uncommitted.";
+
+ tx = new UserTransactionImpl(s2);
+ tx.begin();
+
+ n2.checkout();
+ n2.checkin();
+
+ Version v2_3 = n2.getBaseVersion();
+
+ check(v1_1, phase, "jcr:rootVersion", 1);
+ check(v2_1, phase, "jcr:rootVersion", 1);
+ check(v1_2, phase, "1.0", 0);
+ check(v2_2, phase, "1.0", 1);
+ check(v2_3, phase, "1.1", 0);
+
+ //log.println("--------checkout/checkin n2 (committed) ----------");
+ phase="checkin N2 committed.";
+
+ tx.commit();
+
+ check(v1_1, phase, "jcr:rootVersion", 1);
+ check(v2_1, phase, "jcr:rootVersion", 1);
+ check(v1_2, phase, "1.0", 1);
+ check(v2_2, phase, "1.0", 1);
+ check(v2_3, phase, "1.1", 0);
+
+ //log.println("--------checkout/checkin n1 (uncommitted) ----------");
+ phase="checkin N1 uncommitted.";
+
+ tx = new UserTransactionImpl(s1);
+ tx.begin();
+
+ n1.checkout();
+ n1.checkin();
+
+ Version v1_3 = n1.getBaseVersion();
+
+ check(v1_1, phase, "jcr:rootVersion", 1);
+ check(v2_1, phase, "jcr:rootVersion", 1);
+ check(v1_2, phase, "1.0", 2);
+ check(v2_2, phase, "1.0", 1);
+ check(v2_3, phase, "1.1", 0);
+ check(v1_3, phase, "1.1.1", 0);
+
+ //log.println("--------checkout/checkin n1 (committed) ----------");
+ phase="checkin N1 committed.";
+
+ tx.commit();
+
+ check(v1_1, phase, "jcr:rootVersion", 1);
+ check(v2_1, phase, "jcr:rootVersion", 1);
+ check(v1_2, phase, "1.0", 2);
+ check(v2_2, phase, "1.0", 2);
+ check(v2_3, phase, "1.1", 0);
+ check(v1_3, phase, "1.1.1", 0);
+
+ //log.println("--------remove n1-1.0 (uncommitted) ----------");
+ phase="remove N1 1.0 uncommitted.";
+
+ tx = new UserTransactionImpl(s1);
+ tx.begin();
+
+ n1.getVersionHistory().removeVersion("1.0");
+
+ check(v1_1, phase, "jcr:rootVersion", 2);
+ check(v2_1, phase, "jcr:rootVersion", 1);
+ check(v1_2, phase, "1.0", -1);
+ check(v2_2, phase, "1.0", 2);
+ check(v2_3, phase, "1.1", 0);
+ check(v1_3, phase, "1.1.1", 0);
+
+ //log.println("--------remove n1-1.0 (committed) ----------");
+ phase="remove N1 1.0 committed.";
+
+ tx.commit();
+
+ check(v1_1, phase, "jcr:rootVersion", 2);
+ check(v2_1, phase, "jcr:rootVersion", 2);
+ check(v1_2, phase, "1.0", -1);
+ check(v2_2, phase, "1.0", -1);
+ check(v2_3, phase, "1.1", 0);
+ check(v1_3, phase, "1.1.1", 0);
+
+ //s1.logout();
+ s2.logout();
+
+ }
+
+ /**
+ * helper method for {@link #testXAVersionsThoroughly()}
+ */
+ private void check(Version v, String phase, String name, int numSucc) {
+ String vName;
+ int vSucc = -1;
+ try {
+ vName = v.getName();
+ //vSucc = v.getProperty("jcr:successors").getValues().length;
+ vSucc = v.getSuccessors().length;
+ } catch (RepositoryException e) {
+ // node is invalid after remove
+ vName = name;
+ }
+ assertEquals(phase + " Version Name", name, vName);
+ assertEquals(phase + " Num Successors", numSucc, vSucc);
+ }
+
+
/**
* Test new version label becomes available to other sessions on commit.