/*
* ModeShape (http://www.modeshape.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.modeshape.jcr;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.jcr.ImportUUIDBehavior;
import javax.jcr.ItemExistsException;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.security.AccessControlList;
import javax.jcr.security.AccessControlManager;
import javax.jcr.security.Privilege;
import javax.jcr.version.Version;
import org.junit.Test;
import org.modeshape.common.FixFor;
import org.modeshape.common.junit.SkipLongRunning;
import org.modeshape.common.util.FileUtil;
import org.modeshape.jcr.api.Binary;
import org.modeshape.jcr.api.JcrTools;
import org.modeshape.jcr.api.Workspace;
import org.modeshape.jcr.security.SimplePrincipal;
import org.modeshape.jcr.value.Name;
import org.modeshape.jcr.value.Path;
/**
* Tests of round-trip importing/exporting of repository content.
*/
public class ImportExportTest extends SingleUseAbstractTest {
private enum ExportType {
SYSTEM,
DOCUMENT
}
private static final String BAD_CHARACTER_STRING = "Test & <Test>*";
private String expectedIdentifier = "e41075cb-a09a-4910-87b1-90ce8b4ca9dd";
private void testImportExport( String sourcePath,
String targetPath,
ExportType useSystemView,
boolean skipBinary,
boolean noRecurse,
boolean useWorkspace ) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (useSystemView == ExportType.SYSTEM) {
session.exportSystemView(sourcePath, baos, skipBinary, noRecurse);
} else {
session.exportDocumentView(sourcePath, baos, skipBinary, noRecurse);
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
if (useWorkspace) {
// import via workspace ...
session.getWorkspace().importXML(targetPath, bais, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
} else {
// import via session ...
session.importXML(targetPath, bais, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
}
}
@Test
public void shouldImportExportEscapedXmlCharactersInSystemViewUsingSession() throws Exception {
String testName = "importExportEscapedXmlCharacters";
Node rootNode = session.getRootNode();
Node sourceNode = rootNode.addNode(testName + "Source", "nt:unstructured");
Node targetNode = rootNode.addNode(testName + "Target", "nt:unstructured");
// Test data
sourceNode.setProperty("badcharacters", BAD_CHARACTER_STRING);
assertThat(sourceNode.getProperty("badcharacters").getString(), is(BAD_CHARACTER_STRING));
sourceNode.addNode(BAD_CHARACTER_STRING);
testImportExport(sourceNode.getPath(), targetNode.getPath(), ExportType.SYSTEM, false, false, false);
Node newSourceNode = targetNode.getNode(testName + "Source");
newSourceNode.getNode(BAD_CHARACTER_STRING);
assertThat(newSourceNode.getProperty("badcharacters").getString(), is(BAD_CHARACTER_STRING));
}
@Test
public void shouldImportExportEscapedXmlCharactersInSystemViewUsingWorkspace() throws Exception {
String testName = "importExportEscapedXmlCharacters";
Node rootNode = session.getRootNode();
Node sourceNode = rootNode.addNode(testName + "Source", "nt:unstructured");
Node targetNode = rootNode.addNode(testName + "Target", "nt:unstructured");
// Test data
sourceNode.setProperty("badcharacters", BAD_CHARACTER_STRING);
assertThat(sourceNode.getProperty("badcharacters").getString(), is(BAD_CHARACTER_STRING));
sourceNode.addNode(BAD_CHARACTER_STRING);
session.save();
testImportExport(sourceNode.getPath(), targetNode.getPath(), ExportType.SYSTEM, false, false, true);
Node newSourceNode = targetNode.getNode(testName + "Source");
newSourceNode.getNode(BAD_CHARACTER_STRING);
assertThat(newSourceNode.getProperty("badcharacters").getString(), is(BAD_CHARACTER_STRING));
}
@FixFor("MODE-1405")
@Test
public void shouldImportProtectedContentUsingWorkpace() throws Exception {
String testName = "importExportEscapedXmlCharacters";
Node rootNode = session.getRootNode();
Node sourceNode = rootNode.addNode(testName + "Source", "nt:unstructured");
Node targetNode = rootNode.addNode(testName + "Target", "nt:unstructured");
// Test data
Node child = sourceNode.addNode("child");
child.addMixin("mix:created");
session.save();
// Verify there are 'jcr:createdBy' and 'jcr:created' properties ...
assertThat(child.getProperty("jcr:createdBy").getString(), is(notNullValue()));
assertThat(child.getProperty("jcr:created").getString(), is(notNullValue()));
testImportExport(sourceNode.getPath(), targetNode.getPath(), ExportType.SYSTEM, false, false, true);
Node newSourceNode = targetNode.getNode(testName + "Source");
Node newChild = newSourceNode.getNode("child");
// Verify there are 'jcr:createdBy' and 'jcr:created' properties ...
assertThat(newChild.getProperty("jcr:createdBy").getString(), is(notNullValue()));
assertThat(newChild.getProperty("jcr:created").getString(), is(notNullValue()));
}
@Test
public void shouldImportExportEscapedXmlCharactersInDocumentViewUsingSession() throws Exception {
String testName = "importExportEscapedXmlCharacters";
Node rootNode = session.getRootNode();
Node sourceNode = rootNode.addNode(testName + "Source", "nt:unstructured");
Node targetNode = rootNode.addNode(testName + "Target", "nt:unstructured");
// Test data
sourceNode.setProperty("badcharacters", BAD_CHARACTER_STRING);
assertThat(sourceNode.getProperty("badcharacters").getString(), is(BAD_CHARACTER_STRING));
sourceNode.addNode(BAD_CHARACTER_STRING);
testImportExport(sourceNode.getPath(), targetNode.getPath(), ExportType.DOCUMENT, false, false, false);
Node newSourceNode = targetNode.getNode(testName + "Source");
newSourceNode.getNode(BAD_CHARACTER_STRING);
assertThat(newSourceNode.getProperty("badcharacters").getString(), is(BAD_CHARACTER_STRING));
}
@Test
public void shouldImportSystemViewWithUuidsAfterNodesWithSameUuidsAreDeletedInSessionAndSaved() throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Create the node under which the content will be imported ...
session.getRootNode().addNode("/someNode");
session.save();
// Import the car content ...
importFile("/someNode", "io/cars-system-view-with-uuids.xml", ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
session.save();
// tools.printSubgraph(assertNode("/"));
// Now delete the '/someNode/Cars' node (which is everything that was imported) ...
Node cars = assertNode("/someNode/Cars");
assertThat(cars.getIdentifier(), is(expectedIdentifier));
assertNoNode("/someNode/Cars[2]");
assertNoNode("/someNode[2]");
cars.remove();
session.save();
// Now import again ...
importFile("/someNode", "io/cars-system-view-with-uuids.xml", ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
session.save();
// Verify the same Cars node exists ...
cars = assertNode("/someNode/Cars");
assertThat(cars.getIdentifier(), is(expectedIdentifier));
assertNoNode("/someNode/Cars[2]");
assertNoNode("/someNode[2]");
}
@Test
public void shouldImportSystemViewWithUuidsAfterNodesWithSameUuidsAreDeletedInSessionButNotSaved() throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Create the node under which the content will be imported ...
session.getRootNode().addNode("/someNode");
session.save();
// Import the car content ...
importFile("/someNode", "io/cars-system-view-with-uuids.xml", ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
session.save();
// Now delete the '/someNode/Cars' node (which is everything that was imported) ...
Node cars = assertNode("/someNode/Cars");
assertThat(cars.getIdentifier(), is(expectedIdentifier));
assertNoNode("/someNode/Cars[2]");
assertNoNode("/someNode[2]");
cars.remove();
assertNoNode("/someNode/Cars");
// session.save(); // DO NOT SAVE
// Now import again ...
importFile("/someNode", "io/cars-system-view-with-uuids.xml", ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
session.save();
// Verify the same Cars node exists ...
cars = assertNode("/someNode/Cars");
assertThat(cars.getIdentifier(), is(expectedIdentifier));
assertNoNode("/someNode/Cars[2]");
assertNoNode("/someNode[2]");
}
@Test
public void shouldImportSystemViewWithUuidsIntoDifferentSpotAfterNodesWithSameUuidsAreDeletedInSessionButNotSaved()
throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Create the node under which the content will be imported ...
Node someNode = session.getRootNode().addNode("/someNode");
session.getRootNode().addNode("/otherNode");
session.save();
// Import the car content ...
importFile("/someNode", "io/cars-system-view-with-uuids.xml", ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
session.save();
// Now delete the '/someNode/Cars' node (which is everything that was imported) ...
Node cars = assertNode("/someNode/Cars");
assertThat(cars.getIdentifier(), is(expectedIdentifier));
assertNoNode("/someNode/Cars[2]");
assertNoNode("/someNode[2]");
cars.remove();
// Now create a node at the same spot as cars, but with a different UUID ...
Node newCars = someNode.addNode("Cars");
assertThat(newCars.getIdentifier(), is(not(expectedIdentifier)));
// session.save(); // DO NOT SAVE
// Now import again ...
importFile("/otherNode", "io/cars-system-view-with-uuids.xml", ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
session.save();
// Verify the same Cars node exists ...
cars = assertNode("/otherNode/Cars");
assertThat(cars.getIdentifier(), is(expectedIdentifier));
// Make sure some duplicate nodes didn't show up ...
assertNoNode("/sameNode/Cars[2]");
assertNoNode("/sameNode[2]");
assertNoNode("/otherNode/Cars[2]");
assertNoNode("/otherNode[2]");
}
@FixFor("MODE-1137")
@Test
public void shouldExportContentWithUnicodeCharactersAsDocumentView() throws Exception {
Node unicode = session.getRootNode().addNode("unicodeContent");
Node desc = unicode.addNode("descriptionNode");
desc.setProperty("ex1", "étudiant (student)");
desc.setProperty("ex2", "où (where)");
desc.setProperty("ex3", "forêt (forest)");
desc.setProperty("ex4", "naïve (naïve)");
desc.setProperty("ex5", "garçon (boy)");
desc.setProperty("ex6", "multi\nline\nvalue");
desc.setProperty("ex7", "prop \"value\" with quotes");
desc.setProperty("ex7", "values with \r various \t\n : characters");
session.save();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
session.exportDocumentView("/unicodeContent", baos, false, false);
baos.close();
predefineWorkspace(repository.getConfiguration(), "workspace2");
InputStream istream = new ByteArrayInputStream(baos.toByteArray());
Session session2 = repository.login("workspace2");
session2.getWorkspace().importXML("/", istream, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
Node desc2 = session2.getNode("/unicodeContent/descriptionNode");
assertSameProperties(desc, desc2);
}
@FixFor("MODE-1137")
@Test
public void shouldExportContentWithUnicodeCharactersAsSystemView() throws Exception {
Node unicode = session.getRootNode().addNode("unicodeContent");
Node desc = unicode.addNode("descriptionNode");
desc.setProperty("ex1", "étudiant (student)");
desc.setProperty("ex2", "où (where)");
desc.setProperty("ex3", "forêt (forest)");
desc.setProperty("ex4", "naïve (naïve)");
desc.setProperty("ex5", "garçon (boy)");
desc.setProperty("ex6", "multi\nline\nvalue");
desc.setProperty("ex7", "prop \"value\" with quotes");
desc.setProperty("ex7", "values with \n various \t\n : characters");
session.save();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
session.exportSystemView("/unicodeContent", baos, false, false);
baos.close();
predefineWorkspace(repository.getConfiguration(), "workspace2");
InputStream istream = new ByteArrayInputStream(baos.toByteArray());
Session session2 = repository.login("workspace2");
session2.getWorkspace().importXML("/", istream, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
Node desc2 = session2.getNode("/unicodeContent/descriptionNode");
assertSameProperties(desc, desc2);
}
@Test
public void shouldImportCarsSystemViewWithCreateNewBehaviorWhenImportedContentDoesNotContainJcrRoot() throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
assertImport("io/cars-system-view.xml", "/a/b", ImportBehavior.CREATE_NEW);
assertThat(session, is(notNullValue()));
assertCarsImported();
}
@Test
public void shouldImportCarsSystemViewWithRemoveExistingBehaviorWhenImportedContentDoesNotContainJcrRoot() throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
assertImport("io/cars-system-view.xml", "/a/b", ImportBehavior.REMOVE_EXISTING);
assertThat(session, is(notNullValue()));
assertCarsImported();
}
@Test
public void shouldImportCarsSystemViewWithReplaceExistingBehaviorWhenImportedContentDoesNotContainJcrRoot() throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
assertImport("io/cars-system-view.xml", "/a/b", ImportBehavior.REPLACE_EXISTING);
assertThat(session, is(notNullValue()));
assertCarsImported();
}
@Test
public void shouldImportCarsSystemViewWithRemoveExistingBehaviorWhenImportedContentDoesNotContainJcrRootOrAnyUuids()
throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Set up the repository with existing content ...
assertImport("io/cars-system-view.xml", "/a/b", ImportBehavior.CREATE_NEW);
assertCarsImported();
// Now import again to create a second copy ...
assertImport("io/cars-system-view.xml", "/a/b", ImportBehavior.REMOVE_EXISTING);
assertThat(session, is(notNullValue()));
assertNode("/a/b/Cars");
assertNode("/a/b/Cars/Hybrid");
assertNode("/a/b/Cars/Hybrid/Toyota Prius");
assertNode("/a/b/Cars/Sports/Infiniti G37");
assertNode("/a/b/Cars/Utility/Land Rover LR3");
assertNode("/a/b/Cars[2]");
assertNode("/a/b/Cars[2]/Hybrid");
assertNode("/a/b/Cars[2]/Hybrid/Toyota Prius");
assertNode("/a/b/Cars[2]/Sports/Infiniti G37");
assertNode("/a/b/Cars[2]/Utility/Land Rover LR3");
}
// ----------------------------------------------------------------------------------------------------------------
// Import System View with NO 'jcr:root' node but WITH uuids
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldImportCarsSystemViewWithCreateNewBehaviorWhenImportedContentDoesNotContainJcrRootButDoesContainUnusedUuids()
throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Set up the repository with existing content ...
assertImport("io/cars-system-view.xml", "/a/b", ImportBehavior.CREATE_NEW);
assertCarsImported();
// And attempt to reimport the same content (with UUIDs) into the repository that already has that content ...
// print = true;
assertImport("io/cars-system-view-with-uuids.xml", "/a/b", ImportBehavior.REPLACE_EXISTING);
print();
// Verify that the original content has been left untouched ...
assertThat(session, is(notNullValue()));
assertNode("/a/b/Cars");
assertNode("/a/b/Cars/Hybrid");
assertNode("/a/b/Cars/Hybrid/Toyota Prius");
assertNode("/a/b/Cars/Sports/Infiniti G37");
assertNode("/a/b/Cars/Utility/Land Rover LR3");
assertNode("/a/b/Cars[2]");
assertNode("/a/b/Cars[2]/Hybrid");
assertNode("/a/b/Cars[2]/Hybrid/Toyota Prius");
assertNode("/a/b/Cars[2]/Sports");
}
@Test
public void shouldImportCarsSystemViewWithCreateNewBehaviorWhenImportedContentDoesNotContainJcrRootButDoesContainAlreadyUsedUuids()
throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Set up the repository with existing content ...
assertImport("io/cars-system-view-with-uuids.xml", "/a/b", ImportBehavior.CREATE_NEW);
assertCarsImported();
// And attempt to reimport the same content (with UUIDs) into the repository that already has that content ...
// print = true;
assertImport("io/cars-system-view-with-uuids.xml", "/a/b", ImportBehavior.CREATE_NEW);
print();
// Verify that the original content has been left untouched ...
assertThat(session, is(notNullValue()));
assertNode("/a/b/Cars");
assertNode("/a/b/Cars/Hybrid");
assertNode("/a/b/Cars/Hybrid/Toyota Prius");
assertNode("/a/b/Cars/Sports/Infiniti G37");
assertNode("/a/b/Cars/Utility/Land Rover LR3");
assertNode("/a/b/Cars[2]");
assertNode("/a/b/Cars[2]/Hybrid");
assertNode("/a/b/Cars[2]/Hybrid/Toyota Prius");
assertNode("/a/b/Cars[2]/Sports");
}
@Test
public void shouldImportCarsSystemViewOverExistingContentWhenImportedContentDoesNotContainJcrRootButDoesContainAlreadyUsedUuids()
throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Set up the repository with existing content ...
assertImport("io/cars-system-view-with-uuids.xml", "/a/b", ImportBehavior.CREATE_NEW);
assertCarsImported();
// And attempt to reimport the same content (with UUIDs) into the repository that already has that content ...
// print = true;
assertImport("io/cars-system-view-with-uuids.xml", "/a/b", ImportBehavior.REMOVE_EXISTING);
print();
// Verify that the original content has been replaced (since the SystemView contained UUIDs) and there is no copy ...
assertThat(session, is(notNullValue()));
assertCarsImported();
// And attempt to reimport the same content (with UUIDs) into the repository that already has that content ...
// print = true;
assertImport("io/cars-system-view-with-uuids.xml", "/a/b", ImportBehavior.REPLACE_EXISTING);
print();
// Verify that the original content has been replaced (since the SystemView contained UUIDs) and there is no copy ...
assertThat(session, is(notNullValue()));
assertCarsImported();
}
@Test
public void shouldImportCarsSystemViewWhenImportedContentDoesNotContainJcrRootButDoesContainAlreadyUsedUuids()
throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Set up the repository with existing content ...
assertImport("io/cars-system-view-with-uuids.xml", "/a/b", ImportBehavior.CREATE_NEW);
assertCarsImported();
// And attempt to reimport the same content (with UUIDs) into the repository that already has that content ...
// print = true;
assertImport("io/cars-system-view-with-uuids.xml", "/a/c", ImportBehavior.REPLACE_EXISTING);
print();
// Verify that the original content has been replaced (since the SystemView contained UUIDs) and there is no copy ...
assertThat(session, is(notNullValue()));
assertNode("/a/b");
assertNode("/a/c");
assertCarsImported();
// And attempt to reimport the same content (with UUIDs) into the repository that already has that content ...
// print = true;
assertImport("io/cars-system-view-with-uuids.xml", "/a/d", ImportBehavior.REMOVE_EXISTING);
print();
// Verify that the original content has been replaced (since the SystemView contained UUIDs) and there is no copy ...
assertThat(session, is(notNullValue()));
assertNode("/a/b");
assertNode("/a/c");
assertNode("/a/d/Cars");
assertNode("/a/d/Cars/Hybrid");
assertNode("/a/d/Cars/Hybrid/Toyota Prius");
assertNode("/a/d/Cars/Sports/Infiniti G37");
assertNode("/a/d/Cars/Utility/Land Rover LR3");
assertNoNode("/a/b/Cars[2]");
assertNoNode("/a/b/Cars/Hybrid[2]");
assertNoNode("/a/b/Cars/Hybrid/Toyota Prius[2]");
assertNoNode("/a/b/Cars/Sports[2]");
}
@Test(expected = ItemExistsException.class)
public void shouldFailToImportCarsSystemViewWithThrowBehaviorWhenImportedContentDoesNotContainJcrRootButDoesContainAlreadyUsedUuids()
throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Set up the repository with existing content ...
assertImport("io/cars-system-view-with-uuids.xml", "/a/b", ImportBehavior.CREATE_NEW);
assertCarsImported();
// And attempt to reimport the same content (with UUIDs) into the repository that already has that content ...
// print = true;
assertImport("io/cars-system-view-with-uuids.xml", "/a/c", ImportBehavior.THROW);
}
// ----------------------------------------------------------------------------------------------------------------
// Import System View WITH 'jcr:root' node and NO matching uuids
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldImportSystemViewOfEntireWorkspaceWithNoAlreadyUsedUuids() throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Set up the repository ...
assertImport("io/full-workspace-system-view-with-uuids.xml", "/", ImportBehavior.THROW); // no matching UUIDs expected
assertCarsImported();
}
@Test
public void shouldImportSystemViewOfEntireWorkspaceExportedFromJackrabbit() throws Exception {
// Register the Cars node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Set up the repository ...
assertImport("io/full-workspace-system-view.xml", "/", ImportBehavior.THROW); // no matching UUIDs expected
assertNode("/page1");
}
@Test
public void shouldImportFileExportedFromJackrabbitContainingBinaryData() throws Exception {
// Register the node types ...
tools.registerNodeTypes(session, "cars.cnd");
tools.registerNodeTypes(session, "cnd/magnolia.cnd");
assertThat(session.getWorkspace().getNodeTypeManager().getNodeType("mgnl:content"), is(notNullValue()));
// Now import the file ...
String filename = "io/system-export-with-binary-data-and-uuids.xml";
assertImport(filename, "/a", ImportBehavior.THROW); // no matching UUIDs expected
}
@FixFor("MODE-1026")
@Test
public void shouldImportFileExportedFromJackrabbitContainingBinaryStringData() throws Exception {
// Register the node types ...
tools.registerNodeTypes(session, "cars.cnd");
tools.registerNodeTypes(session, "cnd/magnolia.cnd");
assertThat(session.getWorkspace().getNodeTypeManager().getNodeType("mgnl:content"), is(notNullValue()));
// Now import the file ...
String filename = "io/system-export-with-xsitype-data-and-uuids.xml";
assertImport(filename, "/a", ImportBehavior.THROW); // no matching UUIDs expected
// print = true;
print("/a");
Node imageNode = assertNode("/a/company/image");
assertThat(imageNode.getProperty("extension").getValue().getString(), is("gif"));
}
@Test
public void shouldDecodeBase64() throws Exception {
String base64Str = "R0lGODlhEAAQAMZpAGxZMW1bNW9bMm9cNnJdNXJdNnNfN3tnPX5oQIBqQYJrO4FrQoVtQIZuQohxQopyRopzQYtzRo10Qo51SI12SJB3SZN5Q5N5RpV7TJZ8TJd9SJh+TpyAT52CUJ+FUaOGU6OHUaSIUqGKUqaJVaiKVaGMV6mLVqWOXqyOVayOWLCSWa2VWrSVW7aXXbSbXbqaXrqaX7uaX7ubXsCfYrigcMKgY8OhY8SiZMWjZMWjZcelZsimZsqnZ8unZ8uoaMypaM2pac6qacOtbc+ratCsatKta8uwbdGvctOvbtSvbNWwbciyhdaxbdm2dda7ddq5gd26fN28gNe/ed6+htvCeuHAhd3EfOLCidrDmd7GfuLEj9/HfubKlufLmOjLmOnMmOnNmujNne3UpuzUqe3Vp+7VqO/VqO/Wqe7YsP///////////////////////////////////////////////////////////////////////////////////////////yH+EUNyZWF0ZWQgd2l0aCBHSU1QACH5BAEKAH8ALAAAAAAQABAAAAeJgH+Cg4SFhoeIiYqLhSciiR40S1hoY0JZVE5GK4MOZWdmZGJhJVumW1aDFGBfXl1cWiRSp1sufxYXV1VQUVNPMSAYDwgHEINNTEpJSEcwKR0VCwWERURDQUA9LSYcEwkDhD8+PDs6OCwjGxEIAYQyOTc2NTMqHxkNBgCFChIaKC8hGBBgJIARo0AAOw==";
boolean print = false;
// // Try apache ...
// byte[] apacheBytes = org.apache.util.Base64.decode(base64Str.getBytes("UTF-8"));
// if (print) {
// System.out.println("Apache: " + toString(apacheBytes));
// System.out.println(" length: " + apacheBytes.length);
// }
// Try jboss ...
byte[] jbossBytes = org.jboss.util.Base64.decode(base64Str);
if (print) {
System.out.println("JBoss: " + toString(jbossBytes));
System.out.println(" length: " + jbossBytes.length);
}
// Try jackrabbit ...
ByteArrayOutputStream jrOutput = new ByteArrayOutputStream();
org.apache.jackrabbit.test.api.Base64.decode(base64Str, jrOutput);
byte[] jrBytes = jrOutput.toByteArray();
if (print) {
System.out.println("Jackrabbit: " + toString(jrBytes));
System.out.println(" length: " + jrBytes.length);
}
// Try modeshape ...
byte[] msBytes = org.modeshape.common.util.Base64.decode(base64Str);
if (print) {
System.out.println("ModeShape: " + toString(msBytes));
System.out.println(" length: " + msBytes.length);
}
// assertThat(apacheBytes, is(jbossBytes)); // apache pads 3 0s at the end
assertThat(jrBytes, is(jbossBytes));
assertThat(msBytes, is(jbossBytes));
}
String toString( byte[] bytes ) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(b);
}
return sb.toString();
}
// ----------------------------------------------------------------------------------------------------------------
// Import Document and System View containing constraint violations
// ----------------------------------------------------------------------------------------------------------------
@FixFor("MODE-1139")
@Test(expected = ConstraintViolationException.class)
public void shouldThrowCorrectExceptionWhenImportingDocumentViewContainingPropertiesThatViolateConstraints() throws Exception {
// Register the node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Set up the repository ...
assertImport("io/full-workspace-document-view-with-constraint-violation.xml", "/", ImportBehavior.THROW);
}
@FixFor("MODE-1139")
@Test(expected = ConstraintViolationException.class)
public void shouldThrowCorrectExceptionWhenImportingSystemViewContainingPropertiesThatViolateConstraints() throws Exception {
// Register the node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Set up the repository ...
assertImport("io/full-workspace-system-view-with-constraint-violation.xml", "/", ImportBehavior.THROW);
}
// ----------------------------------------------------------------------------------------------------------------
// Import Document View WITH 'jcr:root' node and WITH uuids
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldImportDocumentViewWithUuids() throws Exception {
// Register the node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Set up the repository ...
assertImport("io/full-workspace-document-view-with-uuids.xml", "/", ImportBehavior.THROW); // no matching UUIDs expected
assertCarsImported();
}
// ----------------------------------------------------------------------------------------------------------------
// Import Document View WITH constraints
// ----------------------------------------------------------------------------------------------------------------
@Test
public void shouldImportDocumentViewWithReferenceConstraints() throws Exception {
// Register the node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Set up the repository ...
assertImport("io/full-workspace-document-view-with-uuids.xml", "/", ImportBehavior.THROW); // no matching UUIDs expected
assertCarsImported();
}
@FixFor("MODE-1171")
@Test
public void shouldExportAndImportMultiValuedPropertyWithSingleValue() throws Exception {
Node rootNode = session.getRootNode();
Node nodeA = rootNode.addNode("a", "nt:unstructured");
Node nodeB = nodeA.addNode("b", "nt:unstructured");
Value v = session.getValueFactory().createValue("singleValue");
javax.jcr.Property prop = nodeB.setProperty("multiValuedProp", new Value[] { v });
assertTrue(prop.isMultiple());
prop = nodeB.setProperty("singleValuedProp", v);
assertTrue(!prop.isMultiple());
session.save();
File exportFile = exportSystemView("/a");
try {
nodeA.remove();
session.save();
assertImport(exportFile, "/", ImportBehavior.THROW);
prop = session.getProperty("/a/b/multiValuedProp");
assertTrue(prop.isMultiple());
assertThat(prop.getValues().length, is(1));
assertThat(prop.getValues()[0].getString(), is("singleValue"));
prop = session.getProperty("/a/b/singleValuedProp");
assertTrue(!prop.isMultiple());
assertThat(prop.getString(), is("singleValue"));
} finally {
exportFile.delete();
}
}
@Test
public void shouldImportIntoWorkspaceTheDocumentViewOfTheContentUsedInTckTests() throws Exception {
Session session3 = repository.login();
session.nodeTypeManager().registerNodeTypes(resourceStream("tck/tck_test_types.cnd"), true);
session.getWorkspace().importXML("/",
resourceStream("tck/documentViewForTckTests.xml"),
ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
assertThat(session.getRootNode().hasNode("testroot/workarea"), is(true));
assertThat(session.getRootNode().getNode("testroot/workarea"), is(notNullValue()));
assertThat(session.getNode("/testroot/workarea"), is(notNullValue()));
assertNode("/testroot/workarea");
Session session1 = repository.login();
assertThat(session1.getRootNode().hasNode("testroot/workarea"), is(true));
assertThat(session1.getRootNode().getNode("testroot/workarea"), is(notNullValue()));
assertThat(session1.getNode("/testroot/workarea"), is(notNullValue()));
session1.logout();
assertThat(session3.getRootNode().hasNode("testroot/workarea"), is(true));
assertThat(session3.getRootNode().getNode("testroot/workarea"), is(notNullValue()));
assertThat(session3.getNode("/testroot/workarea"), is(notNullValue()));
session3.logout();
}
@Test
public void shouldImportIntoWorkspaceTheSystemViewOfTheContentUsedInTckTests() throws Exception {
Session session3 = repository.login();
session.nodeTypeManager().registerNodeTypes(resourceStream("tck/tck_test_types.cnd"), true);
session.getWorkspace().importXML("/",
resourceStream("tck/systemViewForTckTests.xml"),
ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
assertThat(session.getRootNode().hasNode("testroot/workarea"), is(true));
assertThat(session.getRootNode().getNode("testroot/workarea"), is(notNullValue()));
assertNode("/testroot/workarea");
Session session1 = repository.login();
assertThat(session1.getRootNode().hasNode("testroot/workarea"), is(true));
assertThat(session1.getRootNode().getNode("testroot/workarea"), is(notNullValue()));
assertThat(session1.getNode("/testroot/workarea"), is(notNullValue()));
session1.logout();
assertThat(session3.getRootNode().hasNode("testroot/workarea"), is(true));
assertThat(session3.getRootNode().getNode("testroot/workarea"), is(notNullValue()));
assertThat(session3.getNode("/testroot/workarea"), is(notNullValue()));
session3.logout();
}
@Test
public void shouldImportIntoSessionTheDocumentViewOfTheContentUsedInTckTests() throws Exception {
Session session3 = repository.login();
session.nodeTypeManager().registerNodeTypes(resourceStream("tck/tck_test_types.cnd"), true);
session.importXML("/",
resourceStream("tck/documentViewForTckTests.xml"),
ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
assertThat(session.getRootNode().hasNode("testroot/workarea"), is(true));
assertThat(session.getRootNode().getNode("testroot/workarea"), is(notNullValue()));
assertThat(session.getNode("/testroot/workarea"), is(notNullValue()));
assertNode("/testroot/workarea");
Session session1 = repository.login();
assertThat(session1.getRootNode().hasNode("testroot/workarea"), is(false));
session.save();
assertThat(session1.getRootNode().hasNode("testroot/workarea"), is(true));
assertThat(session1.getRootNode().getNode("testroot/workarea"), is(notNullValue()));
assertThat(session1.getNode("/testroot/workarea"), is(notNullValue()));
session1.logout();
assertThat(session3.getRootNode().hasNode("testroot/workarea"), is(true));
assertThat(session3.getRootNode().getNode("testroot/workarea"), is(notNullValue()));
assertThat(session3.getNode("/testroot/workarea"), is(notNullValue()));
session3.logout();
}
@Test
public void shouldImportIntoSessionTheSystemViewOfTheContentUsedInTckTests() throws Exception {
Session session3 = repository.login();
session.nodeTypeManager().registerNodeTypes(resourceStream("tck/tck_test_types.cnd"), true);
session.importXML("/",
resourceStream("tck/systemViewForTckTests.xml"),
ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
assertThat(session.getRootNode().hasNode("testroot/workarea"), is(true));
assertThat(session.getRootNode().getNode("testroot/workarea"), is(notNullValue()));
assertNode("/testroot/workarea");
Session session1 = repository.login();
assertThat(session1.getRootNode().hasNode("testroot/workarea"), is(false));
session.save();
assertThat(session1.getRootNode().hasNode("testroot/workarea"), is(true));
assertThat(session1.getRootNode().getNode("testroot/workarea"), is(notNullValue()));
assertThat(session1.getNode("/testroot/workarea"), is(notNullValue()));
session1.logout();
assertThat(session3.getRootNode().hasNode("testroot/workarea"), is(true));
assertThat(session3.getRootNode().getNode("testroot/workarea"), is(notNullValue()));
assertThat(session3.getNode("/testroot/workarea"), is(notNullValue()));
session3.logout();
}
@Test
@FixFor("MODE-1573")
public void shouldPerformRoundTripOnDocumentViewWithBinaryContent() throws Exception {
JcrTools tools = new JcrTools();
File binaryFile = new File("src/test/resources/io/binary.pdf");
assert (binaryFile.exists() && binaryFile.isFile());
File outputFile = File.createTempFile("modeshape_import_export_" + System.currentTimeMillis(), "_test");
outputFile.deleteOnExit();
tools.uploadFile(session, "file", binaryFile);
session.save();
session.exportDocumentView("/file", new FileOutputStream(outputFile), false, false);
assertTrue(outputFile.length() > 0);
session.getRootNode().getNode("file").remove();
session.save();
//sleep so that the binary can be properly cleaned up (this is done via a listener)
Thread.sleep(200);
session.getWorkspace().importXML("/", new FileInputStream(outputFile), ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
assertNotNull(session.getNode("/file"));
assertNotNull(session.getNode("/file/jcr:content"));
Property data = session.getNode("/file/jcr:content").getProperty("jcr:data");
assertNotNull(data);
Binary binary = (Binary)data.getBinary();
assertNotNull(binary);
assertEquals(binaryFile.length(), binary.getSize());
}
@FixFor("MODE-1478")
@Test
public void shouldBeAbleToImportDroolsXMLIntoSystemView() throws Exception {
startRepositoryWithConfigurationFrom("config/drools-repository.json");
session.importXML("/", resourceStream("io/drools-system-view.xml"), ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
assertNode("/drools:repository", "nt:folder");
assertNode("/drools:repository/drools:package_area", "nt:folder");
assertNode("/drools:repository/drools:package_area/defaultPackage", "drools:packageNodeType");
assertNode("/drools:repository/drools:package_area/defaultPackage/assets", "drools:versionableAssetFolder");
assertNode("/drools:repository/drools:package_area/defaultPackage/assets/drools", "drools:assetNodeType");
assertNode("/drools:repository/drools:packagesnapshot_area", "nt:folder");
assertNode("/drools:repository/drools:tag_area", "nt:folder");
assertNode("/drools:repository/drools:state_area", "nt:folder");
assertNode("/drools:repository/drools.package.migrated", "nt:folder");
}
@FixFor("MODE-1795")
@Test
public void shouldBeAbleToImportXmlFileThatUsesDefaultNamespaceWithNonBlankUri() throws Exception {
session.importXML("/",
resourceStream("io/simple-document-view-with-default-namespace.xml"),
ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
// Get the prefix for the namespace used in the imported file ...
String prefix = session.getWorkspace().getNamespaceRegistry().getPrefix("http://www.ns.com");
assertNode("/" + prefix + ":childNode", "nt:unstructured");
}
@FixFor("MODE-1945")
@Test
public void shouldBeAbleToImportDocumentViewTwiceWithRemoveExistingCollisionMode() throws Exception {
// Register the node types ...
tools.registerNodeTypes(session, "cars.cnd");
// Set up the repository ...
assertImport("io/full-workspace-document-view-with-uuids.xml", "/", ImportBehavior.REMOVE_EXISTING);
assertCarsImported();
assertImport("io/full-workspace-document-view-with-uuids.xml", "/", ImportBehavior.REMOVE_EXISTING);
assertCarsImported();
}
@FixFor("MODE-1945")
@Test
public void shouldBeAbleToImportSystemViewWithBinaryTwiceWithRemoveExistingCollisionMode2() throws Exception {
// Register the node types ...
tools.registerNodeTypes(session, "cnd/magnolia.cnd");
// Now import the file ...
assertImport("io/system-export-with-binary-data-and-uuids.xml", "/",
ImportBehavior.REMOVE_EXISTING); // no matching UUIDs
// expected
assertImport("io/system-export-with-binary-data-and-uuids.xml", "/",
ImportBehavior.REMOVE_EXISTING); // no matching UUIDs
// expected
}
@Test
@FixFor("MODE-1961")
public void shouldBeAbleToImportTwiceWithoutLoosingMixins() throws Exception {
tools.registerNodeTypes(session, "cnd/brix.cnd");
session.save();
InputStream brixWorkspace = resourceStream("io/brixWorkspace.xml");
session.importXML("/", brixWorkspace, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
session.save();
JcrNode root = (JcrNode)session.getItem("/brix:root");
Set<Name> rootMixins = root.getMixinTypeNames();
assertTrue(rootMixins.contains(session.nameFactory().create("brix:node")));
brixWorkspace = resourceStream("io/brixWorkspace.xml");
session.importXML("/", brixWorkspace, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
session.save();
root = (JcrNode)session.getItem("/brix:root");
rootMixins = root.getMixinTypeNames();
assertTrue(rootMixins.contains(session.nameFactory().create("brix:node")));
}
@Test
@FixFor("MODE-2039")
public void shouldImportVersionedSystemView() throws Exception {
assertImport("io/system-export-with-versioning.xml", "/", ImportBehavior.REMOVE_EXISTING); // no matching UUIDs expected
}
@Test
@FixFor( "MODE-2172" )
public void shouldDocumentImportCheckedInNodes() throws Exception {
Node node1 = session.getRootNode().addNode("node1");
node1.addMixin("mix:versionable");
Node node2 = session.getRootNode().addNode("node2");
node2.addMixin("mix:versionable");
session.save();
JcrVersionManager versionManager = session.getWorkspace().getVersionManager();
versionManager.checkpoint("/node1");
session.getNode("/node1").setProperty("11", "some string");
session.getNode("/node1").setProperty("11a1", "some string");
session.save();
versionManager.checkin("/node1");
versionManager.checkpoint("/node2");
//export the data
ByteArrayOutputStream baos = new ByteArrayOutputStream();
session.exportDocumentView("/", baos, false, false);
session.getWorkspace().importXML("/", new ByteArrayInputStream(baos.toByteArray()),
ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
assertEquals(((org.modeshape.jcr.api.Property) session.getItem("/node1/11")).getString(), "some string");
assertEquals(((org.modeshape.jcr.api.Property) session.getItem("/node1/11a1")).getString(), "some string");
}
@Test
@FixFor( "MODE-2171" )
public void shouldNotExportACLsInSystemView() throws Exception {
Node node = session.getRootNode().addNode("node");
AccessControlList acl = acl("/node");
AccessControlManager accessControlManager = session.getAccessControlManager();
acl.addAccessControlEntry(SimplePrincipal.EVERYONE, new Privilege[]{ accessControlManager.privilegeFromName(
Privilege.JCR_ALL)});
accessControlManager.setPolicy("/node", acl);
assertTrue(hasMixin(node, ModeShapeLexicon.ACCESS_CONTROLLABLE_STRING));
session.save();
//export the data
ByteArrayOutputStream baos = new ByteArrayOutputStream();
session.exportSystemView("/", baos, false, false);
node.remove();
session.save();
session.importXML("/", new ByteArrayInputStream(baos.toByteArray()),
ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
node = session.getNode("/node");
assertTrue(hasMixin(node, ModeShapeLexicon.ACCESS_CONTROLLABLE_STRING));
assertFalse(node.getNodes().hasNext());
}
@Test
@FixFor( "MODE-2171" )
public void shouldNotExportACLsInDocumentView() throws Exception {
Node node = session.getRootNode().addNode("node");
AccessControlList acl = acl("/node");
AccessControlManager accessControlManager = session.getAccessControlManager();
acl.addAccessControlEntry(SimplePrincipal.EVERYONE, new Privilege[]{ accessControlManager.privilegeFromName(
Privilege.JCR_ALL)});
accessControlManager.setPolicy("/node", acl);
assertTrue(hasMixin(node, ModeShapeLexicon.ACCESS_CONTROLLABLE_STRING));
session.save();
//export the data
ByteArrayOutputStream baos = new ByteArrayOutputStream();
session.exportDocumentView("/", baos, false, false);
node.remove();
session.save();
session.importXML("/", new ByteArrayInputStream(baos.toByteArray()),
ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
node = session.getNode("/node");
assertTrue(hasMixin(node, ModeShapeLexicon.ACCESS_CONTROLLABLE_STRING));
assertFalse(node.getNodes().hasNext());
}
@Test
@FixFor( "MODE-2035" )
public void shouldExportViewsWithLocks() throws Exception {
Node node1 = session.getRootNode().addNode("node1");
node1.addMixin("mix:lockable");
Node node1_1 = node1.addNode("node1_1");
node1_1.addMixin("mix:lockable");
Node node2 = session.getRootNode().addNode("node2");
node2.addMixin("mix:lockable");
session.save();
session.getWorkspace().lockManager().lock("/node1", true, true, Long.MAX_VALUE, null);
session.getWorkspace().lockManager().lock("/node2", false, false, Long.MAX_VALUE, null);
testImportExport("/", "/", ExportType.SYSTEM, true, false, true);
testImportExport("/", "/", ExportType.DOCUMENT, true, false, true);
}
@Test
@FixFor( "MODE-2192" )
public void shouldImportSystemViewWithCheckedInNodes() throws Exception {
tools.registerNodeTypes(session, "cnd/ecm.cnd");
InputStream stream = resourceStream("io/ecm.xml");
session.importXML("/", stream, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
session.save();
JcrVersionManager versionManager = session.getWorkspace().getVersionManager();
assertNode("/root");
Node file = assertNode("/root/file1", "nt:file");
assertTrue(file.isCheckedOut());
Version fileVersion = versionManager.checkin("/root/file1");
assertEquals("1.0", fileVersion.getName());
assertEquals(2, versionManager.getVersionHistory("/root/file1").getAllVersions().getSize());
Node doc1 = assertNode("/root/folder1/doc1", "nt:file");
assertTrue(doc1.isCheckedOut());
Version docVersion = versionManager.checkin("/root/folder1/doc1");
assertEquals("1.0", docVersion.getName());
assertEquals(2, versionManager.getVersionHistory("/root/folder1/doc1").getAllVersions().getSize());
Node content = assertNode("/root/folder1/doc1/jcr:content", "nt:resource");
assertTrue(content.isCheckedOut());
Version contentVersion = versionManager.checkin("/root/folder1/doc1/jcr:content");
assertEquals("1.0", contentVersion.getName());
assertEquals(2, versionManager.getVersionHistory("/root/folder1/doc1/jcr:content").getAllVersions().getSize());
}
@Test
@FixFor( "MODE-2012" )
@SkipLongRunning( "There are 4 other test cases in JcrWorkspaceTest which validate the fix" )
public void shouldBeAbleToImportAndCloneWorkspaces() throws Exception {
String root = "/brix:root";
// setup
String workspaceA = "workspace_a";
String workspaceB = "workspace_b";
String workspaceC = "workspace_c";
Workspace wsA, wsB, wsC;
JcrSession sessA, sessB, sessC;
JcrWorkspace rootWS = session.getWorkspace();
rootWS.createWorkspace(workspaceA);
sessA = repository.login(workspaceA);
rootWS.createWorkspace(workspaceB);
sessB = repository.login(workspaceB);
rootWS.createWorkspace(workspaceC);
sessC = repository.login(workspaceC);
wsA = sessA.getWorkspace();
wsB = sessB.getWorkspace();
wsC = sessC.getWorkspace();
// namespace registering
wsA.getNamespaceRegistry().registerNamespace("brix", "http://brix-cms.googlecode.com");
wsB.getNamespaceRegistry().registerNamespace("brix", "http://brix-cms.googlecode.com");
wsC.getNamespaceRegistry().registerNamespace("brix", "http://brix-cms.googlecode.com");
// initial imports
tools.registerNodeTypes(sessA, "cnd/brix.cnd");
sessA.save();
InputStream brixWorkspace = resourceStream("io/brixWorkspace.xml");
sessA.importXML("/", brixWorkspace, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
sessA.save();
tools.registerNodeTypes(sessB, "cnd/brix.cnd");
sessB.save();
brixWorkspace = resourceStream("io/brixWorkspace.xml");
sessB.importXML("/", brixWorkspace, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
sessB.save();
tools.registerNodeTypes(sessC, "cnd/brix.cnd");
sessC.save();
brixWorkspace = resourceStream("io/brixWorkspace.xml");
sessC.importXML("/", brixWorkspace, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
sessC.save();
// re-import
if (print) {
new JcrTools().printSubgraph(sessA.getNode(root));
}
sessA.getItem(root).remove();
sessA.save();
brixWorkspace = resourceStream("io/brixWorkspace.xml");
sessA.importXML("/", brixWorkspace, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
sessA.save();
// now we clone the workspace A over the other ones at the path of root...
wsB.getSession().removeItem(root);
wsB.getSession().save();
wsB.clone(workspaceA, root, root, true);
wsB.getSession().save();
wsC.getSession().removeItem(root);
wsC.getSession().save();
wsC.clone(workspaceB, root, root, true);
wsC.getSession().save();
// re-import a second time
sessA.getItem(root).remove();
sessA.save();
brixWorkspace = resourceStream("io/brixWorkspace.xml");
sessA.importXML("/", brixWorkspace, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING);
sessA.save();
sessA.logout();
sessB.logout();
sessC.logout();
}
private void assertCarsImported() throws RepositoryException {
assertNode("/a/b/Cars");
assertNode("/a/b/Cars/Hybrid");
assertNode("/a/b/Cars/Hybrid/Toyota Prius");
assertNode("/a/b/Cars/Sports/Infiniti G37");
assertNode("/a/b/Cars/Utility/Land Rover LR3");
assertNoNode("/a/b/Cars[2]");
assertNoNode("/a/b/Cars/Hybrid[2]");
assertNoNode("/a/b/Cars/Hybrid/Toyota Prius[2]");
assertNoNode("/a/b/Cars/Sports[2]");
}
@FixFor( "MODE-2284" )
@Test
public void shouldRestoreBackreferencePropertiesAterImport() throws Exception {
Node referenceableNode = session.getRootNode().addNode("referenceable");
referenceableNode.addMixin(JcrMixLexicon.REFERENCEABLE.toString());
Value strongRefValue = session.getValueFactory().createValue(referenceableNode, false);
Node node1 = session.getRootNode().addNode("node1");
node1.setProperty("prop1", strongRefValue);
session.save();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
session.exportSystemView("/referenceable", outputStream, false, false);
// Import node tree. This lose backreferences for all nodes in the imported tree
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
session.importXML("/referenceable", inputStream, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
// Now save the changes
session.save();
PropertyIterator propertyIterator = referenceableNode.getReferences();
assertEquals(1, propertyIterator.getSize());
}
@Test
@FixFor( "MODE-2359" )
public void importingMultipleTimeWithReplaceExistingShouldNotIncreaseReferencesCount() throws Exception {
registerNodeTypes("cnd/ab-references.cnd");
session.getNode("/").addNode("testRoot");
session.save();
// A - this is a simple referenceable node
// [test:a] > mix:referenceable
session.importXML("/testRoot", resourceStream("io/a-references.xml"), ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
session.save();
int repeatCount = 2;
for (int i = 0; i < repeatCount; i++) {
// B - this is a simple node that refers to the node A
// [test:b] > mix:referenceable
// - test:prop_ref_a (reference) < test:a
session.importXML("/testRoot", resourceStream("io/b-references.xml"), ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
session.save();
}
// make sure we only have 2 nodes (i.e. replace_existing worked)
assertEquals(2, session.getNode("/testRoot").getNodes().getSize());
AbstractJcrNode a = session.getNode("/testRoot/a");
AbstractJcrNode b = session.getNode("/testRoot/b");
// make sure "a' has only referrer
assertEquals(1, a.getReferences().getSize());
// Remove node B.
b.remove();
session.save();
// After remove node B, node A should have zero referrers
a.remove();
session.save();
}
@Test
@FixFor( "MODE-2375" )
public void importingShouldKeepCorrectReferrerCount() throws Exception {
Node testRoot = session.getRootNode().addNode("testRoot");
//create the firt referrer first, so that it's exported before the referenceable node
Node referrerOne = testRoot.addNode("referrerOne");
// Create referenceable node
Node referenceableNode = testRoot.addNode("referenceable");
referenceableNode.addMixin(JcrMixLexicon.REFERENCEABLE.toString());
Value strongRefValue = session.getValueFactory().createValue(referenceableNode, false);
// Create second referrer
Node referrerTwo = testRoot.addNode("referrerTwo");
referrerTwo.setProperty("prop1", strongRefValue);
// Set strong reference for the first referrer to referenceable node
referrerOne.setProperty("prop1", strongRefValue);
session.save();
// Check that we have two referrers
assertEquals(2, session.getNode("/testRoot/referenceable").getReferences().getSize());
// Export nodes will be in the following order: referrerOne, referenceable, referrerTwo
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
session.exportSystemView("/testRoot", outputStream, false, false);
// Cleanup
session.getNode("/testRoot").remove();
session.save();
// Import nodes.
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
session.importXML("/", inputStream, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
session.save();
// Check that we have two referrers.
// We must not lose the referrer from node referrerOne.
assertEquals(2, session.getNode("/testRoot/referenceable").getReferences().getSize());
}
@Test
@FixFor( "MODE-2482" )
public void shouldSupportMultiValuedPropertiesInDocumentView() throws Exception {
Node test = session.getRootNode().addNode("testRoot");
test.setProperty("prop1", "value 1");
String[] values = { "value 1", "value 2", "value 3" };
test.setProperty("prop2", values);
session.save();
File file = new File("target/test-classes/document_view_multi_prop.xml");
FileUtil.delete(file);
FileOutputStream outputStream = new FileOutputStream(file);
exportDocumentView("/testRoot", outputStream);
session.getNode("/testRoot").remove();
session.save();
importFile("/", file.getName(), ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
assertNotNull(session.getNode("/testRoot"));
Property p1 = (Property)session.getItem("/testRoot/prop1");
assertFalse(p1.isMultiple());
assertEquals("value 1", p1.getString());
Property p2 = (Property)session.getItem("/testRoot/prop2");
assertTrue(p2.isMultiple());
Value[] jcrValues = p2.getValues();
List<String> actualValues = new ArrayList<>(jcrValues.length);
for (Value jcrValue : jcrValues) {
actualValues.add(jcrValue.getString());
}
assertArrayEquals(values, actualValues.toArray());
}
@Test
@FixFor( "MODE-2482 ")
public void shouldSupportMultipleMixinsInDocumentView() throws Exception {
registerNodeTypes("cnd/mixins.cnd");
Node test = session.getRootNode().addNode("a", "nt:set");
test.addMixin("mix:a");
test.addMixin("mix:b");
test.setProperty("jcr:a", "a");
test.setProperty("jcr:b", "b");
session.save();
File file = new File("target/test-classes/document_view_mode_2482.xml");
FileUtil.delete(file);
FileOutputStream outputStream = new FileOutputStream(file);
exportDocumentView("/a", outputStream);
session.getRootNode().addNode("b", "nt:folder");
session.save();
importFile("/b", file.getName(), ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
assertNotNull("/b/a");
assertEquals("a", ((Property)session.getItem("/b/a/jcr:a")).getString());
assertEquals("b", ((Property) session.getItem("/b/a/jcr:b")).getString());
}
@Test
@FixFor( "MODE-2504" )
public void shouldAllowReorderingAfterImport() throws RepositoryException, IOException {
session.getRootNode().addNode("firstLevelNode");
final InputStream xmlStream1 = resourceStream("io/child1-system-view.xml");
session.importXML("/firstLevelNode", xmlStream1, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
final InputStream xmlStream2 = resourceStream("io/child2-system-view.xml");
session.importXML("/firstLevelNode", xmlStream2, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
// now when we call the orderBefore, any operation on non-existing child of /firstLevelNode fails with NPE:
session.getNode("/firstLevelNode").orderBefore("child2", "child1");
assertTrue(session.nodeExists("/firstLevelNode/child1"));
assertTrue(session.nodeExists("/firstLevelNode/child2"));
assertFalse(session.nodeExists("/firstLevelNode/nonexisting"));
}
// ----------------------------------------------------------------------------------------------------------------
// Utilities
// ----------------------------------------------------------------------------------------------------------------
protected static enum ImportBehavior {
CREATE_NEW(ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW),
REPLACE_EXISTING(ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING),
REMOVE_EXISTING(ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING),
THROW(ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
private final int jcrValue;
private ImportBehavior( int value ) {
this.jcrValue = value;
}
public int getJcrValue() {
return jcrValue;
}
}
protected void importFile( String importIntoPath,
String resourceName,
int importBehavior ) throws Exception {
// Import the car content ...
InputStream stream = getClass().getClassLoader().getResourceAsStream(resourceName);
assertThat(stream, is(notNullValue()));
try {
session.importXML(importIntoPath, stream, importBehavior); // shouldn't exist yet
} finally {
stream.close();
}
}
protected Node assertImport( String resourceName,
String pathToParent,
ImportBehavior behavior ) throws RepositoryException, IOException {
InputStream istream = resourceStream(resourceName);
return assertImport(istream, pathToParent, behavior);
}
protected Node assertImport( File resource,
String pathToParent,
ImportBehavior behavior ) throws RepositoryException, IOException {
InputStream istream = new FileInputStream(resource);
return assertImport(istream, pathToParent, behavior);
}
protected Node assertImport( InputStream istream,
String pathToParent,
ImportBehavior behavior ) throws RepositoryException, IOException {
// Make the parent node if it does not exist ...
Path parentPath = path(pathToParent);
assertThat(parentPath.isAbsolute(), is(true));
Node node = session.getRootNode();
boolean found = true;
for (Path.Segment segment : parentPath) {
String name = asString(segment);
if (found) {
try {
node = node.getNode(name);
found = true;
} catch (PathNotFoundException e) {
found = false;
}
}
if (!found) {
node = node.addNode(name, "nt:unstructured");
}
}
if (!found) {
// We added at least one node, so we need to save it before importing ...
session.save();
}
// Verify that the parent node does exist now ...
assertNode(pathToParent);
// Now, load the content of the resource being imported ...
assertThat(istream, is(notNullValue()));
try {
session.getWorkspace().importXML(pathToParent, istream, behavior.getJcrValue());
} finally {
istream.close();
}
session.save();
return node;
}
protected File exportSystemView( String pathToParent ) throws IOException, RepositoryException {
assertNode(pathToParent);
// Export to a string ...
File tmp = File.createTempFile("JcrImportExportText-", "");
FileOutputStream ostream = new FileOutputStream(tmp);
boolean skipBinary = false;
boolean noRecurse = false;
session.exportSystemView(pathToParent, ostream, skipBinary, noRecurse);
return tmp;
}
protected void exportDocumentView( String pathToParent,
OutputStream ostream ) throws RepositoryException, IOException {
boolean skipBinary = false;
boolean noRecurse = false;
try {
session.exportDocumentView(pathToParent, ostream, skipBinary, noRecurse);
} finally {
ostream.close();
}
}
}