/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE file at the root of the source
* tree and available online at
*
* https://github.com/keeps/roda
*/
package org.roda.core.common;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
import org.roda.core.common.iterables.CloseableIterable;
import org.roda.core.common.tools.ZipEntryInfo;
import org.roda.core.common.tools.ZipTools;
import org.roda.core.data.exceptions.AuthorizationDeniedException;
import org.roda.core.data.exceptions.GenericException;
import org.roda.core.data.exceptions.NotFoundException;
import org.roda.core.data.exceptions.RequestNotValidException;
import org.roda.core.data.v2.ip.StoragePath;
import org.roda.core.storage.Binary;
import org.roda.core.storage.Resource;
import org.roda.core.storage.StorageService;
public class DownloadUtils {
private static final String BIN_MEDIA_TYPE = "application/octet-stream";
private static final String ZIP_MEDIA_TYPE = "application/zip";
private static final String ZIP_FILE_NAME_EXTENSION = ".zip";
private static final String ZIP_PATH_DELIMITER = "/";
private DownloadUtils() {
// do nothing
}
public static ConsumesOutputStream download(final StorageService storage, final Resource resource) {
return download(storage, resource, null);
}
public static ConsumesOutputStream download(final StorageService storage, final Resource resource, String name) {
ConsumesOutputStream stream;
final StoragePath storagePath = resource.getStoragePath();
if (resource.isDirectory()) {
// send zip with directory contents
final String fileName = name == null ? storagePath.getName() : name;
stream = new ConsumesOutputStream() {
@Override
public void consumeOutputStream(OutputStream out) throws IOException {
CloseableIterable<Resource> resources;
BufferedOutputStream bos = new BufferedOutputStream(out);
ZipOutputStream zos = new ZipOutputStream(bos);
try {
resources = storage.listResourcesUnderDirectory(storagePath, true);
int basePathSize = storagePath.asList().size();
for (Resource r : resources) {
List<String> pathAsList = r.getStoragePath().asList();
List<String> relativePathAsList = pathAsList.subList(basePathSize, pathAsList.size());
String entryPath = relativePathAsList.stream().collect(Collectors.joining(ZIP_PATH_DELIMITER));
if (r.isDirectory()) {
// adding a directory
entryPath += ZIP_PATH_DELIMITER;
zos.putNextEntry(new ZipEntry(entryPath));
zos.closeEntry();
} else {
// adding a file
ZipEntry entry = new ZipEntry(entryPath);
zos.putNextEntry(entry);
Binary binary = storage.getBinary(r.getStoragePath());
InputStream inputStream = binary.getContent().createInputStream();
IOUtils.copy(inputStream, zos);
IOUtils.closeQuietly(inputStream);
zos.closeEntry();
}
}
IOUtils.closeQuietly(resources);
} catch (GenericException | RequestNotValidException | NotFoundException | AuthorizationDeniedException e) {
throw new IOException(e);
} finally {
IOUtils.closeQuietly(zos);
IOUtils.closeQuietly(bos);
IOUtils.closeQuietly(out);
}
}
@Override
public String getFileName() {
return fileName + ZIP_FILE_NAME_EXTENSION;
}
@Override
public String getMediaType() {
return ZIP_MEDIA_TYPE;
}
};
} else {
// send the one file
stream = new ConsumesOutputStream() {
@Override
public void consumeOutputStream(OutputStream out) throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(out);
Binary binary;
try {
binary = storage.getBinary(storagePath);
InputStream inputStream = binary.getContent().createInputStream();
IOUtils.copy(inputStream, bos);
IOUtils.closeQuietly(inputStream);
} catch (GenericException | RequestNotValidException | NotFoundException | AuthorizationDeniedException e) {
throw new IOException(e);
} finally {
IOUtils.closeQuietly(bos);
IOUtils.closeQuietly(out);
}
}
@Override
public String getFileName() {
return storagePath.getName();
}
@Override
public String getMediaType() {
return BIN_MEDIA_TYPE;
}
};
}
return stream;
}
public static StreamResponse createZipStreamResponse(List<ZipEntryInfo> zipEntries, String zipName) {
final ConsumesOutputStream stream = new ConsumesOutputStream() {
@Override
public String getMediaType() {
return ZIP_MEDIA_TYPE;
}
@Override
public String getFileName() {
return zipName;
}
@Override
public void consumeOutputStream(OutputStream out) throws IOException {
ZipTools.zip(zipEntries, out);
}
};
return new StreamResponse(zipName + ZIP_FILE_NAME_EXTENSION, ZIP_MEDIA_TYPE, stream);
}
}