/* * 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.importing; import org.exoplatform.services.jcr.JcrAPIBaseTest; import org.exoplatform.services.jcr.core.ExtendedSession; import org.exoplatform.services.jcr.core.ExtendedWorkspace; import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager; import org.exoplatform.services.jcr.impl.core.nodetype.NodeTypeManagerImpl; import org.exoplatform.services.jcr.util.IdGenerator; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.jcr.ImportUUIDBehavior; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; 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; /** * Created by The eXo Platform SAS. * * @author <a href="mailto:Sergey.Kabashnyuk@gmail.com">Sergey Kabashnyuk</a> * @version $Id: AbstractImportTest.java 14244 2008-05-14 11:44:54Z ksm $ */ public abstract class AbstractImportTest extends JcrAPIBaseTest { /** * Initialization flag. */ private static boolean isInitialized = false; /** * Logger. */ private Log log = ExoLogger.getLogger("exo.jcr.component.core.BaseImportTest"); private final Random random = new Random(); @Override public void initRepository() throws RepositoryException { super.initRepository(); if (!isInitialized) { NodeTypeManagerImpl ntManager = (NodeTypeManagerImpl)session.getWorkspace().getNodeTypeManager(); InputStream is = TestDocumentViewImport.class.getResourceAsStream("/nodetypes/ext-registry-nodetypes.xml"); ntManager.registerNodeTypes(is, 0, NodeTypeDataManager.TEXT_XML); ntManager.registerNodeTypes(TestDocumentViewImport.class .getResourceAsStream("/org/exoplatform/services/jcr/api/nodetypes/ecm/nodetypes-config.xml"), 0, NodeTypeDataManager.TEXT_XML); ntManager.registerNodeTypes(TestDocumentViewImport.class .getResourceAsStream("/org/exoplatform/services/jcr/api/nodetypes/ecm/nodetypes-config-extended.xml"), 0, NodeTypeDataManager.TEXT_XML); isInitialized = true; } } /** * Deserialize xml content to specific node from InputStream. * * @param importRoot * @param saveType * @param isImportedByStream * @param uuidBehavior * @param is * @throws RepositoryException * @throws SAXException * @throws IOException */ protected void deserialize(Node importRoot, XmlSaveType saveType, boolean isImportedByStream, int uuidBehavior, InputStream is) throws RepositoryException, SAXException, IOException { ExtendedSession extendedSession = (ExtendedSession)importRoot.getSession(); ExtendedWorkspace extendedWorkspace = (ExtendedWorkspace)extendedSession.getWorkspace(); if (isImportedByStream) { if (saveType == XmlSaveType.SESSION) { extendedSession.importXML(importRoot.getPath(), is, uuidBehavior); } else if (saveType == XmlSaveType.WORKSPACE) { extendedWorkspace.importXML(importRoot.getPath(), is, uuidBehavior); } } else { XMLReader reader = XMLReaderFactory.createXMLReader(); if (saveType == XmlSaveType.SESSION) { reader.setContentHandler(extendedSession.getImportContentHandler(importRoot.getPath(), uuidBehavior)); } else if (saveType == XmlSaveType.WORKSPACE) { reader.setContentHandler(extendedWorkspace.getImportContentHandler(importRoot.getPath(), uuidBehavior)); } InputSource inputSource = new InputSource(is); reader.parse(inputSource); } } protected void executeSingeleThreadImportTests(int attempts, Class<? extends BeforeExportAction> firstAction, Class<? extends BeforeImportAction> secondAction, Class<? extends AfterImportAction> thirdAction) throws TransformerConfigurationException, IOException, RepositoryException, SAXException, InterruptedException { ExecutorService executor = Executors.newSingleThreadExecutor(); executeImportTests(executor, attempts, firstAction, secondAction, thirdAction); executor.shutdown(); } protected void executeMultiThreadImportTests(int threadCount, int attempts, Class<? extends BeforeExportAction> firstAction, Class<? extends BeforeImportAction> secondAction, Class<? extends AfterImportAction> thirdAction) throws TransformerConfigurationException, IOException, RepositoryException, SAXException, InterruptedException { ExecutorService executor = Executors.newCachedThreadPool(); executeImportTests(executor, attempts, firstAction, secondAction, thirdAction); executor.shutdown(); } /** * boolean isExportedByStream, boolean isImportedByStream, boolean * isSystemViewExport * * @param firstAction * @param secondAction * @param thirdAction * @throws TransformerConfigurationException * @throws IOException * @throws RepositoryException * @throws SAXException * @throws InterruptedException */ private void executeImportTests(ExecutorService executor, int attempts, Class<? extends BeforeExportAction> firstAction, Class<? extends BeforeImportAction> secondAction, Class<? extends AfterImportAction> thirdAction) throws TransformerConfigurationException, IOException, RepositoryException, SAXException, InterruptedException { XmlSaveType[] posibleSaveTypes = new XmlSaveType[]{XmlSaveType.SESSION, XmlSaveType.WORKSPACE}; int[] posibleImportUUIDBehaviors = new int[]{ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW}; boolean[] posibleExportedByStream = new boolean[]{true, false}; boolean[] posibleImportedByStream = new boolean[]{true, false}; boolean[] posibleSystemViewExport = new boolean[]{true, false}; Collection<Callable<XmlTestResult>> tasks = new ArrayList<Callable<XmlTestResult>>(); List<Session> sessions = new ArrayList<Session>(); for (int z = 0; z < attempts; z++) { for (int i = 0; i < posibleSaveTypes.length; i++) { for (int j = 0; j < posibleImportUUIDBehaviors.length; j++) { for (int j2 = 0; j2 < posibleExportedByStream.length; j2++) { for (int k = 0; k < posibleImportedByStream.length; k++) { for (int k2 = 0; k2 < posibleSystemViewExport.length; k2++) { BeforeExportAction be; BeforeImportAction bi; AfterImportAction ai; try { Session testSession = repository.login(credentials); String testRootName = IdGenerator.generate(); Node testRoot = testSession.getRootNode().addNode(testRootName); testSession.save(); be = ((BeforeExportAction)initImportExportAction(firstAction, testSession, testRoot)); bi = ((BeforeImportAction)initImportExportAction(secondAction, testSession, testRoot)); ai = ((AfterImportAction)initImportExportAction(thirdAction, testSession, testRoot)); if (testSession.getRootNode().hasNode(testRootName)) { testSession.getRootNode().getNode(testRootName).remove(); testSession.save(); } sessions.add(testSession); } catch (IllegalArgumentException e) { throw new RepositoryException(e); } catch (InstantiationException e) { throw new RepositoryException(e); } catch (IllegalAccessException e) { throw new RepositoryException(e); } catch (InvocationTargetException e) { throw new RepositoryException(e); } tasks.add(new XmlTestTask(be, bi, ai, posibleSaveTypes[i], posibleImportUUIDBehaviors[j], posibleExportedByStream[j2], posibleImportedByStream[k], posibleSystemViewExport[k2])); } } } } } } executor.invokeAll(tasks); for (Session testSession : sessions) { testSession.logout(); } } /** * Serialize content of MIX_REFERENCEABLE_NODE_NAME to byte array. * * @param rootNode * @param isSystemView * @param isStream * @return * @throws IOException * @throws RepositoryException * @throws SAXException * @throws TransformerConfigurationException */ protected byte[] serialize(Node exportRootNode, boolean isSystemView, boolean isStream) throws IOException, RepositoryException, SAXException, TransformerConfigurationException { ExtendedSession extendedSession = (ExtendedSession)exportRootNode.getSession(); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); if (isSystemView) { if (isStream) { extendedSession.exportSystemView(exportRootNode.getPath(), outStream, false, false); } else { SAXTransformerFactory saxFact = (SAXTransformerFactory)TransformerFactory.newInstance(); TransformerHandler handler = saxFact.newTransformerHandler(); handler.setResult(new StreamResult(outStream)); extendedSession.exportSystemView(exportRootNode.getPath(), handler, false, false); } } else { if (isStream) { extendedSession.exportDocumentView(exportRootNode.getPath(), outStream, false, false); } else { SAXTransformerFactory saxFact = (SAXTransformerFactory)TransformerFactory.newInstance(); TransformerHandler handler = saxFact.newTransformerHandler(); handler.setResult(new StreamResult(outStream)); extendedSession.exportDocumentView(exportRootNode.getPath(), handler, false, false); } } outStream.close(); return outStream.toByteArray(); } /** * Serialize content of MIX_REFERENCEABLE_NODE_NAME to file. * * @param rootNode * @param isSystemView * @param isStream * @return * @throws IOException * @throws RepositoryException * @throws SAXException * @throws TransformerConfigurationException */ protected File serializeToFile(Node exportRootNode, boolean isSystemView, boolean isStream) throws IOException, RepositoryException, SAXException, TransformerConfigurationException { ExtendedSession extendedSession = (ExtendedSession) exportRootNode.getSession(); File file = File.createTempFile("export", ".xml"); FileOutputStream outStream = new FileOutputStream(file); if (isSystemView) { if (isStream) { extendedSession.exportSystemView(exportRootNode.getPath(), outStream, false, false); } else { SAXTransformerFactory saxFact = (SAXTransformerFactory) TransformerFactory.newInstance(); TransformerHandler handler = saxFact.newTransformerHandler(); handler.setResult(new StreamResult(outStream)); extendedSession.exportSystemView(exportRootNode.getPath(), handler, false, false); } } else { if (isStream) { extendedSession.exportDocumentView(exportRootNode.getPath(), outStream, false, false); } else { SAXTransformerFactory saxFact = (SAXTransformerFactory) TransformerFactory.newInstance(); TransformerHandler handler = saxFact.newTransformerHandler(); handler.setResult(new StreamResult(outStream)); extendedSession.exportDocumentView(exportRootNode.getPath(), handler, false, false); } } outStream.close(); return file; } protected void serialize(Node rootNode, boolean isSystemView, boolean isStream, File content) throws IOException, RepositoryException, SAXException, TransformerConfigurationException { ExtendedSession extendedSession = (ExtendedSession)rootNode.getSession(); OutputStream outStream = new FileOutputStream(content); if (isSystemView) { if (isStream) { extendedSession.exportSystemView(rootNode.getPath(), outStream, false, false); } else { SAXTransformerFactory saxFact = (SAXTransformerFactory)TransformerFactory.newInstance(); TransformerHandler handler = saxFact.newTransformerHandler(); handler.setResult(new StreamResult(outStream)); extendedSession.exportSystemView(rootNode.getPath(), handler, false, false); } } else { if (isStream) { extendedSession.exportDocumentView(rootNode.getPath(), outStream, false, false); } else { SAXTransformerFactory saxFact = (SAXTransformerFactory)TransformerFactory.newInstance(); TransformerHandler handler = saxFact.newTransformerHandler(); handler.setResult(new StreamResult(outStream)); extendedSession.exportDocumentView(rootNode.getPath(), handler, false, false); } } outStream.close(); } private ImportExportAction initImportExportAction(final Class<? extends ImportExportAction> importExportAction, final Session initSession, final Node testRoot) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { Constructor<?>[] constructors = importExportAction.getDeclaredConstructors(); Constructor<? extends ImportExportAction> constructor = null; for (int i = 0; i < constructors.length; i++) { if (constructors[i].getParameterTypes().length > 1) constructor = (Constructor<? extends ImportExportAction>)constructors[i]; } ImportExportAction action = constructor.newInstance(new Object[]{this, initSession, testRoot}); return action; } protected abstract class AfterImportAction extends ImportExportAction { public AfterImportAction(Session session, Node testRootNode) throws RepositoryException { super(session, testRootNode); } @Override public void cleanUp() throws RepositoryException { session.refresh(false); Node rootNode = session.getRootNode(); if (rootNode.hasNodes()) { // clean test root for (NodeIterator children = rootNode.getNodes(); children.hasNext();) { Node node = children.nextNode(); if (!node.getPath().startsWith("/jcr:system")) { // log.info("DELETing ------------- "+node.getPath()); node.remove(); } } session.save(); } } } protected abstract class BeforeExportAction extends ImportExportAction { public BeforeExportAction(Session session, Node testRootNode) throws RepositoryException { super(session, testRootNode); } public abstract Node getExportRoot() throws RepositoryException; } protected abstract class BeforeImportAction extends ImportExportAction { public BeforeImportAction(Session session, Node testRootNode) throws RepositoryException { super(session, testRootNode); } public abstract Node getImportRoot() throws RepositoryException; } protected abstract class ImportExportAction { protected final Node testRootNode; protected final Session testSession; public ImportExportAction(Session testSession, Node testRootNode) throws RepositoryException { super(); this.testSession = testSession; this.testRootNode = testRootNode; } public void cleanUp() throws RepositoryException { }; public void execute() throws RepositoryException { } } private class XmlTestTask implements Callable<XmlTestResult> { private final BeforeExportAction firstAction; private final XmlSaveType importSaveType; private final int importUUIDBehavior; private final boolean isExportedByStream; private final boolean isImportedByStream; private final boolean isSystemViewExport; private final BeforeImportAction secondAction; private final AfterImportAction thirdAction; public XmlTestTask(BeforeExportAction firstAction, BeforeImportAction secondAction, AfterImportAction thirdAction, XmlSaveType importSaveType, int importUUIDBehavior, boolean isExportedByStream, boolean isImportedByStream, boolean isSystemViewExport) { super(); this.firstAction = firstAction; this.secondAction = secondAction; this.thirdAction = thirdAction; this.importSaveType = importSaveType; this.importUUIDBehavior = importUUIDBehavior; this.isExportedByStream = isExportedByStream; this.isImportedByStream = isImportedByStream; this.isSystemViewExport = isSystemViewExport; } public XmlTestResult call() throws Exception { if (log.isDebugEnabled()) log.debug("isSys=" + isSystemViewExport + "\t" + "isES=" + isExportedByStream + "\t" + "importST=" + importSaveType.toString() + "\t" + "isIS=" + isImportedByStream + "\t" + "importBehavior=" + importUUIDBehavior + "\t"); firstAction.execute(); firstAction.cleanUp(); byte[] buf = serialize(firstAction.getExportRoot(), isSystemViewExport, isExportedByStream); secondAction.execute(); secondAction.cleanUp(); Node importRoot = secondAction.getImportRoot(); Exception resultException = null; try { deserialize(importRoot, importSaveType, isImportedByStream, importUUIDBehavior, new ByteArrayInputStream( buf)); if (importSaveType.equals(XmlSaveType.SESSION)) importRoot.getSession().save(); } catch (RepositoryException e) { resultException = e; } catch (SAXException e) { resultException = e; } if (resultException != null && importUUIDBehavior != ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW) { if (resultException instanceof RepositoryException) throw (RepositoryException)resultException; else if (resultException instanceof SAXException) throw (SAXException)resultException; } thirdAction.execute(); thirdAction.cleanUp(); return null; } } public class XmlTestResult { } }