/* * 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.exporting; import org.exoplatform.services.jcr.dataflow.ItemState; import org.exoplatform.services.jcr.impl.Constants; import org.exoplatform.services.jcr.impl.core.NodeImpl; import org.exoplatform.services.jcr.impl.core.PropertyImpl; import org.exoplatform.services.jcr.impl.dataflow.TransientNodeData; import org.exoplatform.services.jcr.impl.dataflow.TransientPropertyData; import org.exoplatform.services.jcr.util.IdGenerator; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; 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.OutputStream; import java.util.Calendar; import java.util.LinkedHashMap; import java.util.Map; import javax.jcr.ImportUUIDBehavior; import javax.jcr.Node; import javax.jcr.Property; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Value; import javax.jcr.version.Version; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; /** * @author <a href="mailto:Sergey.Kabashnyuk@gmail.com">Sergey Kabashnyuk</a> * @version $Id: TestExportImport.java 13888 2008-05-05 13:47:27Z ksm $ */ public class TestExportImport extends ExportBase { private final int SNS_NODES_COUNT = 10; public TestExportImport() throws ParserConfigurationException { super(); } public void testExportImportCustomNodeType() throws Exception { Node folder = root.addNode("childNode", "nt:folder"); Node file = folder.addNode("childNode2", "exo:salestool"); Node contentNode = file.addNode("jcr:content", "nt:resource"); contentNode.setProperty("jcr:data", session.getValueFactory().createValue("this is the content", PropertyType.BINARY)); contentNode.setProperty("jcr:mimeType", "application/octet-stream"); contentNode.setProperty("jcr:lastModified", session.getValueFactory().createValue(Calendar.getInstance())); session.save(); File destFile = File.createTempFile("testExportImportValuesSysView", ".xml"); destFile.deleteOnExit(); OutputStream outStream = new FileOutputStream(destFile); session.exportSystemView(file.getPath(), outStream, false, false); outStream.close(); folder.remove(); session.save(); session.importXML(root.getPath(), new FileInputStream(destFile), ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); session.save(); } public void testExportImportValuesSysView() throws Exception { Node testNode = root.addNode("testExportImport"); for (int i = 0; i < valList.size(); i++) { testNode.setProperty("prop" + i + "_string", valList.get(i), PropertyType.STRING); testNode.setProperty("prop" + i + "_binary", valList.get(i), PropertyType.BINARY); } session.save(); File destFile = File.createTempFile("testExportImportValuesSysView", ".xml"); destFile.deleteOnExit(); OutputStream outStream = new FileOutputStream(destFile); session.exportSystemView(testNode.getPath(), outStream, false, false); outStream.close(); testNode.remove(); session.save(); session.importXML(root.getPath(), new FileInputStream(destFile), ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); session.save(); Node newNode = root.getNode("testExportImport"); for (int i = 0; i < valList.size(); i++) { if (valList.get(i).length > 1) { Value[] stringValues = newNode.getProperty("prop" + i + "_string").getValues(); for (int j = 0; j < stringValues.length; j++) { assertEquals(stringValues[j].getString(), valList.get(i)[j]); } Value[] binaryValues = newNode.getProperty("prop" + i + "_binary").getValues(); for (int j = 0; j < stringValues.length; j++) { assertEquals(binaryValues[j].getString(), valList.get(i)[j]); } } else { assertEquals(valList.get(i)[0], newNode.getProperty("prop" + i + "_string").getValue().getString()); assertEquals(valList.get(i)[0], newNode.getProperty("prop" + i + "_binary").getValue().getString()); } } destFile.delete(); } public void testMixinExportImportDocumentViewContentHandler() throws Exception { Node testNode = root.addNode("childNode"); testNode.setProperty("a", 1); testNode.addMixin("mix:versionable"); testNode.addMixin("mix:lockable"); session.save(); doVersionTests(testNode); session.save(); doExportImport(root, "childNode", false, true, null); session.save(); Node childNode = root.getNode("childNode"); doVersionTests(childNode); } public void testMixinExportImportDocumentViewStream() throws Exception { Node testNode = root.addNode("childNode"); testNode.setProperty("a", 1); testNode.addMixin("mix:versionable"); testNode.addMixin("mix:lockable"); session.save(); doVersionTests(testNode); session.save(); doExportImport(root, "childNode", false, false, null); session.save(); Node childNode = root.getNode("childNode"); doVersionTests(childNode); } public void testMixinExportImportSystemViewContentHandler() throws Exception { Node testNode = root.addNode("childNode"); testNode.setProperty("a", 1); testNode.addMixin("mix:versionable"); testNode.addMixin("mix:lockable"); session.save(); doVersionTests(testNode); doExportImport(root, "childNode", true, true, null); Node childNode = root.getNode("childNode"); doVersionTests(childNode); } public void testMixinExportImportSystemViewStream() throws Exception { Node testNode = root.addNode("childNode"); testNode.setProperty("a", 1); testNode.addMixin("mix:versionable"); testNode.addMixin("mix:lockable"); session.save(); doVersionTests(testNode); doExportImport(root, "childNode", true, false, null); Node childNode = root.getNode("childNode"); doVersionTests(childNode); } public void testSNSDocumentViewCh() throws Exception { Node testSNS = root.addNode("testSNS"); testSNS.addMixin("mix:versionable"); for (int i = 0; i < SNS_NODES_COUNT; i++) { testSNS.addNode("nodeSNS"); } Node testDest = root.addNode("testDest"); session.save(); doExportImport(root, "testSNS", false, true, testDest); assertTrue(testDest.hasNode("testSNS")); Node testSNSNew = testDest.getNode("testSNS"); for (int i = 0; i < SNS_NODES_COUNT; i++) { testSNS.addNode("nodeSNS"); assertTrue(testSNSNew.hasNode("nodeSNS[" + (i + 1) + "]")); } } public void testSNSDocumentViewStream() throws Exception { Node testSNS = root.addNode("testSNS"); testSNS.addMixin("mix:versionable"); for (int i = 0; i < SNS_NODES_COUNT; i++) { testSNS.addNode("nodeSNS"); } Node testDest = root.addNode("testDest"); session.save(); doExportImport(root, "testSNS", false, false, testDest); assertTrue(testDest.hasNode("testSNS")); Node testSNSNew = testDest.getNode("testSNS"); for (int i = 0; i < SNS_NODES_COUNT; i++) { testSNS.addNode("nodeSNS"); assertTrue(testSNSNew.hasNode("nodeSNS[" + (i + 1) + "]")); } } public void testSNSSystemViewCh() throws Exception { Node testSNS = root.addNode("testSNS"); testSNS.addMixin("mix:versionable"); for (int i = 0; i < SNS_NODES_COUNT; i++) { testSNS.addNode("nodeSNS"); } Node testDest = root.addNode("testDest"); session.save(); doExportImport(root, "testSNS", true, true, testDest); assertTrue(testDest.hasNode("testSNS")); Node testSNSNew = testDest.getNode("testSNS"); for (int i = 0; i < SNS_NODES_COUNT; i++) { testSNS.addNode("nodeSNS"); assertTrue(testSNSNew.hasNode("nodeSNS[" + (i + 1) + "]")); } } public void testSNSSystemViewStream() throws Exception { Node testSNS = root.addNode("testSNS"); testSNS.addMixin("mix:versionable"); for (int i = 0; i < SNS_NODES_COUNT; i++) { testSNS.addNode("nodeSNS"); } Node testDest = root.addNode("testDest"); session.save(); doExportImport(root, "testSNS", true, false, testDest); assertTrue(testDest.hasNode("testSNS")); Node testSNSNew = testDest.getNode("testSNS"); for (int i = 0; i < SNS_NODES_COUNT; i++) { testSNS.addNode("nodeSNS"); assertTrue(testSNSNew.hasNode("nodeSNS[" + (i + 1) + "]")); } } private void doExportImport(Node parentNode, String nodeName, boolean isSystemView, boolean isContentHandler, Node destParentNode) throws RepositoryException, IOException, TransformerConfigurationException, SAXException { Node exportNode = parentNode.getNode(nodeName); File destFile = File.createTempFile("testExportImport", ".xml"); destFile.deleteOnExit(); OutputStream outStream = new FileOutputStream(destFile); if (isSystemView) { if (isContentHandler) { SAXTransformerFactory saxFact = (SAXTransformerFactory)TransformerFactory.newInstance(); TransformerHandler handler = saxFact.newTransformerHandler(); handler.setResult(new StreamResult(outStream)); session.exportSystemView(exportNode.getPath(), handler, false, false); } else { session.exportSystemView(exportNode.getPath(), outStream, false, false); } } else { if (isContentHandler) { SAXTransformerFactory saxFact = (SAXTransformerFactory)TransformerFactory.newInstance(); TransformerHandler handler = saxFact.newTransformerHandler(); handler.setResult(new StreamResult(outStream)); session.exportDocumentView(exportNode.getPath(), handler, false, false); } else { session.exportDocumentView(exportNode.getPath(), outStream, false, false); } } outStream.close(); if (destParentNode == null) { exportNode.remove(); session.save(); } session.importXML(destParentNode != null ? destParentNode.getPath() : root.getPath(), new FileInputStream( destFile), ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW); session.save(); assertTrue(parentNode.hasNode(nodeName)); } public void testname() throws Exception { } private void doVersionTests(Node testNode) throws RepositoryException { assertTrue(testNode.isNodeType("mix:lockable")); assertTrue(testNode.isNodeType("mix:referenceable")); assertTrue(testNode.hasProperty("jcr:uuid")); assertTrue(testNode.isCheckedOut()); testNode.setProperty("a", 1); session.save(); Version version1 = testNode.checkin(); testNode.checkout(); testNode.setProperty("a", 2); session.save(); assertEquals(2, testNode.getProperty("a").getLong()); Version version2 = testNode.checkin(); testNode.checkout(); Property prop2 = testNode.getProperty("jcr:mixinTypes"); assertEquals(PropertyType.NAME, prop2.getType()); assertTrue(testNode.isCheckedOut()); testNode.restore(version1, true); testNode.checkout(); assertTrue(testNode.isCheckedOut()); assertEquals(1, testNode.getProperty("a").getLong()); Property prop = testNode.getProperty("jcr:mixinTypes"); assertEquals(PropertyType.NAME, prop.getType()); assertTrue(testNode.isNodeType("mix:lockable")); assertTrue(testNode.isNodeType("mix:referenceable")); assertTrue(testNode.hasProperty("jcr:uuid")); assertTrue(testNode.isCheckedOut()); } public void testShouldThrowExceptionWhenExistingNodeAddedAfterImporting() throws Exception { Node testNode = root.addNode("testNode"); testNode.addMixin("mix:referenceable"); TransientNodeData node = (TransientNodeData)((NodeImpl)testNode.addNode("test2")).getData(); session.save(); File contentFile = new File("target/input-sysview.xml"); OutputStream outStream = new FileOutputStream(contentFile); try { session.exportSystemView(testNode.getPath(), outStream, false, false); } finally { outStream.close(); } testNode.remove(); session.save(); session.importXML(root.getPath(), new FileInputStream(contentFile), ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW); session.save(); TransientNodeData newNodeData = new TransientNodeData(node.getQPath(), IdGenerator.generate(), node.getPersistedVersion(), node.getPrimaryTypeName(), node.getMixinTypeNames(), node.getOrderNumber(), root.getNode("testNode") .getUUID(), node.getACL()); ItemState state = ItemState.createAddedState(newNodeData); session.getTransientNodesManager().updateItemState(state); try { session.save(); fail(); } catch (Exception e) { } } public void testShouldThrowExceptionWhenExistingPropertyAddedAfterImporting() throws Exception { Node testNode = root.addNode("testNode"); testNode.addMixin("mix:referenceable"); TransientPropertyData prop = (TransientPropertyData)((PropertyImpl)testNode.setProperty("testProperty", "testValue")).getData(); session.save(); File contentFile = new File("target/input-sysview.xml"); OutputStream outStream = new FileOutputStream(contentFile); try { session.exportSystemView(testNode.getPath(), outStream, false, false); } finally { outStream.close(); } testNode.remove(); session.save(); session.importXML(root.getPath(), new FileInputStream(contentFile), ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW); session.save(); TransientPropertyData newPropertyData = new TransientPropertyData(prop.getQPath(), IdGenerator.generate(), prop.getPersistedVersion(), prop.getType(), root.getNode("testNode").getUUID(), prop.isMultiValued(), prop.getValues()); ItemState state = ItemState.createAddedState(newPropertyData); session.getTransientNodesManager().updateItemState(state); try { session.save(); fail(); } catch (Exception e) { } } public void testExportImportInvalidCharSystem() throws Exception { Node testNode = root.addNode("testExportImportInvalidCharSystem"); String contentWithInvalidChar = "\001Af\001A\001A\001Ao\001A\001Ao\001A"; String contentWoInvalidChar = "foo"; testNode.setProperty("stringValue", contentWithInvalidChar); testNode.setProperty("binaryValue", new ByteArrayInputStream(contentWithInvalidChar.getBytes(Constants.DEFAULT_ENCODING))); testNode.setProperty("stringValueWo", contentWoInvalidChar); testNode.setProperty("binaryValueWo", new ByteArrayInputStream(contentWoInvalidChar.getBytes(Constants.DEFAULT_ENCODING))); session.save(); assertEquals(PropertyType.STRING, testNode.getProperty("stringValue").getType()); assertEquals(contentWithInvalidChar, testNode.getProperty("stringValue").getString()); assertEquals(PropertyType.BINARY, testNode.getProperty("binaryValue").getType()); assertEquals(contentWithInvalidChar, testNode.getProperty("binaryValue").getString()); assertEquals(PropertyType.STRING, testNode.getProperty("stringValueWo").getType()); assertEquals(contentWoInvalidChar, testNode.getProperty("stringValueWo").getString()); assertEquals(PropertyType.BINARY, testNode.getProperty("binaryValueWo").getType()); assertEquals(contentWoInvalidChar, testNode.getProperty("binaryValueWo").getString()); // With Binary ByteArrayOutputStream outStream = new ByteArrayOutputStream(); session.exportSystemView(testNode.getPath(), outStream, false, false); outStream.close(); testNode.remove(); session.save(); session.importXML(root.getPath(), new ByteArrayInputStream(outStream.toByteArray()), ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); session.save(); Node newNode = root.getNode("testExportImportInvalidCharSystem"); assertEquals(PropertyType.STRING, newNode.getProperty("stringValue").getType()); assertEquals(contentWithInvalidChar, newNode.getProperty("stringValue").getString()); assertEquals(PropertyType.BINARY, newNode.getProperty("binaryValue").getType()); assertEquals(contentWithInvalidChar, newNode.getProperty("binaryValue").getString()); assertEquals(PropertyType.STRING, newNode.getProperty("stringValueWo").getType()); assertEquals(contentWoInvalidChar, newNode.getProperty("stringValueWo").getString()); assertEquals(PropertyType.BINARY, newNode.getProperty("binaryValueWo").getType()); assertEquals(contentWoInvalidChar, newNode.getProperty("binaryValueWo").getString()); outStream.reset(); // Without Binary session.exportSystemView(newNode.getPath(), outStream, true, false); outStream.close(); newNode.remove(); root.save(); session.importXML(root.getPath(), new ByteArrayInputStream(outStream.toByteArray()), ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); session.save(); newNode = root.getNode("testExportImportInvalidCharSystem"); assertEquals(PropertyType.STRING, newNode.getProperty("stringValue").getType()); assertEquals(contentWithInvalidChar, newNode.getProperty("stringValue").getString()); assertEquals(PropertyType.BINARY, newNode.getProperty("binaryValue").getType()); assertEquals("", newNode.getProperty("binaryValue").getString()); assertEquals(PropertyType.STRING, newNode.getProperty("stringValueWo").getType()); assertEquals(contentWoInvalidChar, newNode.getProperty("stringValueWo").getString()); assertEquals(PropertyType.BINARY, newNode.getProperty("binaryValueWo").getType()); assertEquals("", newNode.getProperty("binaryValueWo").getString()); } public void testExportImportInvalidCharSystemWithCH() throws Exception { Node testNode = root.addNode("testExportImportInvalidCharSystemWithCH"); String contentWithInvalidChar = "\001Af\001A\001A\001Ao\001A\001Ao\001A"; String contentWoInvalidChar = "foo"; testNode.setProperty("stringValue", contentWithInvalidChar); testNode.setProperty("binaryValue", new ByteArrayInputStream(contentWithInvalidChar.getBytes(Constants.DEFAULT_ENCODING))); testNode.setProperty("stringValueWo", contentWoInvalidChar); testNode.setProperty("binaryValueWo", new ByteArrayInputStream(contentWoInvalidChar.getBytes(Constants.DEFAULT_ENCODING))); session.save(); assertEquals(PropertyType.STRING, testNode.getProperty("stringValue").getType()); assertEquals(contentWithInvalidChar, testNode.getProperty("stringValue").getString()); assertEquals(PropertyType.BINARY, testNode.getProperty("binaryValue").getType()); assertEquals(contentWithInvalidChar, testNode.getProperty("binaryValue").getString()); assertEquals(PropertyType.STRING, testNode.getProperty("stringValueWo").getType()); assertEquals(contentWoInvalidChar, testNode.getProperty("stringValueWo").getString()); assertEquals(PropertyType.BINARY, testNode.getProperty("binaryValueWo").getType()); assertEquals(contentWoInvalidChar, testNode.getProperty("binaryValueWo").getString()); // With Binary final ByteArrayOutputStream outStream = new ByteArrayOutputStream(); ContentHandler handler = new DefaultHandler() { private Map<String, String> prefixMapping = new LinkedHashMap<String, String>(); private boolean start; public void startPrefixMapping (String prefix, String uri) throws SAXException { prefixMapping.put(prefix, uri); } public void startElement (String uri, String localName, String qName, Attributes atts) throws SAXException { try { outStream.write(("<" + qName).getBytes(Constants.DEFAULT_ENCODING)); if (start) { start = false; for (String prefix : prefixMapping.keySet()) { outStream.write((" xmlns:" + prefix + "=\"" + prefixMapping.get(prefix) + "\"").getBytes(Constants.DEFAULT_ENCODING)); } } for (int i = 0; i < atts.getLength(); i++) { outStream.write((" " + atts.getQName(i) + "=\"" + atts.getValue(i) + "\"").getBytes(Constants.DEFAULT_ENCODING)); } outStream.write(">".getBytes(Constants.DEFAULT_ENCODING)); } catch (Exception e) { throw new SAXException(e); } } public void startDocument() throws SAXException { try { outStream.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>".getBytes(Constants.DEFAULT_ENCODING)); start = true; } catch (Exception e) { throw new SAXException(e); } } public void endElement(String uri, String localName, String qName) throws SAXException { try { outStream.write(("</" + qName + ">").getBytes(Constants.DEFAULT_ENCODING)); } catch (Exception e) { throw new SAXException(e); } } public void endDocument() throws SAXException { prefixMapping.clear(); start = false; } public void characters(char ch[], int start, int length) throws SAXException { try { outStream.write(new String (ch, start, length).getBytes(Constants.DEFAULT_ENCODING)); } catch (Exception e) { throw new SAXException(e); } } }; session.exportSystemView(testNode.getPath(), handler, false, false); outStream.close(); testNode.remove(); session.save(); session.importXML(root.getPath(), new ByteArrayInputStream(outStream.toByteArray()), ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); session.save(); Node newNode = root.getNode("testExportImportInvalidCharSystemWithCH"); assertEquals(PropertyType.STRING, newNode.getProperty("stringValue").getType()); assertEquals(contentWithInvalidChar, newNode.getProperty("stringValue").getString()); assertEquals(PropertyType.BINARY, newNode.getProperty("binaryValue").getType()); assertEquals(contentWithInvalidChar, newNode.getProperty("binaryValue").getString()); assertEquals(PropertyType.STRING, newNode.getProperty("stringValueWo").getType()); assertEquals(contentWoInvalidChar, newNode.getProperty("stringValueWo").getString()); assertEquals(PropertyType.BINARY, newNode.getProperty("binaryValueWo").getType()); assertEquals(contentWoInvalidChar, newNode.getProperty("binaryValueWo").getString()); outStream.reset(); // Without Binary session.exportSystemView(newNode.getPath(), handler, true, false); outStream.close(); newNode.remove(); root.save(); session.importXML(root.getPath(), new ByteArrayInputStream(outStream.toByteArray()), ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); session.save(); newNode = root.getNode("testExportImportInvalidCharSystemWithCH"); assertEquals(PropertyType.STRING, newNode.getProperty("stringValue").getType()); assertEquals(contentWithInvalidChar, newNode.getProperty("stringValue").getString()); assertEquals(PropertyType.BINARY, newNode.getProperty("binaryValue").getType()); assertEquals("", newNode.getProperty("binaryValue").getString()); assertEquals(PropertyType.STRING, newNode.getProperty("stringValueWo").getType()); assertEquals(contentWoInvalidChar, newNode.getProperty("stringValueWo").getString()); assertEquals(PropertyType.BINARY, newNode.getProperty("binaryValueWo").getType()); assertEquals("", newNode.getProperty("binaryValueWo").getString()); } }