org.duracloud.chunk.writer.FilesystemContentWriter.java Source code

Java tutorial

Introduction

Here is the source code for org.duracloud.chunk.writer.FilesystemContentWriter.java

Source

/*
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 *     http://duracloud.org/license/
 */
package org.duracloud.chunk.writer;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.duracloud.chunk.ChunkableContent;
import org.duracloud.chunk.error.NotFoundException;
import org.duracloud.chunk.manifest.ChunksManifest;
import org.duracloud.chunk.stream.ChunkInputStream;
import org.duracloud.chunk.stream.KnownLengthInputStream;
import org.duracloud.common.error.DuraCloudRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class implements the ContentWriter interface to write the provided
 * content to a local filesystem.
 *
 * @author Andrew Woods
 * Date: Feb 5, 2010
 */
public class FilesystemContentWriter implements ContentWriter {

    private final Logger log = LoggerFactory.getLogger(FilesystemContentWriter.class);
    private static final long TWO_GB = 2000000000;

    private List<AddContentResult> results = new ArrayList<AddContentResult>();

    /**
     * This method returns the results of the content write requests.
     *
     * @return List of results
     */
    public List<AddContentResult> getResults() {
        return results;
    }

    public void ignore(String spaceId, String contentId, long contentSize) {
        AddContentResult result = new AddContentResult(spaceId, contentId, contentSize);
        result.setState(AddContentResult.State.IGNORED);
        results.add(result);
    }

    /**
     * This method implements the ContentWriter interface for writing content
     * to a DataStore. In this case, the DataStore is a local filesystem.
     * The arg spaceId is the path to the destination directory.
     *
     * @param spaceId   destination where arg chunkable content will be written
     * @param chunkable content to be written
     */
    public ChunksManifest write(String spaceId, ChunkableContent chunkable) throws NotFoundException {
        return write(spaceId, chunkable, null);
    }

    /**
     * This method implements the ContentWriter interface for writing content
     * to a DataStore. In this case, the DataStore is a local filesystem.
     * The arg spaceId is the path to the destination directory.
     *
     * @param spaceId           destination where arg chunkable content will be written
     * @param contentProperties user defined properties to be associated with content.
     * @param chunkable         content to be written
     */
    public ChunksManifest write(String spaceId, ChunkableContent chunkable, Map<String, String> contentProperties)
            throws NotFoundException {
        for (ChunkInputStream chunk : chunkable) {
            writeSingle(spaceId, null, chunk, null);
        }

        ChunksManifest manifest = chunkable.finalizeManifest();
        KnownLengthInputStream manifestStream = manifest.getBody();

        AddContentResult result = writeContent(spaceId, manifest.getManifestId(), manifestStream,
                manifestStream.getLength(), contentProperties);
        result.setMd5("md5-not-collected-for-manifest");

        return manifest;
    }

    /**
     * This method implements the ContentWriter interface for writing content
     * to a DataStore. In this case, the DataStore is a local filesystem.
     * The arg spaceId is the path to the destination directory.
     *
     * @param spaceId    destination where arg chunk content will be written
     * @param chunk      content to be written
     * @param properties user-defined properties associated with content
     * @return MD5 of content
     * @throws NotFoundException
     */
    @Override
    public String writeSingle(String spaceId, String chunkChecksum, ChunkInputStream chunk,
            Map<String, String> properties) throws NotFoundException {
        AddContentResult result = writeContent(spaceId, chunk.getChunkId(), chunk, chunk.getChunkSize(),
                properties);
        String finalChecksum = chunk.getMD5();
        if (chunkChecksum != null && chunk.md5Preserved()) {
            if (!chunkChecksum.equals(finalChecksum)) {
                result.setState(AddContentResult.State.ERROR);
            }
        }

        result.setMd5(finalChecksum);
        return finalChecksum;
    }

    @Override
    public String writeSingle(String spaceId, String chunkChecksum, ChunkInputStream chunk)
            throws NotFoundException {
        return writeSingle(spaceId, chunkChecksum, chunk, null);
    }

    private AddContentResult writeContent(String spaceId, String contentId, InputStream inputStream,
            long contentSize, Map<String, String> contentProperties) {

        File spaceDir = getSpaceDir(spaceId);
        OutputStream outStream = getOutputStream(spaceDir, contentId);

        AddContentResult result = new AddContentResult(spaceId, contentId, contentSize);
        result.setState(AddContentResult.State.SUCCESS);
        try {
            if (contentSize > TWO_GB) {
                copyLarge(inputStream, outStream);
            } else {
                copy(inputStream, outStream);
            }
        } catch (Exception e) {
            result.setState(AddContentResult.State.ERROR);
        }

        flushAndClose(outStream);

        results.add(result);
        return result;
    }

    private void copyLarge(InputStream chunk, OutputStream outStream) {
        try {
            IOUtils.copyLarge(chunk, outStream);
        } catch (IOException e) {
            String msg = "Error in copy: " + chunk.toString() + ": ";
            log.error(msg, e);
            throw new DuraCloudRuntimeException(msg + e.getMessage(), e);
        }
    }

    private void copy(InputStream chunk, OutputStream outStream) {
        try {
            IOUtils.copy(chunk, outStream);
        } catch (IOException e) {
            String msg = "Error in copy: " + chunk.toString() + ": ";
            log.error(msg, e);
            throw new DuraCloudRuntimeException(msg + e.getMessage(), e);
        }
    }

    private OutputStream getOutputStream(File spaceDir, String contentId) {
        File outFile = getContentFile(spaceDir, contentId);
        return getOutputStream(outFile);
    }

    private OutputStream getOutputStream(File outFile) {
        final int BUFFER_SIZE = 8192;
        try {
            return new BufferedOutputStream(new FileOutputStream(outFile), BUFFER_SIZE);
        } catch (FileNotFoundException e) {
            throw new DuraCloudRuntimeException(e.getMessage(), e);
        }
    }

    private void flushAndClose(OutputStream outStream) {
        try {
            outStream.flush();
        } catch (IOException e) {
            // do nothing
        } finally {
            IOUtils.closeQuietly(outStream);
        }
    }

    private File getContentFile(File spaceDir, String contentId) {
        File contentFile = new File(spaceDir, contentId);
        File parent = contentFile.getParentFile();
        if (parent != null && !parent.exists()) {
            parent.mkdirs();
        }
        return contentFile;
    }

    private File getSpaceDir(String spaceId) {
        File spaceDir = new File(spaceId);
        if (!spaceDir.exists()) {
            spaceDir.mkdirs();
        }
        return spaceDir;
    }

}