/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco * * Alfresco 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 3 of the License, or * (at your option) any later version. * * Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>. */ package fr.itldev.koya.action; import java.io.File; import java.io.IOException; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashSet; import java.util.List; import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.action.ParameterDefinitionImpl; import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ParameterDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.util.TempFileProvider; import org.apache.log4j.Logger; import fr.itldev.koya.alfservice.DossierService; import fr.itldev.koya.alfservice.KoyaContentService; import fr.itldev.koya.alfservice.KoyaNodeService; import fr.itldev.koya.exception.KoyaServiceException; import fr.itldev.koya.model.impl.Directory; import fr.itldev.koya.model.impl.Dossier; import fr.itldev.koya.utils.Zips; public class UnzipActionExecuter extends ActionExecuterAbstractBase { Logger logger = Logger.getLogger(UnzipActionExecuter.class); public static final String NAME = "koyaUnzip"; public static final String PARAM_ENCODING = "encoding"; public static final String PARAM_DESTINATION_FOLDER = "destination"; private static final String TEMP_FILE_PREFIX = "koya"; private static final String TEMP_FILE_SUFFIX_ZIP = ".zip"; private NodeService nodeService; private ContentService contentService; private NamespaceService namespaceService; private BehaviourFilter policyBehaviourFilter; private KoyaNodeService koyaNodeService; private KoyaContentService koyaContentService; private DossierService dossierService; private String defaultZipCharset; private String failoverZipCharset; public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; } public void setContentService(ContentService contentService) { this.contentService = contentService; } public void setNamespaceService(NamespaceService namespaceService) { this.namespaceService = namespaceService; } public void setPolicyBehaviourFilter(BehaviourFilter policyBehaviourFilter) { this.policyBehaviourFilter = policyBehaviourFilter; } public void setKoyaNodeService(KoyaNodeService koyaNodeService) { this.koyaNodeService = koyaNodeService; } public void setKoyaContentService(KoyaContentService koyaContentService) { this.koyaContentService = koyaContentService; } public void setDossierService(DossierService dossierService) { this.dossierService = dossierService; } public void setDefaultZipCharset(String defaultZipCharset) { this.defaultZipCharset = defaultZipCharset; } public void setFailoverZipCharset(String failoverZipCharset) { this.failoverZipCharset = failoverZipCharset; } /** * @see org.alfresco.repo.action.executer.ActionExecuter#execute(org.alfresco.repo.ref.NodeRef, * org.alfresco.repo.ref.NodeRef) */ @Override public void executeImpl(Action ruleAction, NodeRef actionedUponNodeRef) { if (this.nodeService.exists(actionedUponNodeRef) == true) { // The node being passed in should be an Alfresco content package ContentReader reader = this.contentService.getReader( actionedUponNodeRef, ContentModel.PROP_CONTENT); if (reader != null) { // Disabled policy on ASPECT_AUDITABLE // (LastModificationDateBehaviour) policyBehaviourFilter .disableBehaviour(ContentModel.ASPECT_AUDITABLE); // String zipName = (String) nodeService.getProperty( // actionedUponNodeRef, ContentModel.PROP_NAME); StringBuffer sbLog = new StringBuffer(); File tempFile = null; File tempDir = null; try { tempFile = TempFileProvider.createTempFile( TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX_ZIP); reader.getContent(tempFile); // build a temp dir name based on the ID of the noderef we // are importing // also use the long life temp folder as large ZIP files can // take a while File alfTempDir = TempFileProvider .getLongLifeTempDir("unzip"); tempDir = new File(alfTempDir.getPath() + File.separatorChar + actionedUponNodeRef.getId()); logger.debug("Unzip : " + nodeService.getPath(actionedUponNodeRef) .toPrefixString(namespaceService) + " as " + tempFile.getAbsolutePath()); if (Zips.unzip(tempFile.getAbsolutePath(), tempDir.getAbsolutePath(), defaultZipCharset, failoverZipCharset, sbLog)) { NodeRef importDest = (NodeRef) ruleAction .getParameterValue(PARAM_DESTINATION_FOLDER); importDirectory(tempDir.getPath(), importDest, sbLog); logger.debug("Unzip Complete : " + nodeService.getPath(actionedUponNodeRef) .toPrefixString(namespaceService)); } } catch (KoyaServiceException kse) { throw kse; } catch (ContentIOException ex) { throw new AlfrescoRuntimeException( "Failed to import ZIP file. " + ex.getMessage(), ex); } finally { // FileInfo logInfo = fileFolderService.create( // nodeService.getPrimaryParent(actionedUponNodeRef) // .getParentRef(), // nodeService.getProperty(actionedUponNodeRef, // ContentModel.PROP_NAME) + ".log", // ContentModel.TYPE_CONTENT); // ContentWriter logWriter = fileFolderService // .getWriter(logInfo.getNodeRef()); // // logWriter.putContent(sbLog.toString()); // now the import is done, delete the temporary file if (tempDir != null) { deleteDir(tempDir); } if (tempFile != null) { tempFile.delete(); } } } try { // Update the modification date on the parent dossier Dossier d = koyaNodeService.getFirstParentOfType(actionedUponNodeRef, Dossier.class); nodeService.deleteNode(actionedUponNodeRef); dossierService.updateLastModificationDate(d); } catch (Exception ex) { throw new AlfrescoRuntimeException(ex.getMessage(), ex); } } } /** * Recursively import a directory structure into the specified root node * * @param dir * The directory of files and folders to import * @param root * The root node to import into */ private void importDirectory(String directory, NodeRef root, StringBuffer sbLog) { // Path topdir = Paths.get(dir); String currentPath = ""; Set<String> filenames = new HashSet<>(); try (DirectoryStream<Path> directoryStream = Files .newDirectoryStream(Paths.get(directory))) { for (Path path : directoryStream) { String fileName = path.getFileName().toString(); String uniqueFileName = fileName; currentPath = path.toString(); logger.trace("nex :" + fileName); if (Files.isRegularFile(path)) { int i = 1; int dotIdx = fileName.lastIndexOf("."); final String name = (dotIdx != -1) ? fileName.substring(0, dotIdx) : fileName; final String ext = (dotIdx != -1) ? fileName .substring(dotIdx) : ""; while (filenames.contains(uniqueFileName.toLowerCase())) { uniqueFileName = name + " (" + (++i) + ")" + ext; } sbLog.append("\nImporting " + fileName); if (!uniqueFileName.equals(fileName)) { sbLog.append("\nRenaming " + fileName + " to " + uniqueFileName + " due to duplicate filename in zip archive for path " + path); } koyaContentService.createContentNode(root, uniqueFileName, Files.newInputStream(path)); } else { int i = 0; while (filenames.contains(uniqueFileName.toLowerCase())) { uniqueFileName = fileName + "-" + i; i++; } // create a folder node sbLog.append("\nDirectory " + uniqueFileName); Directory d = koyaContentService.createDir(uniqueFileName, root); // logger.debug(file.getPath()); logger.trace(path); // recurcive call to import folder contents importDirectory(path.toString(), d.getNodeRef(), sbLog); } filenames.add(uniqueFileName.toLowerCase()); } } catch (IOException ex) { sbLog.append("\nImport IOException on " + currentPath + " : " + ex.getMessage()); logger.error( "Import IOException on " + currentPath + " : " + ex.toString(), ex); } } @Override protected void addParameterDefinitions(List<ParameterDefinition> paramList) { paramList.add(new ParameterDefinitionImpl(PARAM_DESTINATION_FOLDER, DataTypeDefinition.NODE_REF, true, getParamDisplayLabel(PARAM_DESTINATION_FOLDER))); } /** * Recursively delete a dir of files and directories * * @param dir * directory to delete */ private static void deleteDir(File dir) { if (dir != null) { File elenco = new File(dir.getPath()); // listFiles can return null if the path is invalid i.e. already // been deleted, // therefore check for null before using in loop File[] files = elenco.listFiles(); if (files != null) { for (File file : files) { if (file.isFile()) { file.delete(); } else { deleteDir(file); } } } // delete provided directory dir.delete(); } } }