Downloading Multiple Files - Alfresco Content Services - 23.4 - 23.4 - Ready - Alfresco - external

Alfresco Content Services

Platform
Alfresco
Product
Alfresco Content Services
Release
23.4
License

To download multiple files use the DownloadsApi.createDownload method to create a ZIP download on the server side, then check the status of the ZIP download with DownloadsApi.getDownload. When the download is ready get it with NodesApi.getNodeConent. For more information, see Downloading a File.

For more information about this ReST API endpoint, see Download Multiple Files.

For a description of the common parameters, such as fields, see Common Parameters.

import org.alfresco.core.handler.DownloadsApi;
import org.alfresco.core.handler.NodesApi;
import org.alfresco.core.model.Download;
import org.alfresco.core.model.DownloadBodyCreate;
import org.alfresco.core.model.DownloadEntry;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.time.OffsetDateTime;
import java.util.List;

@Component
public class GetMultipleNodeContentCmd {
    static final Logger LOGGER = LoggerFactory.getLogger(GetMultipleNodeContentCmd.class);

    @Autowired
    DownloadsApi downloadsApi;

    @Autowired
    NodesApi nodesApi;

    public void execute(String[] fileNodeIds, String zipFilePathOnDisk) throws IOException, InterruptedException {
        DownloadEntry downloadEntry = createZipDownload(fileNodeIds);
        Resource zipNodeContent = getNodeContent(downloadEntry.getEntry().getId());

        // Write ZIP file to disk
        File targetFile = new File(zipFilePathOnDisk);
        FileUtils.copyInputStreamToFile(zipNodeContent.getInputStream(), targetFile);
    }

    /**
     * Create a ZIP download with multiple file nodes. This method waits until download is ready.
     *
     * @param nodeIds   the node ids for the files we want to download in one ZIP
     * @return download entry info object for the ZIP
     */
    private DownloadEntry createZipDownload(String[] nodeIds) throws InterruptedException {
        List<String> fields = null;

        // Set up POST data with node IDs we want to download
        DownloadBodyCreate downloads = new DownloadBodyCreate();
        for (String nodeId : nodeIds) {
            downloads.addNodeIdsItem(nodeId);
        }

        // First create the download on the server side
        DownloadEntry result = downloadsApi.createDownload(downloads, fields).getBody();

        LOGGER.info("Created ZIP download: {}", result.getEntry().toString());

        // Check the download status
        DownloadEntry download = downloadsApi.getDownload(result.getEntry().getId(), fields).getBody();
        while (!download.getEntry().getStatus().equals(Download.StatusEnum.DONE)) {
            LOGGER.info("Checking ZIP download status: {}", download.getEntry().getStatus());
            Thread.sleep(1000); // do nothing for 1000 milliseconds (1 second)
            download = downloadsApi.getDownload(result.getEntry().getId(), fields).getBody();
        }

        LOGGER.info("ZIP download is READY: {}", result.getEntry().getId());

        return download;
    }

    /**
     * Get a file node content bytes (folders does not have content).
     *
     * @param nodeId   the id of the file node that we want to fetch content for.
     * @return Node content info object
     */
    private Resource getNodeContent(String nodeId) throws IOException {
        // Relevant when using API call from web browser, true is the default
        Boolean attachment = true;
        // Only download if modified since this time, optional
        OffsetDateTime ifModifiedSince = null;
        // The Range header indicates the part of a document that the server should return.
        // Single part request supported, for example: bytes=1-10., optional
        String range = null;

        Resource result = nodesApi.getNodeContent(nodeId, attachment, ifModifiedSince, range).getBody();
        LOGGER.info("Got node {} size: {}", result.getFilename(), result.contentLength());

        return result;
    }
}

Executing the code gives a result looking something like this:

% java -jar target/rest-api-0.0.1-SNAPSHOT.jar get-multiple-file-content 0492460b-6269-4ca1-9668-0d934d2f3370 48413f7a-066d-4e38-b2e6-c84ede635493 mydownload.zip

2021-04-29 12:58:53.560  INFO 19432 --- [           main] o.a.tutorial.restapi.RestApiApplication  : Started RestApiApplication in 2.956 seconds (JVM running for 3.436)
2021-04-29 12:58:53.562  INFO 19432 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[0]: get-multiple-file-content
2021-04-29 12:58:53.564  INFO 19432 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[1]: 0492460b-6269-4ca1-9668-0d934d2f3370
2021-04-29 12:58:53.564  INFO 19432 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[2]: 48413f7a-066d-4e38-b2e6-c84ede635493
2021-04-29 12:58:53.564  INFO 19432 --- [           main] o.a.tutorial.restapi.RestApiApplication  : args[3]: mydownload.zip
2021-04-29 12:58:54.150  INFO 19432 --- [           main] o.a.t.restapi.GetMultipleNodeContentCmd  : Created ZIP download: class Download {
    filesAdded: 0
    bytesAdded: 0
    id: b73c36e5-112b-48a0-baa6-fa225bd9d53d
    totalFiles: 0
    totalBytes: 0
    status: PENDING
}
2021-04-29 12:58:54.167  INFO 19432 --- [           main] o.a.t.restapi.GetMultipleNodeContentCmd  : Checking ZIP download status: PENDING
2021-04-29 12:58:55.194  INFO 19432 --- [           main] o.a.t.restapi.GetMultipleNodeContentCmd  : ZIP download is READY: b73c36e5-112b-48a0-baa6-fa225bd9d53d
2021-04-29 12:58:55.223  INFO 19432 --- [           main] o.a.t.restapi.GetMultipleNodeContentCmd  : Got node archive.zip size: 23111

In this example we pass in two file node identifiers that will be requested in the zip download. The zip download file will be stored in current directory under the name mydownload.zip. Note that right after we have initialized the creation of the zip download there are no files added to the zip (filesAdded: 0), we have to wait for the zip download to be created on the server side. Then we can download with the usual getNodeContent method. For more information, see Downloading a File.