/* * Copyright (C) 2003-2017 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.management.content.operations.site.contents; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.exoplatform.ecm.webui.utils.Utils; import org.exoplatform.management.common.exportop.JCRNodeExportTask; import org.exoplatform.management.common.importop.AbstractJCRImportOperationHandler; import org.exoplatform.management.content.operations.site.SiteUtil; import org.exoplatform.services.compress.CompressData; import org.exoplatform.services.jcr.RepositoryService; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.gatein.management.api.exceptions.OperationException; import org.gatein.management.api.operation.OperationNames; import org.gatein.management.api.operation.model.ExportTask; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; 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.UUID; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.Value; import javax.jcr.query.Query; import javax.jcr.query.QueryManager; import javax.jcr.query.QueryResult; /** * The Class SiteContentsVersionHistoryExportTask. */ public class SiteContentsVersionHistoryExportTask implements ExportTask { /** The Constant log. */ private static final Log log = ExoLogger.getLogger(JCRNodeExportTask.class); /** The Constant VERSION_HISTORY_FILE_SUFFIX. */ public static final String VERSION_HISTORY_FILE_SUFFIX = "_VersionHistory.zip"; /** The Constant ROOT_SQL_QUERY. */ public static final String ROOT_SQL_QUERY = "select * from mix:versionable order by exo:dateCreated DESC"; /** The Constant VERSION_SQL_QUERY. */ public static final String VERSION_SQL_QUERY = "select * from mix:versionable where jcr:path like '$0/%' " + "order by exo:dateCreated DESC"; /** The temp files. */ private static List<File> tempFiles = new ArrayList<File>(); /** The repository service. */ private final RepositoryService repositoryService; /** The workspace. */ private final String workspace; /** The absolute path. */ private final String absolutePath; /** The site name. */ private final String siteName; /** The recurse. */ private final boolean recurse; /** * Instantiates a new site contents version history export task. * * @param repositoryService the repository service * @param workspace the workspace * @param siteName the site name * @param absolutePath the absolute path * @param recurse the recurse */ public SiteContentsVersionHistoryExportTask(RepositoryService repositoryService, String workspace, String siteName, String absolutePath, boolean recurse) { this.repositoryService = repositoryService; this.workspace = workspace; this.siteName = siteName; this.absolutePath = absolutePath; this.recurse = recurse; } /** * {@inheritDoc} */ @Override public String getEntry() { return SiteUtil.getSiteContentsBasePath(siteName) + "/" + JCRNodeExportTask.JCR_DATA_SEPARATOR + absolutePath + VERSION_HISTORY_FILE_SUFFIX; } /** * {@inheritDoc} */ @Override public void export(OutputStream outputStream) throws IOException { log.info("Export VersionHistory: " + workspace + ":" + absolutePath); List<OutputStream> ousList = new ArrayList<OutputStream>(); List<InputStream> isList = new ArrayList<InputStream>(); File exportedFile = null; File zipFile = null; File propertiesFile = getExportedFile("mapping", ".properties"); OutputStream propertiesBOS = new BufferedOutputStream(new FileOutputStream(propertiesFile)); InputStream propertiesBIS = new BufferedInputStream(new TempFileInputStream(propertiesFile)); CompressData zipService = new CompressData(); Session session = null; try { Node currentNode = getCurrentNode(); String sysWsName = repositoryService.getCurrentRepository().getConfiguration().getSystemWorkspaceName(); session = AbstractJCRImportOperationHandler.getSession(repositoryService, sysWsName); if (recurse) { // Export version history of sub nodes QueryResult queryResult = getQueryResult(currentNode); NodeIterator queryIter = queryResult.getNodes(); while (queryIter.hasNext()) { Node node = queryIter.nextNode(); exportedFile = getExportedFile("data", ".xml"); OutputStream out = new BufferedOutputStream(new FileOutputStream(exportedFile)); ousList.add(out); InputStream in = new BufferedInputStream(new TempFileInputStream(exportedFile)); isList.add(in); String historyValue = getHistoryValue(node); propertiesBOS.write(historyValue.getBytes()); propertiesBOS.write('\n'); session.exportDocumentView(node.getVersionHistory().getPath(), out, false, false); out.flush(); zipService.addInputStream(node.getUUID() + ".xml", in); } } if (currentNode.isNodeType(Utils.MIX_VERSIONABLE)) { // Export version history of current nodes exportedFile = getExportedFile("data", ".xml"); OutputStream out = new BufferedOutputStream(new FileOutputStream(exportedFile)); ousList.add(out); InputStream in = new BufferedInputStream(new TempFileInputStream(exportedFile)); isList.add(in); String historyValue = getHistoryValue(currentNode); propertiesBOS.write(historyValue.getBytes()); propertiesBOS.write('\n'); session.exportDocumentView(currentNode.getVersionHistory().getPath(), out, false, false); out.flush(); zipService.addInputStream(currentNode.getUUID() + ".xml", in); } propertiesBOS.flush(); zipService.addInputStream("mapping.properties", propertiesBIS); zipFile = getExportedFile("data", ".zip"); InputStream in = new BufferedInputStream(new TempFileInputStream(zipFile)); isList.add(in); OutputStream out = new BufferedOutputStream(new FileOutputStream(zipFile)); ousList.add(out); out.flush(); zipService.createZip(out); IOUtils.copy(in, outputStream); outputStream.flush(); } catch (OutOfMemoryError error) { throw new OperationException(OperationNames.EXPORT_RESOURCE, "OutOfMemoryError, Unable to export content from : " + absolutePath, error); } catch (Exception exception) { throw new OperationException(OperationNames.EXPORT_RESOURCE, "Unable to export content from : " + absolutePath, exception); } finally { propertiesBOS.close(); propertiesBIS.close(); for (InputStream inputStream : isList) { if (inputStream != null) { inputStream.close(); } } for (OutputStream ous : ousList) { if (ous != null) { ous.close(); } } if (session != null) { session.logout(); } clearTempFiles(); } } /** * Delete temp files created by GateIN management operations. */ protected void clearTempFiles() { for (File tempFile : tempFiles) { if (tempFile != null && tempFile.exists()) { tempFile.delete(); } } } /** * Gets the query result. * * @param currentNode the current node * @return the query result * @throws Exception the exception */ private QueryResult getQueryResult(Node currentNode) throws Exception { QueryManager queryManager = currentNode.getSession().getWorkspace().getQueryManager(); String queryStatement = ""; if (currentNode.getPath().equals("/")) { queryStatement = ROOT_SQL_QUERY; } else { queryStatement = StringUtils.replace(VERSION_SQL_QUERY, "$0", currentNode.getPath()); } Query query = queryManager.createQuery(queryStatement, Query.SQL); return query.execute(); } /** * Gets the current node. * * @return the current node * @throws Exception the exception */ private Node getCurrentNode() throws Exception { Session session = null; try { session = AbstractJCRImportOperationHandler.getSession(repositoryService, workspace); return (Node) session.getItem(absolutePath); } catch (RepositoryException exception) { throw new OperationException(OperationNames.EXPORT_RESOURCE, "Unable to export content from : " + absolutePath, exception); } } /** * Gets the history value. * * @param node the node * @return the history value * @throws Exception the exception */ private String getHistoryValue(Node node) throws Exception { String versionHistory = node.getProperty("jcr:versionHistory").getValue().getString(); String baseVersion = node.getProperty("jcr:baseVersion").getValue().getString(); Value[] predecessors = node.getProperty("jcr:predecessors").getValues(); StringBuilder historyValue = new StringBuilder(); StringBuilder predecessorsBuilder = new StringBuilder(); for (Value value : predecessors) { if (predecessorsBuilder.length() > 0) predecessorsBuilder.append(","); predecessorsBuilder.append(value.getString()); } historyValue.append(node.getUUID()).append("=").append(versionHistory).append(";").append(baseVersion).append(";").append(predecessorsBuilder.toString()); return historyValue.toString(); } /** * Create temp file to allow download a big data. * * @param prefix the prefix * @param suffix the suffix * @return file * @throws IOException Signals that an I/O exception has occurred. */ private static File getExportedFile(String prefix, String suffix) throws IOException { File tempFile = File.createTempFile(prefix.concat(UUID.randomUUID().toString()), suffix); tempFile.deleteOnExit(); tempFiles.add(tempFile); return tempFile; } }