/*
* Copyright (C) 2009 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.exoplatform.services.jcr.api.version;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.version.Version;
import javax.jcr.version.VersionException;
import javax.jcr.version.VersionHistory;
import javax.jcr.version.VersionIterator;
/**
* Created by The eXo Platform SAS 07.05.2006
*
* @author <a href="mailto:peter.nedonosko@exoplatform.com.ua">Peter
* Nedonosko</a>
* @version $Id: TestVersionHistory.java 11907 2008-03-13 15:36:21Z ksm $
*/
public class TestVersionHistory extends BaseVersionTest
{
private Node testRoot = null;
private Node testVersionable = null;
public void setUp() throws Exception
{
super.setUp();
testRoot = root.addNode("testRoot");
testVersionable = testRoot.addNode("testVersionable", "nt:unstructured");
testVersionable.addMixin("mix:versionable");
root.save();
}
protected void tearDown() throws Exception
{
try
{
testVersionable.checkout();
testRoot.remove();
root.save();
}
catch (RepositoryException e)
{
log.error("tear down error: " + e, e);
}
super.tearDown();
}
/**
* Scenario (script): Creating nodes: n1, n2 making: ver.1 Creating nodes:
* n1[2], n1[3], n1[4], n3 making: ver.2 Creating node: n4 making: ver.3
* Creating node: n5 making: ver.4 Removing nodes: n2, n4 Restoring ver.1:
* (n1, n2) Creating node: n6 making: ver.1.1 Removing nodes: n1, n6 Restoring
* ver.3: (n1, n1[2], n1[3], n1[4], n2, n3, n4) Creating node: n2[2] making:
* ver.3.1 making: ver.3.1.1 Restoring ver.2 (n1, n1[2], n1[3], n1[4], n2, n3)
* Creating node: n2[2] again!!! making: ver.2.1
* ------------------------------------------------- [PN] 08.05.06 Play in
* same play as above. There are some problems in CMS Web UI ('Manage Version'
* menu) if we will look on the version history of the /testVersionable node.
* After ver.3 was restored we create n2 (n2[2]) and make a new version
* ver.3.1. Then we go to 'Manage Version' menu item and will not see the base
* version (ver.3.1, name is '6'). Same case history if we restore ver.1.1
* (named '5'), then add a node in the /testVersionable and make checkin.
*/
public void testVersionHistoryTree() throws Exception
{
// testVersionable = versionableNode; // it's nt:folder
VersionHistory vHistory = testVersionable.getVersionHistory();
// Creating nodes: n1, n2
Node n1 = testVersionable.addNode("n1");
Node n2 = testVersionable.addNode("n2");
testVersionable.save();
Version ver1 = testVersionable.checkin(); // v1
vHistory.addVersionLabel(ver1.getName(), "ver.1", false);
testVersionable.checkout();
// sameNameSibs nodes
// Creating nodes: n1[2], n1[3], n1[4]
Node snsN1_2 = testVersionable.addNode("n1");
Node snsN1_3 = testVersionable.addNode("n1");
Node snsN1_4 = testVersionable.addNode("n1");
// Creating node: n3
Node n3 = testVersionable.addNode("n3");
testVersionable.save();
Version ver2 = testVersionable.checkin(); // v2
vHistory.addVersionLabel(ver2.getName(), "ver.2", false);
testVersionable.checkout();
// Creating node: n4
Node n4 = testVersionable.addNode("n4");
testVersionable.save();
Version ver3 = testVersionable.checkin(); // v3
vHistory.addVersionLabel(ver3.getName(), "ver.3", false);
vHistory.addVersionLabel(ver3.getName(), "version 3.0", false);
testVersionable.checkout();
// Creating node: n5
Node n5 = testVersionable.addNode("n5");
testVersionable.save();
Version ver4 = testVersionable.checkin(); // v4
vHistory.addVersionLabel(ver4.getName(), "ver.4", false);
testVersionable.checkout();
if (log.isDebugEnabled())
log.debug("===== init =====");
checkItemsExisted(new String[]{n1.getPath(), snsN1_2.getPath(), snsN1_3.getPath(), snsN1_4.getPath(),
n2.getPath(), n3.getPath(), n4.getPath(), n5.getPath()}, null);
checkVersionHistory(testVersionable, 4);
// removing nodes: n2, n4
n2.remove();
n4.remove();
testVersionable.save();
if (log.isDebugEnabled())
log.debug("===== ver.1 before restore =====");
checkItemsExisted(new String[]{n1.getPath(), snsN1_2.getPath(), snsN1_3.getPath(), snsN1_4.getPath(),
n3.getPath(), n5.getPath()}, new String[]{n2.getPath(), n4.getPath()});
checkVersionHistory(testVersionable, 4);
// RESTORE ver.1 and n1, n2 will be restored
testVersionable.restore(ver1, true);
if (log.isDebugEnabled())
log.debug("===== ver.1 after restore =====");
checkItemsExisted(new String[]{n1.getPath(), n2.getPath()}, new String[]{snsN1_2.getPath(), snsN1_3.getPath(),
snsN1_4.getPath(), n3.getPath(), n4.getPath(), n5.getPath()});
checkVersionHistory(testVersionable, 4);
testVersionable.checkout();
// adding nodes: n6
Node n6 = testVersionable.addNode("n6");
testVersionable.save();
Version ver11 = testVersionable.checkin(); // v1.1
vHistory.addVersionLabel(ver11.getName(), "ver.1.1", false);
if (log.isDebugEnabled())
log.debug("===== ver.1.1 =====");
checkItemsExisted(new String[]{n1.getPath(), n2.getPath(), n6.getPath()}, new String[]{snsN1_2.getPath(),
snsN1_3.getPath(), snsN1_4.getPath(), n3.getPath(), n4.getPath(), n5.getPath()});
checkVersionHistory(testVersionable, 5); // has five versions in history
testVersionable.checkout();
// removing nodes: n1, n6
n1.remove();
n6.remove();
testVersionable.save();
if (log.isDebugEnabled())
log.debug("===== ver.3 before restore =====");
checkItemsExisted(new String[]{n2.getPath()}, new String[]{n1.getPath(), snsN1_2.getPath(), snsN1_3.getPath(),
snsN1_4.getPath(), n2.getPath(), n3.getPath(), n4.getPath(), n5.getPath(), n6.getPath()});
checkVersionHistory(testVersionable, 5);
// RESTORE ver.3 and n1, n1_2, n1_3, n1_4, n2, n3, n4 will be restored
testVersionable.restore(ver3, true);
if (log.isDebugEnabled())
log.debug("===== ver.3 after restore =====");
checkItemsExisted(new String[]{n1.getPath(), snsN1_2.getPath(), snsN1_3.getPath(), snsN1_4.getPath(),
n2.getPath(), n3.getPath(), n4.getPath()}, new String[]{n5.getPath(), n6.getPath()});
checkVersionHistory(testVersionable, 5);
testVersionable.checkout();
// adding node: n2[2]
Node snsN2_2 = testVersionable.addNode("n2");
testVersionable.save();
Version ver31 = testVersionable.checkin(); // v3.1
vHistory.addVersionLabel(ver31.getName(), "ver.3.1", false);
if (log.isDebugEnabled())
log.debug("===== ver.3.1 =====");
checkItemsExisted(new String[]{n1.getPath(), snsN1_2.getPath(), snsN1_3.getPath(), snsN1_4.getPath(),
n2.getPath(), snsN2_2.getPath(), n3.getPath(), n4.getPath()}, new String[]{n5.getPath(), n6.getPath()});
checkVersionHistory(testVersionable, 6);
testVersionable.checkout();
Version ver311 = testVersionable.checkin(); // v3.1.1
vHistory.addVersionLabel(ver311.getName(), "ver.3.1.1", false);
if (log.isDebugEnabled())
log.debug("===== ver.2 before restore =====");
checkItemsExisted(new String[]{n1.getPath(), snsN1_2.getPath(), snsN1_3.getPath(), snsN1_4.getPath(),
n2.getPath(), snsN2_2.getPath(), n3.getPath(), n4.getPath()}, new String[]{n5.getPath(), n6.getPath()});
checkVersionHistory(testVersionable, 7);
// RESTORE ver.2 and n1, n1_2, n1_3, n1_4, n2, n3 will be restored
testVersionable.restore(ver2, true);
if (log.isDebugEnabled())
log.debug("===== ver.2 after restore =====");
// the node snsN2_2 points to a node with index 1 (result of reindex), i.e.
// n2 (n2[1])
checkItemsExisted(new String[]{n1.getPath(), snsN1_2.getPath(), snsN1_3.getPath(), snsN1_4.getPath(),
n2.getPath(), n3.getPath()}, new String[]{testVersionable.getPath() + "/n2[2]", n4.getPath(), n5.getPath(),
n6.getPath()});
checkVersionHistory(testVersionable, 7);
if (log.isDebugEnabled())
log.debug("===== ver.2.1 =====");
testVersionable.checkout();
// adding node: n2[2] again
Node snsN2_2_Other = testVersionable.addNode("n2"); // testVersionable.
// getNodes()
snsN1_3.refresh(true);
snsN1_3.remove();
// testVersionable.getNode(snsN1_3.getName() + "[3]").remove();
testVersionable.save(); // reindex: n1[4] -> n1[3]
Version ver21 = testVersionable.checkin(); // v2.1
vHistory.addVersionLabel(ver21.getName(), "ver.2.1", false);
// The node snsN2_2 has no actual node in the repository, it's phantom node
// with old state.
// But node with same path already created (snsN2_2_Other)!
//
// The node snsN1_3 has no actual node in the repository, it's phantom node
// with old state.
// But reindex done: n1[4] -> n1[3] and n1[3] already exists
//
checkItemsExisted(new String[]{n1.getPath(), snsN1_2.getPath(), snsN1_3.getPath(), n2.getPath(),
snsN2_2_Other.getPath(), n3.getPath()}, new String[]{n4.getPath(), n5.getPath(), n6.getPath()});
checkVersionHistory(testVersionable, 8);
}
public void testRemoveBaseVersion() throws Exception
{
Node testRemove = testRoot.addNode("testRemove", "nt:unstructured");
testRemove.setProperty("exo:test","V0");
testRemove.addMixin("mix:versionable");
root.save();
VersionHistory vHistory = testRemove.getVersionHistory();
VersionIterator versionIterator = vHistory.getAllVersions();
Version rootVersion = vHistory.getRootVersion();
assertEquals(1, versionIterator.getSize());
assertEquals(rootVersion.getName(), versionIterator.nextVersion().getName());
Version ver1 = testRemove.checkin();
vHistory.addVersionLabel(ver1.getName(), "v1", false);
testRemove.checkout();
versionIterator= vHistory.getAllVersions();
assertEquals(2, versionIterator.getSize());
Version ver2 = testRemove.checkin();
vHistory.addVersionLabel(ver2.getName(), "v2", false);
testRemove.checkout();
versionIterator= vHistory.getAllVersions();
assertEquals(3, versionIterator.getSize());
Version baseVersion = testRemove.getBaseVersion();
assertEquals(baseVersion.getName(),vHistory.getVersionByLabel("v2").getName());
try
{
vHistory.removeVersion(vHistory.getVersionByLabel("v2").getName());
}
catch (Exception e)
{
fail();
}
baseVersion = testRemove.getBaseVersion();
assertEquals(baseVersion.getName(),vHistory.getVersionByLabel("v1").getName());
versionIterator= vHistory.getAllVersions();
assertEquals(2, versionIterator.getSize());
try
{
vHistory.removeVersion(vHistory.getVersionByLabel("v1").getName());
}
catch (Exception e)
{
fail();
}
baseVersion = testRemove.getBaseVersion();
assertEquals(baseVersion.getName(), rootVersion.getName());
versionIterator= vHistory.getAllVersions();
assertEquals(1, versionIterator.getSize());
}
public void testRemoveBaseVersion1() throws Exception
{
Node testRemove = testRoot.addNode("testRemove", "nt:unstructured");
testRemove.setProperty("exo:test1","V0");
testRemove.addMixin("mix:versionable");
testRemove.addMixin("mix:lockable");
root.save();
VersionHistory vHistory = testRemove.getVersionHistory();
VersionIterator versionIterator = vHistory.getAllVersions();
assertEquals(1, versionIterator.getSize());
Version ver1 = testRemove.checkin();
vHistory.addVersionLabel(ver1.getName(), "v1", false);
testRemove.checkout();
versionIterator= vHistory.getAllVersions();
assertEquals(2, versionIterator.getSize());
Version ver2 = testRemove.checkin();
vHistory.addVersionLabel(ver2.getName(), "v2", false);
testRemove.checkout();
versionIterator= vHistory.getAllVersions();
assertEquals(3, versionIterator.getSize());
Version ver3 = testRemove.checkin();
vHistory.addVersionLabel(ver3.getName(), "v3", false);
testRemove.checkout();
try
{
vHistory.removeVersion(vHistory.getVersionByLabel("v3").getName());
//Expected
}
catch (Exception e)
{
fail();
}
Version baseVersion = testRemove.getBaseVersion();
assertEquals(baseVersion.getName(), vHistory.getVersionByLabel("v2").getName());
testRemove.restore(vHistory.getVersionByLabel("v1").getName(),true);
baseVersion = testRemove.getBaseVersion();
assertEquals(baseVersion.getName(), vHistory.getVersionByLabel("v1").getName());
vHistory.removeVersion(vHistory.getVersionByLabel("v1").getName());
baseVersion = testRemove.getBaseVersion();
assertEquals(baseVersion.getName(), vHistory.getRootVersion().getName());
testRemove.restore(vHistory.getVersionByLabel("v2").getName(),true);
baseVersion = testRemove.getBaseVersion();
assertEquals(baseVersion.getName(), vHistory.getVersionByLabel("v2").getName());
try
{
vHistory.removeVersion(vHistory.getVersionByLabel("v2").getName());
//Expected
}
catch (Exception e)
{
fail();
}
baseVersion = testRemove.getBaseVersion();
assertEquals(baseVersion.getName(), vHistory.getRootVersion().getName());
try
{
vHistory.removeVersion(vHistory.getRootVersion().getName());
fail();
}
catch (Exception e)
{
//Expected
}
}
private VersionHistory prepareHistory() throws Exception
{
VersionHistory vHistory = testVersionable.getVersionHistory();
if (log.isDebugEnabled())
log.debug("===== prepare =====");
showVersionable(testVersionable);
// Creating nodes: n1, n2
Node n1 = testVersionable.addNode("n1");
Node n2 = testVersionable.addNode("n2");
testVersionable.save();
Version ver1 = testVersionable.checkin(); // v1
vHistory.addVersionLabel(ver1.getName(), "ver.1", false);
if (log.isDebugEnabled())
log.debug("===== ver.1 checkin =====");
showVersionable(testVersionable);
testVersionable.checkout();
if (log.isDebugEnabled())
log.debug("===== ver.1 checkout =====");
showVersionable(testVersionable);
// sameNameSibs nodes
// Creating nodes: n1[2], n1[3], n1[4]
Node snsN1_2 = testVersionable.addNode("n1");
Node snsN1_3 = testVersionable.addNode("n1");
Node snsN1_4 = testVersionable.addNode("n1");
// Creating node: n3
Node n3 = testVersionable.addNode("n3");
testVersionable.save();
Version ver2 = testVersionable.checkin(); // v2
vHistory.addVersionLabel(ver2.getName(), "ver.2", false);
if (log.isDebugEnabled())
log.debug("===== ver.2 checkin =====");
showVersionable(testVersionable);
testVersionable.checkout();
if (log.isDebugEnabled())
log.debug("===== ver.2 checkout =====");
showVersionable(testVersionable);
// Creating node: n4
Node n4 = testVersionable.addNode("n4");
testVersionable.save();
Version ver3 = testVersionable.checkin(); // v3
vHistory.addVersionLabel(ver3.getName(), "ver.3", false);
vHistory.addVersionLabel(ver3.getName(), "version 3.0", false);
if (log.isDebugEnabled())
log.debug("===== ver.3 checkin =====");
showVersionable(testVersionable);
testVersionable.checkout();
if (log.isDebugEnabled())
log.debug("===== ver.3 checkout =====");
showVersionable(testVersionable);
// Creating node: n5
Node n5 = testVersionable.addNode("n5");
testVersionable.save();
Version ver4 = testVersionable.checkin(); // v4
vHistory.addVersionLabel(ver4.getName(), "ver.4", false);
if (log.isDebugEnabled())
log.debug("===== ver.4 checkin =====");
showVersionable(testVersionable);
testVersionable.checkout();
if (log.isDebugEnabled())
log.debug("===== ver.4 checkout =====");
showVersionable(testVersionable);
return vHistory;
}
public void testVersionRemove() throws Exception
{
// -------- prepare the case --------
VersionHistory vHistory = prepareHistory();
if (log.isDebugEnabled())
log.debug("===== init =====");
checkItemsExisted(new String[]{"/testRoot/testVersionable/n1", "/testRoot/testVersionable/n1[2]",
"/testRoot/testVersionable/n1[3]", "/testRoot/testVersionable/n1[4]", "/testRoot/testVersionable/n2",
"/testRoot/testVersionable/n3", "/testRoot/testVersionable/n4", "/testRoot/testVersionable/n5"}, null);
showVersionable(testVersionable);
checkVersionHistory(testVersionable, 4);
// -------- play with version remove --------
// we have v4 as base version, REMOVE v1 from history
vHistory.removeVersion(vHistory.getVersionByLabel("ver.1").getName());
if (log.isDebugEnabled())
log.debug("===== ver.1 removed =====");
showVersionable(testVersionable);
checkVersionHistory(testVersionable, 3);
try
{
vHistory.getVersion("1");
fail("ver.1 must be not existed");
}
catch (VersionException e)
{
// ok
}
// removing nodes: n2, n4
testVersionable.getNode("n2").remove();
testVersionable.getNode("n4").remove();
testVersionable.save();
if (log.isDebugEnabled())
log.debug("===== ver.3 before restore =====");
checkItemsExisted(new String[]{"/testRoot/testVersionable/n1", "/testRoot/testVersionable/n1[2]",
"/testRoot/testVersionable/n1[3]", "/testRoot/testVersionable/n1[4]", "/testRoot/testVersionable/n3",
"/testRoot/testVersionable/n5"}, new String[]{"/testRoot/testVersionable/n2", "/testRoot/testVersionable/n4"});
showVersionable(testVersionable);
checkVersionHistory(testVersionable, 3);
// RESTORE ver.3 and n1, n4 will be restored
testVersionable.restore(vHistory.getVersionByLabel("ver.3"), true);
if (log.isDebugEnabled())
log.debug("===== ver.3 after restore =====");
checkItemsExisted(new String[]{"/testRoot/testVersionable/n1", "/testRoot/testVersionable/n1[2]",
"/testRoot/testVersionable/n1[3]", "/testRoot/testVersionable/n1[4]", "/testRoot/testVersionable/n3",
"/testRoot/testVersionable/n4"}, new String[]{"/testRoot/testVersionable/n5"});
showVersionable(testVersionable);
checkVersionHistory(testVersionable, 3);
// testVersionable.checkout();
// // adding nodes: n6
// Node n6 = testVersionable.addNode("n6");
// testVersionable.save();
// Version ver11 = testVersionable.checkin(); // v1.1
// vHistory.addVersionLabel(ver11.getName(), "ver.1.1", false);
//
// log.info("===== ver.1.1 =====");
// checkItemsExisted(new String[] {n1.getPath(), n2.getPath(),
// n6.getPath()},
// new String[] {snsN1_2.getPath(), snsN1_3.getPath(), snsN1_4.getPath(),
// n3.getPath(),
// n4.getPath(), n5.getPath()});
// checkVersionHistory(testVersionable, 5); // has five versions in history
//
// testVersionable.checkout();
// // removing nodes: n1, n6
// n1.remove();
// n6.remove();
// testVersionable.save();
// log.info("===== ver.3 before restore =====");
// checkItemsExisted(new String[] {n2.getPath()},
// new String[] {n1.getPath(), snsN1_2.getPath(), snsN1_3.getPath(),
// snsN1_4.getPath(),
// n2.getPath(), n3.getPath(), n4.getPath(), n5.getPath(), n6.getPath()});
// checkVersionHistory(testVersionable, 5);
}
private void checkVersionableCopy(Node versionable1, Node versionable2) throws RepositoryException
{
String v1_VH_UUID = versionable1.getProperty("jcr:versionHistory").getString();
String v1_BV_UUID = versionable1.getProperty("jcr:baseVersion").getString();
try
{
String v2_VH_UUID = versionable2.getProperty("jcr:versionHistory").getString();
String v2_BV_UUID = versionable2.getProperty("jcr:baseVersion").getString();
assertNotSame("Copied node must has a new version history ", v1_VH_UUID, v2_VH_UUID);
assertNotSame("Copied node must has a new base version ", v1_BV_UUID, v2_BV_UUID);
// add new version to the source
versionable1.checkin();
versionable1.checkout();
v1_BV_UUID = versionable1.getProperty("jcr:baseVersion").getString();
v2_BV_UUID = versionable2.getProperty("jcr:baseVersion").getString();
assertNotSame("Copied node and its source versionable node must has a different version graphs (1) ",
v1_BV_UUID, v2_BV_UUID);
// add new version to the another versionable
versionable2.checkin();
versionable2.checkout();
v2_BV_UUID = versionable2.getProperty("jcr:baseVersion").getString();
assertNotSame("Copied node and its source versionable node must has a different version graphs (2) ",
v1_BV_UUID, v2_BV_UUID);
}
catch (RepositoryException e)
{
fail("Versionable node was not copied properly. " + e);
}
}
public void testCopyVersionable() throws Exception
{
// Node source = testRoot.addNode("node1");
session.getWorkspace().copy(testVersionable.getPath(), testRoot.getPath() + "/newVersionable");
checkVersionableCopy(testVersionable, testRoot.getNode("newVersionable"));
}
public void testCopyVersionableInAnotherWorkspace() throws Exception
{
Session ws1 = repository.login(credentials, "ws1");
ws1.getWorkspace().copy("ws", testVersionable.getPath(), "/newVersionable");
checkVersionableCopy(testVersionable, ws1.getRootNode().getNode("newVersionable"));
}
}