/* * 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 org.exoplatform.services.jcr.impl.Constants; import java.io.ByteArrayInputStream; import java.util.Calendar; import javax.jcr.Node; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.UnsupportedRepositoryOperationException; import javax.jcr.lock.LockException; import javax.jcr.version.Version; import javax.jcr.version.VersionException; /** * <code>TestVersionRestore</code> covers tests related to the methods of the * {@link javax.jcr.version.Version} class. * * @test * @sources TestVersionRestore.java * @executeClass org.apache.jackrabbit.test.api.version.VersionTest * @keywords versioning */ public class TestVersionRestore extends BaseVersionTest { /** * Tests if we add one node to versionable and checkin. Later we have to be able to restore each * one version created. * * We have versionableNode node of type nt:folder. OPV is VERSION. So, we have to add a version on * the node child node. */ public void testRestore() throws Exception { try { // Preparing versions Node doc = versionableNode.addNode("doc1", "nt:file"); Node docContent = doc.addNode("jcr:content", "nt:unstructured"); docContent.setProperty("doc1ContentProperty", "doc1 content"); // doc2/jcr:content/ // doc1ContentProperty root.save(); // Version verDoc1 = doc.checkin(); // make a version for doc1 Version ver1 = versionableNode.checkin(); versionableNode.checkout(); doc = versionableNode.addNode("doc2", "nt:file"); docContent = doc.addNode("jcr:content", "nt:unstructured"); docContent.setProperty("doc2ContentProperty", "doc2 content"); // doc2/jcr:content/ // doc2ContentProperty makeVersionable(doc); root.save(); doc.checkin(); doc.checkout(); root.save(); Version ver2 = versionableNode.checkin(); versionableNode.checkout(); doc = versionableNode.addNode("doc3", "nt:file"); doc.addNode("jcr:content", "nt:base"); // makeVersionable(doc); root.save(); Version ver3 = versionableNode.checkin(); versionableNode.checkout(); // Check version consistency // do restore ver1 versionableNode.restore(ver1, true); Node doc1 = checkExisted("doc1", new String[]{"jcr:content/jcr:primaryType", "jcr:content/doc1ContentProperty"}); Node doc2 = checkExisted("doc2", new String[]{"jcr:content/jcr:primaryType", "jcr:content/doc2ContentProperty"}); checkNotExisted("doc3"); versionableNode.checkout(); doc1.remove(); root.save(); // doc1.save();ipossible to call save() on removed node // do restore ver2 versionableNode.restore(ver2, true); doc1 = checkExisted("doc1", new String[]{"jcr:content/jcr:primaryType", "jcr:content/doc1ContentProperty"}); doc2 = checkExisted("doc2", new String[]{"jcr:content/jcr:primaryType", "jcr:content/doc2ContentProperty"}); checkNotExisted("doc3"); return; } catch (UnsupportedRepositoryOperationException e) { log.error("testRestore()", e); throw e; } catch (VersionException e) { log.error("testRestore()", e); throw e; } catch (LockException e) { log.error("testRestore()", e); throw e; } catch (RepositoryException e) { log.error("testRestore()", e); throw e; } catch (Exception e) { log.error("testRestore()", e); throw e; } // fail("An exception occurs in testRestore()"); } /** * Test right version number calculation. We wuill create three version then delete second and * create one new. Tha last version must have number 4. */ public void testDelete() throws Exception { try { // Preparing versions Node doc = versionableNode.addNode("doc1", "nt:file"); Node docContent = doc.addNode("jcr:content", "nt:unstructured"); docContent.setProperty("doc1ContentProperty", "doc1 content"); // doc2/jcr:content/ // doc1ContentProperty root.save(); // Version verDoc1 = doc.checkin(); // make a version for doc1 Version ver1 = versionableNode.checkin(); versionableNode.checkout(); doc = versionableNode.addNode("doc2", "nt:file"); docContent = doc.addNode("jcr:content", "nt:unstructured"); docContent.setProperty("doc2ContentProperty", "doc2 content"); // doc2/jcr:content/ // doc2ContentProperty makeVersionable(doc); root.save(); doc.checkin(); doc.checkout(); root.save(); Version ver2 = versionableNode.checkin(); versionableNode.checkout(); doc = versionableNode.addNode("doc3", "nt:file"); doc.addNode("jcr:content", "nt:base"); root.save(); versionableNode.checkin(); versionableNode.checkout(); // do delete the ver2 versionableNode.getVersionHistory().removeVersion(ver2.getName()); Version ver4 = versionableNode.checkin(); versionableNode.checkout(); assertEquals("Version created has wrong version number", "4", ver4.getName()); return; } catch (UnsupportedRepositoryOperationException e) { log.error("testDelete()", e); throw e; } catch (VersionException e) { log.error("testDelete()", e); throw e; } catch (LockException e) { log.error("testDelete()", e); throw e; } catch (RepositoryException e) { log.error("testDelete()", e); throw e; } catch (Exception e) { log.error("testDelete()", e); throw e; } } /** * Test if Node.restore(version, relPath, removeExisted) works ok with relPath different from * versionable node. The problem occurs with subnodes of versionable subtree which has * OnParentVersion.COPY or VERSION. * * @throws Exception */ public void testRestoreRelPath() throws Exception { // prepare Node vnode = root.addNode("versionableNode"); vnode.addMixin("mix:versionable"); root.save(); vnode.checkin();// v.1 vnode.checkout(); // Subnode will cause an error!!! vnode.addNode("Subnode").setProperty("Property", "property of subnode"); vnode.save(); Version v2 = vnode.checkin();// v.2 vnode.checkout(); vnode.addNode("Another subnode").setProperty("Property", "property of another subnode"); vnode.save(); vnode.checkin();// v.3 vnode.checkout(); // gen a relPath for a restore Node rnode = root.addNode("restoredNode"); root.save(); String relPath = "../" + rnode.getName() + "/" + vnode.getName() + "_restored"; // test it vnode.restore(v2, relPath, true); } /** * Test if Workspace.restore works ok with existing versionable childs. * * @throws Exception */ public void testWorkspaceRestore() throws Exception { Node nodeA = root.addNode("versionableNodeA"); nodeA.addMixin("mix:versionable"); root.save(); nodeA.checkin();// v.1 nodeA.checkout(); Node nodeB = nodeA.addNode("Subnode B"); nodeA.save(); nodeB.addMixin("mix:versionable"); nodeA.save(); nodeB.checkin();// B v.1 Node nodeC = nodeA.addNode("Subnode C"); nodeA.save(); nodeC.addMixin("mix:versionable"); nodeA.save(); nodeC.checkin();// C v.1 nodeC.checkout(); nodeC.setProperty("Property Y", nodeB); // ref to Subnode B nodeC.save(); Version vC = nodeC.checkin();// C v.2 nodeC.checkout(); nodeB.checkout(); nodeB.setProperty("Property X", nodeC); // ref to Subnode C nodeB.save(); Version vB = nodeB.checkin();// B v.2 nodeB.checkout(); // add some stuff nodeA.setProperty("Property", "property of subnode"); nodeA.save(); Version vA = nodeA.checkin();// v.3 nodeA.checkout(); nodeB.remove(); nodeC.remove(); nodeA.save(); Version[] vs = new Version[]{vA, vB, vC}; // test it session.getWorkspace().restore(vs, true);// restore A v.3, B v.2, C v.2 // get node B and restore v1 nodeB = (Node)session.getItem("/versionableNodeA/Subnode B"); assertTrue(nodeB.isNodeType("mix:versionable")); nodeB.restore("1", true); // get node C and restore v1 nodeC = (Node)session.getItem("/versionableNodeA/Subnode C"); assertTrue(nodeB.isNodeType("mix:versionable")); nodeC.restore("1", true); // get node A and restore v2 nodeA = (Node)session.getItem("/versionableNodeA"); assertTrue(nodeB.isNodeType("mix:versionable")); nodeA.restore("1", true); } /** * Tests multiple restores of same version. * * @throws Exception * if error */ public void testMultipleRestore() throws Exception { String content = "Binary content"; byte[] bytes = content.getBytes(Constants.DEFAULT_ENCODING); Node file = root.addNode("testMultipleRestore_File", "nt:file"); Node contentNode = file.addNode("jcr:content", "nt:resource"); contentNode.setProperty("jcr:data", content, PropertyType.BINARY); contentNode.setProperty("jcr:mimeType", "text/plain"); contentNode.setProperty("jcr:lastModified", session.getValueFactory().createValue(Calendar.getInstance())); file.addMixin("mix:versionable"); session.save(); file.checkin(); // v1 file.checkout(); compareStream(new ByteArrayInputStream(bytes), file.getNode("jcr:content").getProperty("jcr:data").getStream()); String content2 = content + " #2"; file.getNode("jcr:content").setProperty("jcr:data", content2, PropertyType.BINARY); file.save(); file.checkin(); // v2 file.checkout(); String content3 = content + " #3"; file.getNode("jcr:content").setProperty("jcr:data", content3, PropertyType.BINARY); session.save(); // restore version v2 Version v2 = file.getBaseVersion(); file.restore(v2, true); compareStream(new ByteArrayInputStream(content2.getBytes(Constants.DEFAULT_ENCODING)), file .getNode("jcr:content").getProperty("jcr:data").getStream()); // restore version v1 Version v1 = file.getBaseVersion().getPredecessors()[0]; file.restore(v1, true); compareStream(new ByteArrayInputStream(bytes), file.getNode("jcr:content").getProperty("jcr:data").getStream()); // restore version v2 again file.restore(v2, true); compareStream(new ByteArrayInputStream(content2.getBytes(Constants.DEFAULT_ENCODING)), file .getNode("jcr:content").getProperty("jcr:data").getStream()); } }