diff --git a/config/alfresco/action-services-context.xml b/config/alfresco/action-services-context.xml
index 349ff953ab..6a55930f53 100644
--- a/config/alfresco/action-services-context.xml
+++ b/config/alfresco/action-services-context.xml
@@ -230,15 +230,15 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -300,9 +300,9 @@
${mail.header}
-
- ${mail.from.default}
-
+
+ ${mail.from.default}
+
@@ -344,6 +344,12 @@
+
+
+
+
+
+
@@ -482,22 +488,22 @@
false
-
-
-
-
-
-
-
-
-
-
-
-
-
- false
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
diff --git a/config/alfresco/mimetype/mimetype-map.xml b/config/alfresco/mimetype/mimetype-map.xml
index 8b25d1972e..9e4926bac2 100644
--- a/config/alfresco/mimetype/mimetype-map.xml
+++ b/config/alfresco/mimetype/mimetype-map.xml
@@ -292,7 +292,10 @@
z
- zip
+ zip
+ war
+ jar
+ ear
dwg
diff --git a/source/java/org/alfresco/repo/action/executer/ImporterActionExecuter.java b/source/java/org/alfresco/repo/action/executer/ImporterActionExecuter.java
index cdcb3445b3..ac3032f8e9 100644
--- a/source/java/org/alfresco/repo/action/executer/ImporterActionExecuter.java
+++ b/source/java/org/alfresco/repo/action/executer/ImporterActionExecuter.java
@@ -24,9 +24,24 @@
*/
package org.alfresco.repo.action.executer;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
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.OutputStream;
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.zip.ZipException;
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.model.ApplicationModel;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.ParameterDefinitionImpl;
import org.alfresco.repo.content.MimetypeMap;
@@ -34,13 +49,21 @@ import org.alfresco.repo.importer.ACPImportPackageHandler;
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.model.FileExistsException;
+import org.alfresco.service.cmr.model.FileFolderService;
+import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
+import org.alfresco.service.cmr.repository.ContentWriter;
+import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.view.ImporterService;
import org.alfresco.service.cmr.view.Location;
+import org.alfresco.service.namespace.QName;
import org.alfresco.util.TempFileProvider;
+import org.apache.tools.zip.ZipEntry;
+import org.apache.tools.zip.ZipFile;
/**
* Importer action executor
@@ -53,8 +76,10 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
public static final String PARAM_ENCODING = "encoding";
public static final String PARAM_DESTINATION_FOLDER = "destination";
+ private static final int BUFFER_SIZE = 16384;
private static final String TEMP_FILE_PREFIX = "alf";
- private static final String TEMP_FILE_SUFFIX = ".acp";
+ private static final String TEMP_FILE_SUFFIX_ACP = ".acp";
+ private static final String TEMP_FILE_SUFFIX_ZIP = ".zip";
/**
* The importer service
@@ -71,6 +96,16 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
*/
private ContentService contentService;
+ /**
+ * The mimetype service
+ */
+ private MimetypeService mimetypeService;
+
+ /**
+ * The file folder service
+ */
+ private FileFolderService fileFolderService;
+
/**
* Sets the ImporterService to use
*
@@ -100,6 +135,26 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
{
this.contentService = contentService;
}
+
+ /**
+ * Sets the MimetypeService to use
+ *
+ * @param mimetypeService The MimetypeService
+ */
+ public void setMimetypeService(MimetypeService mimetypeService)
+ {
+ this.mimetypeService = mimetypeService;
+ }
+
+ /**
+ * Sets the FileFolderService to use
+ *
+ * @param fileFolderService The FileFolderService
+ */
+ public void setFileFolderService(FileFolderService fileFolderService)
+ {
+ this.fileFolderService = fileFolderService;
+ }
/**
* @see org.alfresco.repo.action.executer.ActionExecuter#execute(org.alfresco.repo.ref.NodeRef, org.alfresco.repo.ref.NodeRef)
@@ -112,19 +167,20 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
ContentReader reader = this.contentService.getReader(actionedUponNodeRef, ContentModel.PROP_CONTENT);
if (reader != null)
{
+ NodeRef importDest = (NodeRef)ruleAction.getParameterValue(PARAM_DESTINATION_FOLDER);
if (MimetypeMap.MIMETYPE_ACP.equals(reader.getMimetype()))
{
+ // perform an import of an Alfresco ACP file (special format ZIP structure)
File zipFile = null;
try
{
// unfortunately a ZIP file can not be read directly from an input stream so we have to create
// a temporary file first
- zipFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX);
+ zipFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX_ACP);
reader.getContent(zipFile);
-
+
ACPImportPackageHandler importHandler = new ACPImportPackageHandler(zipFile,
(String)ruleAction.getParameterValue(PARAM_ENCODING));
- NodeRef importDest = (NodeRef)ruleAction.getParameterValue(PARAM_DESTINATION_FOLDER);
this.importerService.importView(importHandler, new Location(importDest), null, null);
}
@@ -137,10 +193,108 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
}
}
}
+ else if (MimetypeMap.MIMETYPE_ZIP.equals(reader.getMimetype()))
+ {
+ // perform an import of a standard ZIP file
+ ZipFile zipFile = null;
+ File tempFile = null;
+ try
+ {
+ tempFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX_ACP);
+ reader.getContent(tempFile);
+ // NOTE: This encoding allows us to workaround bug:
+ // http://bugs.sun.com/bugdatabase/view_bug.do;:WuuT?bug_id=4820807
+ zipFile = new ZipFile(tempFile, "Cp437");
+
+ // build a temp dir name based on the ID of the noderef we are importing
+ File alfTempDir = TempFileProvider.getTempDir();
+ File tempDir = new File(alfTempDir.getPath() + File.separatorChar + actionedUponNodeRef.getId());
+ try
+ {
+ // TODO: improve this code to directly pipe the zip stream output into the repo objects -
+ // to remove the need to expand to the filesystem first?
+ extractFile(zipFile, tempDir.getPath());
+ importDirectory(tempDir.getPath(), importDest);
+ }
+ finally
+ {
+ deleteDir(tempDir);
+ }
+ }
+ catch (IOException ioErr)
+ {
+ throw new AlfrescoRuntimeException("Failed to import ZIP file.", ioErr);
+ }
+ finally
+ {
+ // now the import is done, delete the temporary file
+ if (tempFile != null)
+ {
+ tempFile.delete();
+ }
+ }
+ }
}
}
}
+ /**
+ * 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 dir, NodeRef root)
+ {
+ File topdir = new File(dir);
+ for (File file : topdir.listFiles())
+ {
+ try
+ {
+ if (file.isFile())
+ {
+ String fileName = file.getName();
+
+ // create content node based on the file name
+ FileInfo fileInfo = this.fileFolderService.create(root, fileName, ContentModel.TYPE_CONTENT);
+ NodeRef fileRef = fileInfo.getNodeRef();
+
+ // add titled aspect for the read/edit properties screens
+ Map titledProps = new HashMap(1, 1.0f);
+ titledProps.put(ContentModel.PROP_TITLE, fileName);
+ this.nodeService.addAspect(fileRef, ContentModel.ASPECT_TITLED, titledProps);
+
+ // push the content of the file into the node
+ InputStream contentStream = new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE);
+ ContentWriter writer = this.contentService.getWriter(fileRef, ContentModel.PROP_CONTENT, true);
+ writer.setMimetype(this.mimetypeService.guessMimetype(fileName));
+ writer.putContent(contentStream);
+ }
+ else
+ {
+ // create a folder based on the folder name
+ FileInfo folderInfo = this.fileFolderService.create(root, file.getName(), ContentModel.TYPE_FOLDER);
+ NodeRef folderRef = folderInfo.getNodeRef();
+
+ // add the uifacets aspect for the read/edit properties screens
+ this.nodeService.addAspect(folderRef, ApplicationModel.ASPECT_UIFACETS, null);
+
+ importDirectory(file.getPath(), folderRef);
+ }
+ }
+ catch (FileNotFoundException e)
+ {
+ // TODO: add failed file info to status message?
+ throw new AlfrescoRuntimeException("Failed to process ZIP file.", e);
+ }
+ catch (FileExistsException e)
+ {
+ // TODO: add failed file info to status message?
+ throw new AlfrescoRuntimeException("Failed to process ZIP file.", e);
+ }
+ }
+ }
+
/**
* @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List)
*/
@@ -151,5 +305,80 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
paramList.add(new ParameterDefinitionImpl(PARAM_ENCODING, DataTypeDefinition.TEXT,
true, getParamDisplayLabel(PARAM_ENCODING)));
}
+
+ /**
+ * Extract the file and folder structure of a ZIP file into the specified directory
+ *
+ * @param archive The ZIP archive to extract
+ * @param extractDir The directory to extract into
+ */
+ public static void extractFile(ZipFile archive, String extractDir)
+ {
+ String fileName;
+ String destFileName;
+ byte[] buffer = new byte[BUFFER_SIZE];
+ extractDir = extractDir + File.separator;
+ try
+ {
+ for (Enumeration e = archive.getEntries(); e.hasMoreElements();)
+ {
+ ZipEntry entry = (ZipEntry) e.nextElement();
+ if (!entry.isDirectory())
+ {
+ fileName = entry.getName();
+ fileName = fileName.replace('/', File.separatorChar);
+ destFileName = extractDir + fileName;
+ File destFile = new File(destFileName);
+ String parent = destFile.getParent();
+ if (parent != null)
+ {
+ File parentFile = new File(parent);
+ if (!parentFile.exists()) parentFile.mkdirs();
+ }
+ InputStream in = new BufferedInputStream(archive.getInputStream(entry), BUFFER_SIZE);
+ OutputStream out = new BufferedOutputStream(new FileOutputStream(destFileName), BUFFER_SIZE);
+ int count;
+ while ((count = in.read(buffer)) != -1)
+ {
+ out.write(buffer, 0, count);
+ }
+ in.close();
+ out.close();
+ }
+ else
+ {
+ File newdir = new File(extractDir + entry.getName());
+ newdir.mkdir();
+ }
+ }
+ }
+ catch (ZipException e)
+ {
+ throw new AlfrescoRuntimeException("Failed to process ZIP file.", e);
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new AlfrescoRuntimeException("Failed to process ZIP file.", e);
+ }
+ catch (IOException e)
+ {
+ throw new AlfrescoRuntimeException("Failed to process ZIP file.", e);
+ }
+ }
+ /**
+ * Recursively delete a dir of files and directories
+ *
+ * @param dir directory to delete
+ */
+ public static void deleteDir(File dir)
+ {
+ File elenco = new File(dir.getPath());
+ for (File file : elenco.listFiles())
+ {
+ if (file.isFile()) file.delete();
+ else deleteDir(file);
+ }
+ dir.delete();
+ }
}
diff --git a/source/java/org/alfresco/repo/template/BasePathResultsMap.java b/source/java/org/alfresco/repo/template/BasePathResultsMap.java
index ada739ce32..2ec47f1f8c 100644
--- a/source/java/org/alfresco/repo/template/BasePathResultsMap.java
+++ b/source/java/org/alfresco/repo/template/BasePathResultsMap.java
@@ -70,7 +70,18 @@ public abstract class BasePathResultsMap extends BaseTemplateMap
if (xpath.length() != 0)
{
if (logger.isDebugEnabled())
- logger.debug("Executing xpath: " + xpath);
+ {
+ String out = "Executing xpath: " + xpath;
+ if (params != null)
+ {
+ out += " with params:";
+ for (QueryParameterDefinition p : params)
+ {
+ out += " " + p.getDefault();
+ }
+ }
+ logger.debug(out);
+ }
List nodes = this.services.getSearchService().selectNodes(
this.parent.getNodeRef(),