/*
* 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.lang.StringUtils;
import org.exoplatform.commons.utils.ActivityTypeUtils;
import org.exoplatform.management.common.DataTransformerService;
import org.exoplatform.management.common.exportop.AbstractJCRExportOperationHandler;
import org.exoplatform.management.common.exportop.ActivitiesExportTask;
import org.exoplatform.management.common.exportop.JCRNodeExportTask;
import org.exoplatform.management.content.operations.site.SiteUtil;
import org.exoplatform.services.cms.templates.TemplateService;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.wcm.core.NodeLocation;
import org.exoplatform.services.wcm.core.WCMConfigurationService;
import org.exoplatform.services.wcm.portal.PortalFolderSchemaHandler;
import org.exoplatform.social.core.activity.model.ExoSocialActivity;
import org.exoplatform.social.core.manager.ActivityManager;
import org.exoplatform.social.core.manager.IdentityManager;
import org.gatein.management.api.PathAddress;
import org.gatein.management.api.exceptions.OperationException;
import org.gatein.management.api.operation.OperationAttributes;
import org.gatein.management.api.operation.OperationContext;
import org.gatein.management.api.operation.OperationNames;
import org.gatein.management.api.operation.ResultHandler;
import org.gatein.management.api.operation.model.ExportResourceModel;
import org.gatein.management.api.operation.model.ExportTask;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.query.Query;
/**
* The Class SiteContentsExportResource.
*
* @author <a href="mailto:thomas.delhomenie@exoplatform.com">Thomas
* Delhoménie</a>
* @author <a href="mailto:boubaker.khanfir@exoplatform.com">Boubaker
* Khanfir</a>
* @version $Revision$
*/
public class SiteContentsExportResource extends AbstractJCRExportOperationHandler {
/** The Constant log. */
private static final Log log = ExoLogger.getLogger(SiteContentsExportResource.class);
/** The Constant FILTER_SEPARATOR. */
public static final String FILTER_SEPARATOR = ":";
/** The wcm configuration service. */
private WCMConfigurationService wcmConfigurationService = null;
/**
* {@inheritDoc}
*/
@Override
public void execute(OperationContext operationContext, ResultHandler resultHandler) throws OperationException {
increaseCurrentTransactionTimeOut(operationContext);
try {
String operationName = operationContext.getOperationName();
PathAddress address = operationContext.getAddress();
OperationAttributes attributes = operationContext.getAttributes();
String siteName = address.resolvePathTemplate("site-name");
if (siteName == null) {
throw new OperationException(operationName, "No site name specified.");
}
repositoryService = operationContext.getRuntimeContext().getRuntimeComponent(RepositoryService.class);
templateService = operationContext.getRuntimeContext().getRuntimeComponent(TemplateService.class);
wcmConfigurationService = operationContext.getRuntimeContext().getRuntimeComponent(WCMConfigurationService.class);
identityManager = operationContext.getRuntimeContext().getRuntimeComponent(IdentityManager.class);
activityManager = operationContext.getRuntimeContext().getRuntimeComponent(ActivityManager.class);
List<ExportTask> exportTasks = new ArrayList<ExportTask>();
List<String> excludePaths = attributes.getValues("excludePaths");
List<String> filters = attributes.getValues("filter");
NodeLocation sitesLocation = wcmConfigurationService.getLivePortalsLocation();
// "taxonomy" attribute. Defaults to true.
boolean exportSiteTaxonomy = !filters.contains("taxonomy:false");
// "no-history" attribute. Defaults to false.
boolean exportVersionHistory = !filters.contains("no-history:true");
// Exports only metadata
boolean exportOnlyMetadata = filters.contains("only-metadata:true");
// Exports with skeleton
boolean exportSiteWithSkeleton = !filters.contains("no-skeleton:true");
// get JCR Query
String jcrQuery = getParameterValue(filters, "query:", null);
// get JCR workspace
String workspace = getParameterValue(filters, "workspace:", sitesLocation.getWorkspace());
// remove JCR Nodes
String removeNodes = getParameterValue(filters, "removeNodes:", null);
// get JCR Site path
String sitePath = (sitesLocation.getPath().endsWith("/") ? sitesLocation.getPath() : (sitesLocation.getPath() + "/")) + siteName;
SiteMetaData metaData = new SiteMetaData();
metaData.getOptions().put(SiteMetaData.SITE_PATH, sitePath);
metaData.getOptions().put(SiteMetaData.SITE_WORKSPACE, workspace);
metaData.getOptions().put(SiteMetaData.SITE_NAME, siteName);
if (!StringUtils.isEmpty(removeNodes)) {
metaData.getOptions().put("removeNodes", removeNodes);
} else {
Set<String> activitiesId = new HashSet<String>();
// Site contents
if (!StringUtils.isEmpty(jcrQuery)) {
exportTasks.addAll(exportQueryResult(workspace, sitePath, jcrQuery, excludePaths, exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
} else if (exportSiteWithSkeleton) {
exportTasks.addAll(exportSite(workspace, sitePath, exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
} else {
exportTasks.addAll(exportSiteWithoutSkeleton(workspace, sitePath, exportSiteTaxonomy, exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
}
if (!exportOnlyMetadata) {
// Export activities
exportActivities(exportTasks, activitiesId, siteName);
}
}
// Export Site Metadata
exportTasks.add(new SiteMetaDataExportTask(metaData));
resultHandler.completed(new ExportResourceModel(exportTasks));
} catch (Exception e) {
throw new OperationException(OperationNames.EXPORT_RESOURCE, "Unable to export site contents, cause : " + e.getMessage(), e);
} finally {
restoreDefaultTransactionTimeOut(operationContext);
}
}
/**
* Export activities.
*
* @param exportTasks the export tasks
* @param activitiesId the activities id
* @param siteName the site name
*/
private void exportActivities(List<ExportTask> exportTasks, Set<String> activitiesId, String siteName) {
// In case of minimal profile
if (activityManager != null) {
try {
List<ExoSocialActivity> activities = new ArrayList<ExoSocialActivity>();
for (String activityId : activitiesId) {
addActivityWithComments(activities, activityId);
}
if (!activities.isEmpty()) {
exportTasks.add(new ActivitiesExportTask(identityManager, activities, SiteUtil.getSiteContentsBasePath(siteName)));
}
} catch (Exception e) {
log.warn("Can't export activities", e);
}
}
}
/**
* Export site.
*
* @param workspace the workspace
* @param siteRootNodePath the site root node path
* @param exportVersionHistory the export version history
* @param metaData the meta data
* @param activitiesId the activities id
* @param exportOnlyMetadata the export only metadata
* @return the list
* @throws Exception the exception
*/
private List<ExportTask> exportSite(String workspace, String siteRootNodePath, boolean exportVersionHistory, SiteMetaData metaData, Set<String> activitiesId, boolean exportOnlyMetadata)
throws Exception {
List<ExportTask> exportTasks = new ArrayList<ExportTask>();
Session session = getSession(workspace);
Node siteNode = (Node) session.getItem(siteRootNodePath);
Node parentNode = siteNode.getParent();
exportNode(workspace, parentNode, null, exportVersionHistory, exportTasks, siteNode, metaData, activitiesId, exportOnlyMetadata);
return exportTasks;
}
/**
* Export query result.
*
* @param workspace the workspace
* @param siteRootNodePath the site root node path
* @param jcrQuery the jcr query
* @param excludePaths the exclude paths
* @param exportVersionHistory the export version history
* @param metaData the meta data
* @param activitiesId the activities id
* @param exportOnlyMetadata the export only metadata
* @return the list
* @throws Exception the exception
*/
private List<ExportTask> exportQueryResult(String workspace, String siteRootNodePath, String jcrQuery, List<String> excludePaths, boolean exportVersionHistory, SiteMetaData metaData,
Set<String> activitiesId, boolean exportOnlyMetadata) throws Exception {
List<ExportTask> exportTasks = new ArrayList<ExportTask>();
if (!jcrQuery.contains("jcr:path")) {
String queryPath = "jcr:path = '" + siteRootNodePath + "/%'";
queryPath.replace("//", "/");
if (jcrQuery.contains("where")) {
int startIndex = jcrQuery.indexOf("where");
int endIndex = startIndex + "where".length();
String condition = jcrQuery.substring(endIndex);
condition = queryPath + " AND (" + condition + ")";
jcrQuery = jcrQuery.substring(0, startIndex) + " where " + condition;
} else {
jcrQuery += " where " + queryPath;
}
}
Session session = getSession(workspace);
Query query = session.getWorkspace().getQueryManager().createQuery(jcrQuery, Query.SQL);
NodeIterator nodeIterator = query.execute().getNodes();
while (nodeIterator.hasNext()) {
Node node = nodeIterator.nextNode();
exportNode(workspace, node.getParent(), excludePaths, exportVersionHistory, exportTasks, node, metaData, activitiesId, exportOnlyMetadata);
}
return exportTasks;
}
/**
* Export site without skeleton.
*
* @param workspace the workspace
* @param path the path
* @param exportSiteTaxonomy the export site taxonomy
* @param exportVersionHistory the export version history
* @param metaData the meta data
* @param activitiesId the activities id
* @param exportOnlyMetadata the export only metadata
* @return the list
* @throws Exception the exception
* @throws RepositoryException the repository exception
*/
private List<ExportTask> exportSiteWithoutSkeleton(String workspace, String path, boolean exportSiteTaxonomy, boolean exportVersionHistory, SiteMetaData metaData, Set<String> activitiesId,
boolean exportOnlyMetadata) throws Exception, RepositoryException {
List<ExportTask> exportTasks = new ArrayList<ExportTask>();
NodeLocation nodeLocation = new NodeLocation("repository", workspace, path, null, true);
Node portalNode = NodeLocation.getNodeByLocation(nodeLocation);
PortalFolderSchemaHandler portalFolderSchemaHandler = new PortalFolderSchemaHandler();
// CSS Folder
exportTasks.addAll(exportSubNodes(workspace, portalFolderSchemaHandler.getCSSFolder(portalNode), null, exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
// JS Folder
exportTasks.addAll(exportSubNodes(workspace, portalFolderSchemaHandler.getJSFolder(portalNode), null, exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
// Document Folder
exportTasks.addAll(exportSubNodes(workspace, portalFolderSchemaHandler.getDocumentStorage(portalNode), null, exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
// Images Folder
exportTasks.addAll(exportSubNodes(workspace, portalFolderSchemaHandler.getImagesFolder(portalNode), null, exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
// Audio Folder
exportTasks.addAll(exportSubNodes(workspace, portalFolderSchemaHandler.getAudioFolder(portalNode), null, exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
// Video Folder
exportTasks.addAll(exportSubNodes(workspace, portalFolderSchemaHandler.getVideoFolder(portalNode), null, exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
// Multimedia Folder
exportTasks.addAll(exportSubNodes(workspace, portalFolderSchemaHandler.getMultimediaFolder(portalNode), Arrays.asList("images", "audio", "videos"), exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
// Link Folder
exportTasks.addAll(exportSubNodes(workspace, portalFolderSchemaHandler.getLinkFolder(portalNode), null, exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
// WebContent Folder
exportTasks.addAll(exportSubNodes(workspace, portalFolderSchemaHandler.getWebContentStorage(portalNode), Arrays.asList("site artifacts"), exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
// Site Artifacts Folder
Node webContentNode = portalFolderSchemaHandler.getWebContentStorage(portalNode);
exportTasks.addAll(exportSubNodes(workspace, webContentNode.getNode("site artifacts"), null, exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
if (exportSiteTaxonomy) {
// Categories Folder
Node categoriesNode = portalNode.getNode("categories");
exportTasks.addAll(exportSubNodes(workspace, categoriesNode, null, exportVersionHistory, metaData, activitiesId, exportOnlyMetadata));
}
return exportTasks;
}
/**
* Export all sub-nodes of the given node.
*
* @param workspace the workspace
* @param parentNode the parent node
* @param excludedNodes the excluded nodes
* @param exportVersionHistory the export version history
* @param metaData the meta data
* @param activitiesId the activities id
* @param exportOnlyMetadata the export only metadata
* @return the list
* @throws Exception the exception
*/
protected List<ExportTask> exportSubNodes(String workspace, Node parentNode, List<String> excludedNodes, boolean exportVersionHistory, SiteMetaData metaData, Set<String> activitiesId,
boolean exportOnlyMetadata) throws Exception {
List<ExportTask> subNodesExportTask = new ArrayList<ExportTask>();
NodeIterator childrenNodes = parentNode.getNodes();
while (childrenNodes.hasNext()) {
Node childNode = (Node) childrenNodes.next();
exportNode(workspace, parentNode, excludedNodes, exportVersionHistory, subNodesExportTask, childNode, metaData, activitiesId, exportOnlyMetadata);
}
return subNodesExportTask;
}
/**
* Export node.
*
* @param workspace the workspace
* @param parentNode the parent node
* @param excludedNodes the excluded nodes
* @param exportVersionHistory the export version history
* @param subNodesExportTask the sub nodes export task
* @param childNode the child node
* @param metaData the meta data
* @param activitiesId the activities id
* @param exportOnlyMetadata the export only metadata
* @throws Exception the exception
*/
private void exportNode(String workspace, Node parentNode, List<String> excludedNodes, boolean exportVersionHistory, List<ExportTask> subNodesExportTask, Node childNode, SiteMetaData metaData,
Set<String> activitiesId, boolean exportOnlyMetadata) throws Exception {
if (excludedNodes == null || (!excludedNodes.contains(childNode.getName()) && !excludedNodes.contains(childNode.getPath()))) {
String path = childNode.getPath();
boolean recursive = isRecursiveExport(childNode);
if (!exportOnlyMetadata) {
if (childNode.isNodeType("exo:activityInfo")) {
String activityId = ActivityTypeUtils.getActivityId(childNode);
if (activityId != null && !activityId.isEmpty()) {
activitiesId.add(activityId);
}
}
String prefix = SiteUtil.getSiteContentsBasePath(metaData.getOptions().get(SiteMetaData.SITE_NAME));
JCRNodeExportTask siteContentExportTask = new JCRNodeExportTask(repositoryService, workspace, path, prefix, recursive, true);
subNodesExportTask.add(siteContentExportTask);
String parentPathName = siteContentExportTask.getEntry().substring(0, siteContentExportTask.getEntry().lastIndexOf('/'));
int initialSize = subNodesExportTask.size();
DataTransformerService.exportData("Content", subNodesExportTask, childNode, parentPathName);
if (initialSize < subNodesExportTask.size()) {
siteContentExportTask.setExportBinary(false);
}
if (exportVersionHistory && childNode.isNodeType(org.exoplatform.ecm.webui.utils.Utils.MIX_VERSIONABLE) && childNode.getVersionHistory().hasNodes()) {
SiteContentsVersionHistoryExportTask versionHistoryExportTask = new SiteContentsVersionHistoryExportTask(repositoryService, workspace, metaData.getOptions().get(SiteMetaData.SITE_NAME), path, recursive);
subNodesExportTask.add(versionHistoryExportTask);
}
} else {
NodeMetadata nodeMetadata = new NodeMetadata();
metaData.getNodesMetadata().put(path, nodeMetadata);
nodeMetadata.setPath(path);
if (childNode.hasProperty("exo:title")) {
nodeMetadata.setTitle(childNode.getProperty("exo:title").getString());
} else if (childNode.hasProperty("exo:name")) {
nodeMetadata.setTitle(childNode.getProperty("exo:name").getString());
} else {
nodeMetadata.setTitle(childNode.getName());
}
if (childNode.hasProperty("exo:lastModifier")) {
nodeMetadata.setLastModifier(childNode.getProperty("exo:lastModifier").getString());
}
if (childNode.hasProperty("publication:currentState")) {
nodeMetadata.setPublished(childNode.getProperty("publication:currentState").getString().equals("published"));
}
if (childNode.hasProperty("publication:liveDate")) {
nodeMetadata.setLiveDate(childNode.getProperty("publication:liveDate").getDate());
}
if (childNode.hasProperty("exo:lastModifiedDate")) {
nodeMetadata.setLastModificationDate(childNode.getProperty("exo:lastModifiedDate").getDate());
}
}
// If not export the whole node
if (!recursive) {
NodeIterator nodeIterator = childNode.getNodes();
while (nodeIterator.hasNext()) {
Node node = nodeIterator.nextNode();
exportNode(workspace, childNode, excludedNodes, exportVersionHistory, subNodesExportTask, node, metaData, activitiesId, exportOnlyMetadata);
}
}
}
}
/**
* Gets the parameter value.
*
* @param filters the filters
* @param prefix the prefix
* @param defaultValue the default value
* @return the parameter value
*/
private String getParameterValue(List<String> filters, String prefix, String defaultValue) {
String value = null;
for (String filterValue : filters) {
if (filterValue.startsWith(prefix)) {
value = filterValue.replace(prefix, "");
break;
}
}
if (defaultValue != null && (value == null || value.isEmpty())) {
value = defaultValue;
}
return value;
}
/**
* {@inheritDoc}
*/
@Override
protected void addJCRNodeExportTask(Node childNode, List<ExportTask> subNodesExportTask, boolean recursive, String... params) throws Exception {}
}