The Import dialog now allows ZIP file structure import into the repo from the web-client by any user with Write access to a folder - this is nice quick way for any user to import bulk data without using an FTP client or CIFS folder access.

Import action moved to top-level in the main browse screen now it is useful on a day-to-day basis.
The 'import' repository action (ImporterActionExecuter) extended to support import of any zip flavour file.
More zip flavour filetypes added to mimetype map.
Improved debugging output added to BasePathResultsMap for xpaths executed in templates.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5760 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2007-05-23 12:25:04 +00:00
parent ec07d35a23
commit a55a186705
4 changed files with 283 additions and 34 deletions

View File

@@ -344,6 +344,12 @@
<property name="contentService"> <property name="contentService">
<ref bean="ContentService" /> <ref bean="ContentService" />
</property> </property>
<property name="mimetypeService">
<ref bean="mimetypeService"/>
</property>
<property name="fileFolderService">
<ref bean="FileFolderService"/>
</property>
</bean> </bean>
<bean id="export" class="org.alfresco.repo.action.executer.ExporterActionExecuter" parent="action-executer"> <bean id="export" class="org.alfresco.repo.action.executer.ExporterActionExecuter" parent="action-executer">

View File

@@ -292,7 +292,10 @@
<extension>z</extension> <extension>z</extension>
</mimetype> </mimetype>
<mimetype mimetype="application/zip" display="ZIP"> <mimetype mimetype="application/zip" display="ZIP">
<extension>zip</extension> <extension display="ZIP" default="true">zip</extension>
<extension display="WAR">war</extension>
<extension display="JAR">jar</extension>
<extension display="EAR">ear</extension>
</mimetype> </mimetype>
<mimetype mimetype="image/x-dwg" display="AutoCAD Drawing"> <mimetype mimetype="image/x-dwg" display="AutoCAD Drawing">
<extension>dwg</extension> <extension>dwg</extension>

View File

@@ -24,9 +24,24 @@
*/ */
package org.alfresco.repo.action.executer; package org.alfresco.repo.action.executer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File; 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.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.model.ContentModel;
import org.alfresco.repo.action.ParameterDefinitionImpl; import org.alfresco.repo.action.ParameterDefinitionImpl;
import org.alfresco.repo.content.MimetypeMap; 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.Action;
import org.alfresco.service.cmr.action.ParameterDefinition; import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition; 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.ContentReader;
import org.alfresco.service.cmr.repository.ContentService; 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.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.view.ImporterService; import org.alfresco.service.cmr.view.ImporterService;
import org.alfresco.service.cmr.view.Location; import org.alfresco.service.cmr.view.Location;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.TempFileProvider; import org.alfresco.util.TempFileProvider;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
/** /**
* Importer action executor * Importer action executor
@@ -53,8 +76,10 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
public static final String PARAM_ENCODING = "encoding"; public static final String PARAM_ENCODING = "encoding";
public static final String PARAM_DESTINATION_FOLDER = "destination"; 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_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 * The importer service
@@ -71,6 +96,16 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
*/ */
private ContentService contentService; private ContentService contentService;
/**
* The mimetype service
*/
private MimetypeService mimetypeService;
/**
* The file folder service
*/
private FileFolderService fileFolderService;
/** /**
* Sets the ImporterService to use * Sets the ImporterService to use
* *
@@ -101,6 +136,26 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
this.contentService = contentService; 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) * @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); ContentReader reader = this.contentService.getReader(actionedUponNodeRef, ContentModel.PROP_CONTENT);
if (reader != null) if (reader != null)
{ {
NodeRef importDest = (NodeRef)ruleAction.getParameterValue(PARAM_DESTINATION_FOLDER);
if (MimetypeMap.MIMETYPE_ACP.equals(reader.getMimetype())) if (MimetypeMap.MIMETYPE_ACP.equals(reader.getMimetype()))
{ {
// perform an import of an Alfresco ACP file (special format ZIP structure)
File zipFile = null; File zipFile = null;
try try
{ {
// unfortunately a ZIP file can not be read directly from an input stream so we have to create // unfortunately a ZIP file can not be read directly from an input stream so we have to create
// a temporary file first // 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); reader.getContent(zipFile);
ACPImportPackageHandler importHandler = new ACPImportPackageHandler(zipFile, ACPImportPackageHandler importHandler = new ACPImportPackageHandler(zipFile,
(String)ruleAction.getParameterValue(PARAM_ENCODING)); (String)ruleAction.getParameterValue(PARAM_ENCODING));
NodeRef importDest = (NodeRef)ruleAction.getParameterValue(PARAM_DESTINATION_FOLDER);
this.importerService.importView(importHandler, new Location(importDest), null, null); 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<QName, Serializable> titledProps = new HashMap<QName, Serializable>(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) * @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List)
*/ */
@@ -152,4 +306,79 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
true, getParamDisplayLabel(PARAM_ENCODING))); 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();
}
} }

View File

@@ -70,7 +70,18 @@ public abstract class BasePathResultsMap extends BaseTemplateMap
if (xpath.length() != 0) if (xpath.length() != 0)
{ {
if (logger.isDebugEnabled()) 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<NodeRef> nodes = this.services.getSearchService().selectNodes( List<NodeRef> nodes = this.services.getSearchService().selectNodes(
this.parent.getNodeRef(), this.parent.getNodeRef(),