Download as Zip folder with custom folder type

509 views Asked by At

When I download folders as zip which type is not cm:folder I get empty zip archive. For folders with cm:content type and for documents it works properly.

More details:

In our project we have created a custom folder type which parent's type is cm:folder:

<type name="ef:folder">
  <title>Parent of all folders</title>
  <parent>cm:folder</parent>
  <mandatory-aspects>
    <aspect>ef:typed</aspect>
  </mandatory-aspects>
</type>

The problem is that when I press Download as Zip button for selected folder(s) I get empty zip file. It comes from startNode method of ZipDownloadExporter.java:

@Override
public void startNode(NodeRef nodeRef)
{
  this.currentName = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
  path.push(new Pair<String, NodeRef>(currentName, nodeRef));
  if (ContentModel.TYPE_FOLDER.equals(nodeService.getType(nodeRef)))
  {
    String path = getPath() + PATH_SEPARATOR;
    ZipArchiveEntry archiveEntry = new ZipArchiveEntry(path);
    try
    {
      zipStream.putArchiveEntry(archiveEntry);
      zipStream.closeArchiveEntry();
    }
    catch (IOException e)
    {
      throw new ExporterException("Unexpected IOException adding folder entry", e);
    }
  }
}

Since custom folder has type ef:folder this check returns false:

if (ContentModel.TYPE_FOLDER.equals(nodeService.getType(nodeRef)))

and folder is not added to the zip.

Is it a bug (maybe proper solution would be to check not only node's type but also parent type)?

How it could be fixed without creating custom exporter for custom folder types?

Due to project restriction type of folder couldn't be changed to cm:folder.

1

There are 1 answers

0
Stefan De Laet On BEST ANSWER

I had to fix the same problem. In order to fix it you will indeed need the check for subtype of cm:folder , so you need to have the dictionaryservice inside this class. Doing that is quite tedious, but here is my solution:

Override the bean with id "createDownloadArchiveAction", and ingest the serviceregistry into it=>

 <bean id="createDownloadArchiveAction" class="org.alfresco.repo.download.CreateDownloadArchiveActionSR" parent="action-executer">
  <property name="checkOutCheckInSerivce" ref="checkOutCheckInService"/>
  <property name="contentServiceHelper" ref="downloadContentServiceHelper" />
  <property name="downloadStorage" ref="downloadStorage" />
  <property name="exporterService" ref="exporterComponent" />
  <property name="maximumContentSize" value="${download.maxContentSize}" />
  <property name="nodeService" ref="nodeService" />
  <property name="publicAction" value="false"/>
  <property name="transactionHelper" ref="retryingTransactionHelper"/>
  <property name="updateService" ref="downloadStatusUpdateService"/>
  <property name="serviceRegistry">
    <ref bean="ServiceRegistry" />
  </property>

In this new class, you have to forward the serviceregistry to the ZipDownloadExporter =>

private void createDownload(final NodeRef actionedUponNodeRef, ExporterCrawlerParameters crawlerParameters, SizeEstimator estimator)
    {
        // perform the actual export
        final File tempFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX);
        final MyZipDownloadExporter handler = new MyZipDownloadExporter (tempFile, checkOutCheckInService, nodeService, transactionHelper, updateService, downloadStorage,serviceRegistry, actionedUponNodeRef, estimator.getSize(), estimator.getFileCount());

In this class MyZipDownloadExporter you can now do the subtype check:

 public void startNode(NodeRef nodeRef)
    {
        this.currentName = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
        path.push(new Pair<String, NodeRef>(currentName, nodeRef));
        if (this.sr.getDictionaryService().isSubClass((nodeService.getType(nodeRef), ContentModel.TYPE_FOLDER))
        { ....