/*
* 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.forum.operations;
import org.exoplatform.commons.utils.ListAccess;
import org.exoplatform.forum.common.jcr.KSDataLocation;
import org.exoplatform.forum.service.Category;
import org.exoplatform.forum.service.Forum;
import org.exoplatform.forum.service.ForumService;
import org.exoplatform.forum.service.Post;
import org.exoplatform.forum.service.Topic;
import org.exoplatform.forum.service.Utils;
import org.exoplatform.forum.service.impl.model.TopicFilter;
import org.exoplatform.management.common.FileEntry;
import org.exoplatform.management.common.exportop.ActivitiesExportTask;
import org.exoplatform.management.common.exportop.SpaceMetadataExportTask;
import org.exoplatform.management.common.importop.AbstractJCRImportOperationHandler;
import org.exoplatform.management.common.importop.ActivityImportOperationInterface;
import org.exoplatform.management.common.importop.FileImportOperationInterface;
import org.exoplatform.management.forum.ForumExtension;
import org.exoplatform.poll.service.Poll;
import org.exoplatform.poll.service.PollService;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.social.core.activity.model.ExoSocialActivity;
import org.exoplatform.social.core.manager.ActivityManager;
import org.exoplatform.social.core.space.SpaceUtils;
import org.exoplatform.social.core.space.model.Space;
import org.exoplatform.social.core.space.spi.SpaceService;
import org.exoplatform.social.core.storage.api.ActivityStorage;
import org.exoplatform.social.core.storage.api.IdentityStorage;
import org.gatein.common.logging.Logger;
import org.gatein.common.logging.LoggerFactory;
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.NoResultModel;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* The Class ForumDataImportResource.
*
* @author <a href="mailto:bkhanfir@exoplatform.com">Boubaker Khanfir</a>
* @version $Revision$
*/
public class ForumDataImportResource extends AbstractJCRImportOperationHandler implements ActivityImportOperationInterface, FileImportOperationInterface {
/** The Constant log. */
final private static Logger log = LoggerFactory.getLogger(ForumDataImportResource.class);
/** The forum service. */
private ForumService forumService;
/** The poll service. */
private PollService pollService;
/** The data location. */
private KSDataLocation dataLocation;
/** The type. */
private String type;
/**
* Instantiates a new forum data import resource.
*
* @param isSpaceForumType the is space forum type
*/
public ForumDataImportResource(boolean isSpaceForumType) {
type = isSpaceForumType ? ForumExtension.SPACE_FORUM_TYPE : ForumExtension.PUBLIC_FORUM_TYPE;
}
/**
* {@inheritDoc}
*/
@Override
public void execute(OperationContext operationContext, ResultHandler resultHandler) throws OperationException {
spaceService = operationContext.getRuntimeContext().getRuntimeComponent(SpaceService.class);
forumService = operationContext.getRuntimeContext().getRuntimeComponent(ForumService.class);
repositoryService = operationContext.getRuntimeContext().getRuntimeComponent(RepositoryService.class);
dataLocation = operationContext.getRuntimeContext().getRuntimeComponent(KSDataLocation.class);
activityManager = operationContext.getRuntimeContext().getRuntimeComponent(ActivityManager.class);
activityStorage = operationContext.getRuntimeContext().getRuntimeComponent(ActivityStorage.class);
identityStorage = operationContext.getRuntimeContext().getRuntimeComponent(IdentityStorage.class);
pollService = operationContext.getRuntimeContext().getRuntimeComponent(PollService.class);
OperationAttributes attributes = operationContext.getAttributes();
List<String> filters = attributes.getValues("filter");
// "replace-existing" attribute. Defaults to false.
boolean replaceExisting = filters.contains("replace-existing:true");
// "create-space" attribute. Defaults to false.
boolean createSpace = filters.contains("create-space:true");
log.info("Importing Forums Data");
InputStream attachmentInputStream = getAttachementInputStream(operationContext);
increaseCurrentTransactionTimeOut(operationContext);
try {
// extract data from zip
Map<String, List<FileEntry>> contentsByOwner = extractDataFromZip(attachmentInputStream);
String workspace = dataLocation.getWorkspace();
for (String categoryId : contentsByOwner.keySet()) {
List<FileEntry> fileEntries = contentsByOwner.get(categoryId);
boolean isSpaceForum = categoryId.contains(Utils.FORUM_SPACE_ID_PREFIX);
if (isSpaceForum) {
String forumId = categoryId;
FileEntry spaceMetadataFile = getAndRemoveFileByPath(fileEntries, SpaceMetadataExportTask.FILENAME);
boolean spaceCreatedOrAlreadyExists = false;
if (spaceMetadataFile != null && spaceMetadataFile.getFile().exists()) {
spaceCreatedOrAlreadyExists = createSpaceIfNotExists(spaceMetadataFile.getFile(), createSpace);
}
if (!spaceCreatedOrAlreadyExists) {
log.warn("Import of forum category '" + categoryId + "' is ignored because space doesn't exist."
+ " Turn on 'create-space:true' option if you want to automatically create the space and you should provide the space metadata with exported ZIP file.");
continue;
}
Category spaceCategory = forumService.getCategoryIncludedSpace();
Forum forum = forumService.getForum(spaceCategory.getId(), forumId);
if (forum != null) {
if (replaceExisting) {
log.info("Overwrite existing Space Forum: '" + forum.getForumName() + "' (replace-existing=true)");
deleteActivities(spaceCategory.getId(), forumId);
} else {
log.info("Ignore existing Space Forum: '" + forum.getForumName() + "' (replace-existing=false)");
continue;
}
}
FileEntry activitiesFile = getAndRemoveFileByPath(fileEntries, ActivitiesExportTask.FILENAME);
Collections.sort(fileEntries);
for (FileEntry fileEntry : fileEntries) {
importNode(fileEntry, workspace, false);
}
// Refresh caches
forumService.calculateDeletedUser("fakeUser" + Utils.DELETED);
// Import activities
if (activitiesFile != null && activitiesFile.getFile().exists()) {
String spaceGroupName = forumId.replace(Utils.FORUM_SPACE_ID_PREFIX, "");
String spaceGroupId = SpaceUtils.SPACE_GROUP + "/" + spaceGroupName;
Space space = spaceService.getSpaceByGroupId(spaceGroupId);
log.info("Importing Forum activities");
importActivities(activitiesFile.getFile(), space.getPrettyName(), true);
}
} else {
Category category = forumService.getCategory(categoryId);
if (category != null) {
if (replaceExisting) {
log.info("Overwrite existing Forum Category: '" + category.getCategoryName() + "' (replace-existing=true)");
@SuppressWarnings("deprecation")
List<Forum> forums = forumService.getForums(categoryId, null);
for (Forum forum : forums) {
deleteActivities(categoryId, forum.getId());
}
} else {
log.info("Ignore existing Forum Category: '" + category.getCategoryName() + "' (replace-existing=false)");
continue;
}
}
FileEntry activitiesFile = getAndRemoveFileByPath(fileEntries, ActivitiesExportTask.FILENAME);
Collections.sort(fileEntries);
for (FileEntry fileEntry : fileEntries) {
importNode(fileEntry, workspace, false);
}
// Refresh caches
forumService.calculateDeletedUser("fakeUser" + Utils.DELETED);
// Import activities
if (activitiesFile != null && activitiesFile.getFile().exists()) {
log.info("Importing Forum activities");
importActivities(activitiesFile.getFile(), null, true);
}
}
}
forumService.calculateDeletedUser("fakeUser" + Utils.DELETED);
} catch (Exception e) {
throw new OperationException(OperationNames.IMPORT_RESOURCE, "Unable to import forum contents", e);
} finally {
restoreDefaultTransactionTimeOut(repositoryService);
if (attachmentInputStream != null) {
try {
attachmentInputStream.close();
} catch (IOException e) {
// Nothing to do
}
}
}
resultHandler.completed(NoResultModel.INSTANCE);
}
/**
* {@inheritDoc}
*/
@Override
public String getNodePath(String filePath) {
return super.getNodePath(filePath);
}
/**
* {@inheritDoc}
*/
public String getManagedFilesPrefix() {
return "forum/" + type + "/";
}
/**
* {@inheritDoc}
*/
public boolean isUnKnownFileFormat(String filePath) {
return !filePath.endsWith(".xml") && !filePath.endsWith(SpaceMetadataExportTask.FILENAME) && !filePath.contains(ActivitiesExportTask.FILENAME);
}
/**
* {@inheritDoc}
*/
public boolean addSpecialFile(List<FileEntry> fileEntries, String filePath, File file) {
if (filePath.endsWith(SpaceMetadataExportTask.FILENAME)) {
fileEntries.add(new FileEntry(SpaceMetadataExportTask.FILENAME, file));
return true;
} else if (filePath.endsWith(ActivitiesExportTask.FILENAME)) {
fileEntries.add(new FileEntry(ActivitiesExportTask.FILENAME, file));
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
public void attachActivityToEntity(ExoSocialActivity activity, ExoSocialActivity comment) throws Exception {
if (activity.getTemplateParams().containsKey("PollLink")) {
if (comment == null) {
String topicId = activity.getTemplateParams().get("Id");
String pollId = topicId.replace(Utils.TOPIC, Utils.POLL);
Poll poll = pollService.getPoll(pollId);
String pollPath = poll.getParentPath() + "/" + pollId;
pollService.saveActivityIdForOwner(pollPath, activity.getId());
} else {
// Don't attach poll comment to anything
}
return;
}
String catId = activity.getTemplateParams().get("CateId");
if (catId == null) {
return;
} else {
String forumId = activity.getTemplateParams().get("ForumId");
String topicId = activity.getTemplateParams().get("TopicId");
Topic topic = forumService.getTopic(catId, forumId, topicId, null);
if (comment == null) {
forumService.saveActivityIdForOwnerPath(topic.getPath(), activity.getId());
} else {
String postId = comment.getTemplateParams().get("PostId");
if (postId != null) {
Post post = forumService.getPost(catId, forumId, topicId, postId);
forumService.saveActivityIdForOwnerPath(post.getPath(), comment.getId());
}
}
}
}
/**
* {@inheritDoc}
*/
public boolean isActivityNotValid(ExoSocialActivity activity, ExoSocialActivity comment) throws Exception {
if (activity.getTemplateParams().containsKey("PollLink")) {
String topicId = activity.getTemplateParams().get("Id");
if (topicId == null) {
log.warn("Poll with null id of topic. Cannot import activity '" + activity.getTitle() + "'.");
return true;
}
String pollId = topicId.replace(Utils.TOPIC, Utils.POLL);
Poll poll = pollService.getPoll(pollId);
if (poll == null) {
log.warn("Poll not found. Cannot import activity '" + activity.getTitle() + "'.");
return true;
}
return false;
}
String catId = activity.getTemplateParams().get("CateId");
if (catId == null) {
return false;
} else {
String forumId = activity.getTemplateParams().get("ForumId");
String topicId = activity.getTemplateParams().get("TopicId");
if (forumId == null || topicId == null) {
log.warn("Activity template params are inconsistent: '" + activity.getTitle() + "'.");
return true;
}
Topic topic = forumService.getTopic(catId, forumId, topicId, null);
if (topic == null) {
log.warn("Forum Topic not found. Cannot import activity '" + activity.getTitle() + "'.");
return true;
}
if (comment != null) {
String postId = comment.getTemplateParams().get("PostId");
if (postId != null) {
Post post = forumService.getPost(catId, forumId, topicId, postId);
if (post == null) {
log.warn("Forum Post not found. Cannot import activity '" + activity.getTitle() + "'.");
return true;
}
}
}
}
return false;
}
/**
* {@inheritDoc}
*/
public String extractIdFromPath(String path) {
int beginIndex = ("forum/" + type + "/").length();
int endIndex = path.indexOf("/", beginIndex + 1);
return path.substring(beginIndex, endIndex);
}
/**
* Delete activities.
*
* @param categoryId the category id
* @param forumId the forum id
* @throws Exception the exception
*/
private void deleteActivities(String categoryId, String forumId) throws Exception {
// Delete Forum activity stream
TopicFilter topicFilter = new TopicFilter(categoryId, forumId);
ListAccess<Topic> topicsListAccess = forumService.getTopics(topicFilter);
if (topicsListAccess.getSize() > 0) {
Topic[] topics = topicsListAccess.load(0, topicsListAccess.getSize());
for (Topic topic : topics) {
ExoSocialActivity activity = activityManager.getActivity(forumService.getActivityIdForOwnerId(topic.getId()));
if (activity != null) {
deleteActivity(activity);
}
}
}
}
}