/* * 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.social.operations; import com.thoughtworks.xstream.XStream; import org.apache.commons.io.IOUtils; import org.exoplatform.container.PortalContainer; import org.exoplatform.container.component.RequestLifeCycle; import org.exoplatform.management.common.SpaceMetaData; import org.exoplatform.management.common.exportop.ActivitiesExportTask; import org.exoplatform.management.common.exportop.SpaceMetadataExportTask; import org.exoplatform.management.common.importop.AbstractImportOperationHandler; import org.exoplatform.management.common.importop.ActivityImportOperationInterface; import org.exoplatform.management.social.SocialExtension; import org.exoplatform.portal.config.DataStorage; import org.exoplatform.portal.config.UserACL; import org.exoplatform.portal.config.model.Dashboard; import org.exoplatform.portal.mop.importer.ImportMode; import org.exoplatform.services.organization.Group; import org.exoplatform.services.organization.OrganizationService; import org.exoplatform.services.organization.User; import org.exoplatform.social.common.RealtimeListAccess; import org.exoplatform.social.core.activity.model.ActivityStream.Type; import org.exoplatform.social.core.activity.model.ExoSocialActivity; import org.exoplatform.social.core.application.SpaceActivityPublisher; import org.exoplatform.social.core.identity.model.Identity; import org.exoplatform.social.core.identity.model.Profile; import org.exoplatform.social.core.identity.provider.SpaceIdentityProvider; import org.exoplatform.social.core.manager.ActivityManager; import org.exoplatform.social.core.manager.IdentityManager; import org.exoplatform.social.core.model.AvatarAttachment; 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.exoplatform.social.core.storage.cache.CachedActivityStorage; import org.gatein.common.logging.Logger; import org.gatein.common.logging.LoggerFactory; import org.gatein.management.api.ContentType; import org.gatein.management.api.PathAddress; import org.gatein.management.api.controller.ManagedRequest; import org.gatein.management.api.controller.ManagedResponse; import org.gatein.management.api.controller.ManagementController; import org.gatein.management.api.exceptions.OperationException; import org.gatein.management.api.operation.OperationAttachment; 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.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; /** * The Class SocialDataImportResource. * * @author <a href="mailto:bkhanfir@exoplatform.com">Boubaker Khanfir</a> * @version $Revision$ */ public class SocialDataImportResource extends AbstractImportOperationHandler implements ActivityImportOperationInterface { /** The Constant log. */ final private static Logger log = LoggerFactory.getLogger(SocialDataImportResource.class); /** The Constant MANAGED_ENTRY_PATH_PREFIX. */ final private static String MANAGED_ENTRY_PATH_PREFIX = "social/space/"; /** The organization service. */ private OrganizationService organizationService; /** The identity manager. */ private IdentityManager identityManager; /** The management controller. */ private ManagementController managementController; /** The data storage. */ private DataStorage dataStorage; /** * {@inheritDoc} */ @Override public void execute(OperationContext operationContext, ResultHandler resultHandler) throws OperationException { organizationService = operationContext.getRuntimeContext().getRuntimeComponent(OrganizationService.class); spaceService = operationContext.getRuntimeContext().getRuntimeComponent(SpaceService.class); managementController = operationContext.getRuntimeContext().getRuntimeComponent(ManagementController.class); activityManager = operationContext.getRuntimeContext().getRuntimeComponent(ActivityManager.class); identityManager = operationContext.getRuntimeContext().getRuntimeComponent(IdentityManager.class); userACL = operationContext.getRuntimeContext().getRuntimeComponent(UserACL.class); dataStorage = operationContext.getRuntimeContext().getRuntimeComponent(DataStorage.class); activityStorage = operationContext.getRuntimeContext().getRuntimeComponent(ActivityStorage.class); identityStorage = operationContext.getRuntimeContext().getRuntimeComponent(IdentityStorage.class); activitiesByPostTime.clear(); OperationAttributes attributes = operationContext.getAttributes(); List<String> filters = attributes.getValues("filter"); // "replace-existing" attribute. Defaults to false. boolean replaceExisting = filters.contains("replace-existing:true"); // "create-users" attribute. Defaults to false. boolean createAbsentUsers = filters.contains("create-users:true"); // space-name = spaceDisplayName || spacePrettyName || // spaceOriginalPrettyName (before renaming) String spaceName = operationContext.getAddress().resolvePathTemplate("space-name"); if (spaceName != null) { Space space = spaceService.getSpaceByDisplayName(spaceName); if (space == null) { space = spaceService.getSpaceByPrettyName(spaceName); if (space == null) { space = spaceService.getSpaceByGroupId(SpaceUtils.SPACE_GROUP + "/" + spaceName); } } if (space != null) { if (!replaceExisting) { log.info("Space '" + space.getDisplayName() + "' was found but replaceExisting=false. Ignore space '" + spaceName + "' import."); resultHandler.completed(NoResultModel.INSTANCE); return; } spaceName = space.getPrettyName(); } } File tmpZipFile = null; increaseCurrentTransactionTimeOut(operationContext); try { // Copy attachement to local temporary File tmpZipFile = File.createTempFile("staging-social", ".zip"); Map<String, Map<String, File>> fileToImportByOwner = extractDataFromZipAndCreateSpaces(operationContext.getAttachment(false), spaceName, replaceExisting, createAbsentUsers, tmpZipFile); Set<String> spacePrettyNames = fileToImportByOwner.keySet(); for (String extractedSpacePrettyName : spacePrettyNames) { log.info("Importing applications data for space: " + extractedSpacePrettyName + " ..."); Space space = spaceService.getSpaceByPrettyName(extractedSpacePrettyName); if (space == null) { continue; } Map<String, File> spaceFiles = fileToImportByOwner.get(extractedSpacePrettyName); Set<String> filesKeys = spaceFiles.keySet(); List<String> filesKeysList = new ArrayList<String>(filesKeys); Collections.sort(filesKeysList, new Comparator<String>() { @Override public int compare(String o1, String o2) { if (o1.contains(SocialDashboardExportTask.FILENAME)) { return 1; } if (o2.contains(SocialDashboardExportTask.FILENAME)) { return -1; } return o1.compareTo(o2); } }); List<File> activitiesFileList = new ArrayList<File>(); for (String fileKey : filesKeysList) { File fileToImport = spaceFiles.get(fileKey); if (fileKey.equals(SocialExtension.CALENDAR_RESOURCE_PATH) || fileKey.equals(SocialExtension.CONTENT_RESOURCE_PATH) || fileKey.equals(SocialExtension.FORUM_RESOURCE_PATH) || fileKey.equals(SocialExtension.WIKI_RESOURCE_PATH) || fileKey.equals(SocialExtension.SITES_IMPORT_RESOURCE_PATH)) { importSubResource(fileToImport, fileKey); deleteTempFile(fileToImport); } else { if (fileKey.contains(ActivitiesExportTask.FILENAME)) { activitiesFileList.add(fileToImport); } else if (fileToImport.getAbsolutePath().contains(SocialDashboardExportTask.FILENAME)) { updateDashboard(space.getGroupId(), fileToImport); deleteTempFile(fileToImport); } else if (fileToImport.getAbsolutePath().contains(SpaceAvatarExportTask.FILENAME)) { updateAvatar(space, fileToImport); deleteTempFile(fileToImport); } else { log.warn("Cannot handle file: " + fileToImport.getAbsolutePath() + ". Ignore it."); deleteTempFile(fileToImport); } } } log.info("Importing space '" + extractedSpacePrettyName + "' activities."); activitiesByPostTime.clear(); for (File file : activitiesFileList) { importActivities(file, extractedSpacePrettyName, false); } log.info("Import operation finished successfully for space: " + extractedSpacePrettyName); } log.info("Import operation finished successfully for all space."); } catch (IOException e) { log.warn("Cannot create temporary file.", e); } finally { restoreDefaultTransactionTimeOut(operationContext); if (tmpZipFile != null) { String tempFolderPath = tmpZipFile.getAbsolutePath().replaceAll("\\.zip$", ""); File tempFolderFile = new File(tempFolderPath); deleteTempFile(tempFolderFile); deleteTempFile(tmpZipFile); } } resultHandler.completed(NoResultModel.INSTANCE); } /** * Delete space activities. * * @param extractedSpacePrettyName the extracted space pretty name */ private void deleteSpaceActivities(String extractedSpacePrettyName) { Identity spaceIdentity = identityManager.getOrCreateIdentity(SpaceIdentityProvider.NAME, extractedSpacePrettyName, false); RealtimeListAccess<ExoSocialActivity> listAccess = activityManager.getActivitiesOfSpaceWithListAccess(spaceIdentity); // To refresh activities list from storage listAccess.getNumberOfUpgrade(); if (listAccess.getSize() > 0) { ExoSocialActivity[] activities = listAccess.load(0, listAccess.getSize()); log.info("Delete " + listAccess.getSize() + " space activities"); deleteActivities(activities); } RequestLifeCycle.end(); RequestLifeCycle.begin(PortalContainer.getInstance()); if (activityStorage instanceof CachedActivityStorage) { ((CachedActivityStorage) activityStorage).clearCache(); } } /** * Update avatar. * * @param space the space * @param fileToImport the file to import */ private void updateAvatar(Space space, File fileToImport) { log.info("Update Space avatar '" + space.getDisplayName() + "'"); FileInputStream inputStream = null; try { inputStream = new FileInputStream(fileToImport); InputStreamReader reader = new InputStreamReader(inputStream, "UTF-8"); space = spaceService.getSpaceByGroupId(space.getGroupId()); XStream xstream = new XStream(); AvatarAttachment avatarAttachment = (AvatarAttachment) xstream.fromXML(reader); space.setAvatarAttachment(avatarAttachment); fixSpaceEditor(space); space = spaceService.updateSpace(space); space = spaceService.getSpaceByGroupId(space.getGroupId()); fixSpaceEditor(space); if (space.getAvatarAttachment() == null) { space.setAvatarAttachment(avatarAttachment); } spaceService.updateSpaceAvatar(space); } catch (Exception e) { log.error("Error while updating Space '" + space.getDisplayName() + "' avatar.", e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { log.warn("Cannot close input stream: " + fileToImport.getAbsolutePath() + ". Ignore non blocking operation."); } } } } /** * Fix space editor. * * @param space the space */ private void fixSpaceEditor(Space space) { if (space.getEditor() == null) { // Fix space editor that is always null space.setEditor(space.getManagers()[0]); } } /** * Update dashboard. * * @param spaceGroupId the space group id * @param fileToImport the file to import */ private void updateDashboard(String spaceGroupId, File fileToImport) { FileInputStream inputStream = null; try { Dashboard dashboard = SocialDashboardExportTask.getDashboard(dataStorage, spaceGroupId); if (dashboard == null) { return; } inputStream = new FileInputStream(fileToImport); XStream xstream = new XStream(); Dashboard newDashboard = (Dashboard) xstream.fromXML(inputStream); dashboard.setAccessPermissions(newDashboard.getAccessPermissions()); dashboard.setChildren(newDashboard.getChildren()); dashboard.setDecorator(newDashboard.getDecorator()); dashboard.setDescription(newDashboard.getDescription()); dashboard.setFactoryId(newDashboard.getFactoryId()); dashboard.setHeight(newDashboard.getHeight()); dashboard.setIcon(newDashboard.getIcon()); dashboard.setName(newDashboard.getName()); dashboard.setTemplate(newDashboard.getTemplate()); dashboard.setTitle(newDashboard.getTitle()); dashboard.setWidth(newDashboard.getWidth()); dataStorage.saveDashboard(newDashboard); } catch (Exception e) { throw new OperationException(OperationNames.IMPORT_RESOURCE, "Error while updating Space '" + spaceGroupId + "' dashbord.", e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { log.warn("Cannot close input stream: " + fileToImport.getAbsolutePath() + ". Ignore non blocking operation."); } } } } /** * {@inheritDoc} */ public void attachActivityToEntity(ExoSocialActivity activity, ExoSocialActivity comment) throws Exception { Identity spaceIdentity = getIdentity(activity.getStreamOwner()); if (SpaceActivityPublisher.SPACE_PROFILE_ACTIVITY.equals(activity.getType()) || SpaceActivityPublisher.USER_ACTIVITIES_FOR_SPACE.equals(activity.getType())) { if (comment != null) { activity = comment; } identityStorage.updateProfileActivityId(spaceIdentity, activity.getId(), Profile.AttachedActivityType.SPACE); } } /** * {@inheritDoc} */ public boolean isActivityNotValid(ExoSocialActivity activity, ExoSocialActivity comment) throws Exception { if (comment == null) { boolean notValidActivity = activity.getActivityStream() == null || !activity.getActivityStream().getType().equals(Type.SPACE); if (notValidActivity) { log.warn("NOT Valid space activity: '" + activity.getTitle() + "'"); } return notValidActivity; } else { return false; } } /** * Creates the or replace space. * * @param spacePrettyName the space pretty name * @param targetSpaceName the target space name * @param replaceExisting the replace existing * @param createAbsentUsers the create absent users * @param inputStream the input stream * @return true, if successful * @throws Exception the exception */ private boolean createOrReplaceSpace(String spacePrettyName, String targetSpaceName, boolean replaceExisting, boolean createAbsentUsers, InputStream inputStream) throws Exception { // Unmarshall metadata xml file XStream xstream = new XStream(); xstream.alias("metadata", SpaceMetaData.class); SpaceMetaData spaceMetaData = (SpaceMetaData) xstream.fromXML(inputStream); String newSpacePrettyName = spaceMetaData.getPrettyName(); String oldSpacePrettyName = spaceMetaData.getGroupId().replace(SpaceUtils.SPACE_GROUP + "/", ""); // If selected space doesn't fit the found space, ignore it if (targetSpaceName != null && !(targetSpaceName.equals(spaceMetaData.getDisplayName()) || targetSpaceName.equals(oldSpacePrettyName) || targetSpaceName.equals(newSpacePrettyName))) { return true; } Space space = spaceService.getSpaceByGroupId(spaceMetaData.getGroupId()); if (space != null) { if (replaceExisting) { String groupId = space.getGroupId(); deleteSpaceActivities(spaceMetaData.getPrettyName()); log.info("Delete space: '" + spaceMetaData.getPrettyName() + "'."); RequestLifeCycle.begin(PortalContainer.getInstance()); try { String[] members = space.getMembers(); for (String member : members) { spaceService.removeMember(space, member); } spaceService.deleteSpace(space); } finally { RequestLifeCycle.end(); } // FIXME Workaround: deleting a space don't delete the corresponding // group RequestLifeCycle.begin(PortalContainer.getInstance()); try { Group group = organizationService.getGroupHandler().findGroupById(groupId); if (group != null) { organizationService.getGroupHandler().removeGroup(group, true); } } finally { RequestLifeCycle.end(); } } else { log.info("Space '" + space.getDisplayName() + "' was found but replaceExisting=false. Ignore space import."); return true; } } Group spaceGroup = organizationService.getGroupHandler().findGroupById(spaceMetaData.getGroupId()); if (spaceGroup != null) { RequestLifeCycle.begin(PortalContainer.getInstance()); try { organizationService.getGroupHandler().removeGroup(spaceGroup, true); } finally { RequestLifeCycle.end(); } } if (createAbsentUsers) { log.info("Create not found users of space: '" + spaceMetaData.getPrettyName() + "'."); String[] members = spaceMetaData.getMembers(); for (String member : members) { RequestLifeCycle.begin(PortalContainer.getInstance()); try { User user = organizationService.getUserHandler().findUserByName(member); if (user == null) { user = organizationService.getUserHandler().createUserInstance(member); user.setDisplayName(member); user.setFirstName(member); user.setLastName(member); user.setEmail(member + "@example.com"); user.setPassword("" + Math.random()); log.info(" Create not found user of space: '" + member + "' with random password."); try { organizationService.getUserHandler().createUser(user, true); } catch (RuntimeException e) { // The user JCR data are already in the JCR if (null == organizationService.getUserHandler().findUserByName(member)) { log.warn("Exception while creating the user '" + member + "' with broadcasting event, try without broadcast", e); organizationService.getUserHandler().createUser(user, false); } else { throw e; } } } } catch (Exception e) { log.warn("Exception while creating the user: " + member, e); } finally { RequestLifeCycle.end(); } } } log.info("Create new space: '" + spaceMetaData.getPrettyName() + "'."); space = new Space(); boolean isRenamed = !newSpacePrettyName.equals(oldSpacePrettyName); space.setPrettyName(oldSpacePrettyName); if (isRenamed) { space.setDisplayName(oldSpacePrettyName); } else { space.setDisplayName(spaceMetaData.getDisplayName()); } space.setGroupId(spaceMetaData.getGroupId()); space.setTag(spaceMetaData.getTag()); space.setApp(spaceMetaData.getApp()); // Filter on existing users String[] members = getExistingUsers(spaceMetaData.getMembers()); if (members == null || members.length == 0) { members = new String[] { userACL.getSuperUser() }; log.warn("Members of space '" + spaceMetaData.getDisplayName() + "' is empty, the super user '" + Arrays.toString(space.getMembers()) + "' will be used instead."); } String[] managers = getExistingUsers(spaceMetaData.getManagers()); if (managers == null || managers.length == 0) { managers = new String[] { userACL.getSuperUser() }; log.warn("Managers of space '" + spaceMetaData.getDisplayName() + "' is empty, the super user '" + Arrays.toString(space.getManagers()) + "' will be used instead."); } String[] editor = getExistingUsers(spaceMetaData.getEditor()); if (editor == null || editor.length == 0) { editor = new String[] { managers[0] }; } space.setEditor(editor[0]); space.setInvitedUsers(getExistingUsers(spaceMetaData.getInvitedUsers())); space.setRegistration(spaceMetaData.getRegistration()); space.setDescription(spaceMetaData.getDescription()); space.setType(spaceMetaData.getType()); space.setVisibility(spaceMetaData.getVisibility()); space.setPriority(spaceMetaData.getPriority()); space.setUrl(spaceMetaData.getUrl()); RequestLifeCycle.begin(PortalContainer.getInstance()); try { space = spaceService.createSpace(space, space.getEditor() == null ? space.getManagers()[0] : space.getEditor()); if (isRenamed) { log.info("Rename space from '" + oldSpacePrettyName + "' to '" + newSpacePrettyName + "'."); spaceService.renameSpace(space, spaceMetaData.getDisplayName().trim()); space = spaceService.getSpaceByDisplayName(spaceMetaData.getDisplayName()); } if (space == null) { throw new IllegalStateException("Space '" + spaceMetaData.getDisplayName() + "' was not found after creating it."); } } finally { RequestLifeCycle.end(); } // FIXME Workaround, after replacing space, it still using flag // deleted=false RequestLifeCycle.begin(PortalContainer.getInstance()); try { Identity identity = null; int countIerations = 0; // Wait until the identity of the space is committed do { identity = getIdentity(space.getPrettyName()); if (identity == null) { log.warn("Identity of space '" + spaceMetaData.getPrettyName() + "' not found, retry getting it."); Thread.sleep(2000); countIerations++; } } while (identity == null && countIerations < 5); if (identity == null) { throw new OperationException(OperationNames.IMPORT_RESOURCE, "Identity of space with pretty name '" + spaceMetaData.getPrettyName() + "' was not found. Cannot continue importing the space."); } if (identity.isDeleted()) { log.info("Set space identity not deleted, it was deleted=" + spaceMetaData.getPrettyName() + "'."); identity.setDeleted(false); identityStorage.saveIdentity(identity); } } finally { RequestLifeCycle.end(); } RequestLifeCycle.begin(PortalContainer.getInstance()); try { log.info("Add members to space: '" + spaceMetaData.getPrettyName() + "'."); space.setEditor(managers[0]); space.setMembers(members); space = spaceService.updateSpace(space); for (String member : members) { try { SpaceUtils.addUserToGroupWithMemberMembership(member, space.getGroupId()); log.info(" User '" + member + "' added to space as member: '" + spaceMetaData.getPrettyName() + "'."); } catch (Exception e) { log.warn(" Cannot add member '" + member + "' to space: " + space.getPrettyName(), e); } } } finally { RequestLifeCycle.end(); } RequestLifeCycle.begin(PortalContainer.getInstance()); try { log.info("Set manager(s) of space: '" + spaceMetaData.getPrettyName() + "'."); space.setEditor(managers[0]); space.setManagers(managers); space = spaceService.updateSpace(space); for (String manager : managers) { try { log.info(" User '" + manager + "' promoted to manager of space: '" + spaceMetaData.getPrettyName() + "'."); SpaceUtils.addUserToGroupWithManagerMembership(manager, space.getGroupId()); } catch (Exception e) { log.warn(" Cannot add manager '" + manager + "' to space: " + space.getPrettyName(), e); } } } finally { RequestLifeCycle.end(); } deleteSpaceActivities(spaceMetaData.getPrettyName()); return false; } /** * Gets the existing users. * * @param users the users * @return the existing users */ private String[] getExistingUsers(String... users) { Set<String> existingUsers = new HashSet<String>(); if (users != null && users.length > 0) { for (String userId : users) { if (userId == null || userId.isEmpty()) { continue; } try { User user = organizationService.getUserHandler().findUserByName(userId); if (user != null) { existingUsers.add(userId); } else { log.info(" User '" + userId + "' doesn't exist, the user will not be added as member or manager of the space."); } } catch (Exception e) { log.warn("Exception while attempting to get user: " + userId, e); } } } return existingUsers.toArray(EMPTY_STRING_ARRAY); } /** * Import sub resource. * * @param tempFile the temp file * @param subResourcePath the sub resource path */ private void importSubResource(File tempFile, String subResourcePath) { Map<String, List<String>> attributesMap = new HashMap<String, List<String>>(); attributesMap.put("filter", Collections.singletonList("replace-existing:true")); attributesMap.put("importMode", Collections.singletonList(ImportMode.OVERWRITE.name())); // This will be closed in sub resources, don't close it here InputStream inputStream = null; try { inputStream = new FileInputStream(tempFile); ManagedRequest request = ManagedRequest.Factory.create(OperationNames.IMPORT_RESOURCE, PathAddress.pathAddress(subResourcePath), attributesMap, inputStream, ContentType.ZIP); ManagedResponse response = managementController.execute(request); Object model = response.getResult(); if (!(model instanceof NoResultModel)) { throw new OperationException(OperationNames.IMPORT_RESOURCE, "Unknown error while importing to path: " + subResourcePath); } } catch (FileNotFoundException e) { throw new OperationException(OperationNames.IMPORT_RESOURCE, "Cannot find extracted file: " + (tempFile != null ? tempFile.getAbsolutePath() : tempFile), e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { log.warn("Cannot close input stream: " + tempFile + ". Ignore non blocking operation."); } } } } /** * Extract data from zip and create spaces. * * @param attachment the attachment * @param spaceName the space name * @param replaceExisting the replace existing * @param createAbsentUsers the create absent users * @param tmpZipFile the tmp zip file * @return the map * @throws OperationException the operation exception */ private Map<String, Map<String, File>> extractDataFromZipAndCreateSpaces(OperationAttachment attachment, String spaceName, boolean replaceExisting, boolean createAbsentUsers, File tmpZipFile) throws OperationException { if (attachment == null || attachment.getStream() == null) { throw new OperationException(OperationNames.IMPORT_RESOURCE, "No attachment available for Social import."); } InputStream inputStream = attachment.getStream(); try { copyAttachementToLocalFolder(inputStream, tmpZipFile); // Organize File paths by id and extract files from zip to a temp // folder and create spaces return extractFilesByIdAndCreateSpaces(tmpZipFile, spaceName, replaceExisting, createAbsentUsers); } catch (Exception e) { throw new OperationException(OperationNames.IMPORT_RESOURCE, "Error occured while handling attachement", e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { log.warn("Cannot close input stream."); } } } } /** * Extract files by id and create spaces. * * @param tmpZipFile the tmp zip file * @param targetSpaceName the target space name * @param replaceExisting the replace existing * @param createAbsentUsers the create absent users * @return the map * @throws Exception the exception */ private Map<String, Map<String, File>> extractFilesByIdAndCreateSpaces(File tmpZipFile, String targetSpaceName, boolean replaceExisting, boolean createAbsentUsers) throws Exception { // Get path of folder where to unzip files String targetFolderPath = tmpZipFile.getAbsolutePath().replaceAll("\\.zip$", "") + "/"; // Open an input stream on local zip file NonCloseableZipInputStream zis = new NonCloseableZipInputStream(new FileInputStream(tmpZipFile)); Map<String, Map<String, File>> filesToImportByOwner = new HashMap<String, Map<String, File>>(); List<String> ignoredSpaces = new ArrayList<String>(); try { Map<String, ZipOutputStream> zipOutputStreamMap = new HashMap<String, ZipOutputStream>(); ZipEntry entry; while ((entry = zis.getNextEntry()) != null) { try { String zipEntryPath = entry.getName(); // Skip entries not managed by this extension if (!zipEntryPath.startsWith(MANAGED_ENTRY_PATH_PREFIX)) { continue; } // Skip directories if (entry.isDirectory()) { // Create directory in unzipped folder location createFile(new File(targetFolderPath + replaceSpecialChars(zipEntryPath)), true); continue; } int idBeginIndex = MANAGED_ENTRY_PATH_PREFIX.length(); String spacePrettyName = zipEntryPath.substring(idBeginIndex, zipEntryPath.indexOf("/", idBeginIndex)); if (ignoredSpaces.contains(spacePrettyName)) { continue; } if (!filesToImportByOwner.containsKey(spacePrettyName)) { filesToImportByOwner.put(spacePrettyName, new HashMap<String, File>()); } Map<String, File> ownerFiles = filesToImportByOwner.get(spacePrettyName); log.info("Receiving content " + zipEntryPath); if (zipEntryPath.contains(SocialExtension.CALENDAR_RESOURCE_PATH)) { putSubResourceEntry(tmpZipFile, targetFolderPath, zis, zipOutputStreamMap, zipEntryPath, spacePrettyName, ownerFiles, SocialExtension.CALENDAR_RESOURCE_PATH); } else if (zipEntryPath.contains(SocialExtension.CONTENT_RESOURCE_PATH)) { putSubResourceEntry(tmpZipFile, targetFolderPath, zis, zipOutputStreamMap, zipEntryPath, spacePrettyName, ownerFiles, SocialExtension.CONTENT_RESOURCE_PATH); } else if (zipEntryPath.contains(SocialExtension.FORUM_RESOURCE_PATH)) { putSubResourceEntry(tmpZipFile, targetFolderPath, zis, zipOutputStreamMap, zipEntryPath, spacePrettyName, ownerFiles, SocialExtension.FORUM_RESOURCE_PATH); } else if (zipEntryPath.contains(SocialExtension.WIKI_RESOURCE_PATH)) { putSubResourceEntry(tmpZipFile, targetFolderPath, zis, zipOutputStreamMap, zipEntryPath, spacePrettyName, ownerFiles, SocialExtension.WIKI_RESOURCE_PATH); } else if (zipEntryPath.contains(SocialExtension.GROUP_SITE_RESOURCE_PATH)) { putSubResourceEntry(tmpZipFile, targetFolderPath, zis, zipOutputStreamMap, zipEntryPath, spacePrettyName, ownerFiles, SocialExtension.SITES_IMPORT_RESOURCE_PATH); } else { String localFilePath = targetFolderPath + replaceSpecialChars(zipEntryPath); if (localFilePath.endsWith(SpaceMetadataExportTask.FILENAME)) { // Create space here to be sure that it's created before importing // other application resources boolean toIgnore = createOrReplaceSpace(spacePrettyName, targetSpaceName, replaceExisting, createAbsentUsers, zis); if (toIgnore) { ignoredSpaces.add(spacePrettyName); filesToImportByOwner.remove(spacePrettyName); } } else { ownerFiles.put(zipEntryPath, new File(localFilePath)); // Put file Export file in temp folder copyToDisk(zis, localFilePath); } } } finally { zis.closeEntry(); } } Collection<ZipOutputStream> zipOutputStreams = zipOutputStreamMap.values(); for (ZipOutputStream zipOutputStream : zipOutputStreams) { zipOutputStream.close(); } } finally { try { zis.reallyClose(); } catch (Exception e) { log.warn("Cannot delete temporary file " + tmpZipFile + ". Ignore it."); } } return filesToImportByOwner; } /** * Put sub resource entry. * * @param tmpZipFile the tmp zip file * @param targetFolderPath the target folder path * @param zis the zis * @param zipOutputStreamMap the zip output stream map * @param zipEntryPath the zip entry path * @param spacePrettyName the space pretty name * @param ownerFiles the owner files * @param subResourcePath the sub resource path * @throws Exception the exception */ private void putSubResourceEntry(File tmpZipFile, String targetFolderPath, NonCloseableZipInputStream zis, Map<String, ZipOutputStream> zipOutputStreamMap, String zipEntryPath, String spacePrettyName, Map<String, File> ownerFiles, String subResourcePath) throws Exception { if (!ownerFiles.containsKey(subResourcePath)) { createFile(new File(targetFolderPath + "social/space/" + spacePrettyName + subResourcePath), true); String zipFilePath = targetFolderPath + "social/space/" + spacePrettyName + subResourcePath + ".zip"; ownerFiles.put(subResourcePath, new File(zipFilePath)); ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFilePath)); zipOutputStreamMap.put(spacePrettyName + subResourcePath, zos); } ZipOutputStream zos = zipOutputStreamMap.get(spacePrettyName + subResourcePath); String subResourceZipEntryPath = zipEntryPath.replace("social/space/" + spacePrettyName + "/", ""); zos.putNextEntry(new ZipEntry(subResourceZipEntryPath)); IOUtils.copy(zis, zos); zos.closeEntry(); } }