org.dspace.ctask.replicate.store.DuraCloudObjectStore.java Source code

Java tutorial

Introduction

Here is the source code for org.dspace.ctask.replicate.store.DuraCloudObjectStore.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://www.dspace.org/license/
 */
package org.dspace.ctask.replicate.store;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

//import com.google.common.io.Files;
import com.google.common.hash.Hashing;

import org.duracloud.client.ContentStore;
import org.duracloud.client.ContentStoreManager;
import org.duracloud.client.ContentStoreManagerImpl;
import org.duracloud.common.model.Credential;
import org.duracloud.domain.Content;
import org.duracloud.error.ContentStoreException;
import org.duracloud.error.NotFoundException;

import org.dspace.core.ConfigurationManager;
import org.dspace.ctask.replicate.ObjectStore;

/**
 * DuraCloudReplicaStore invokes the DuraCloud RESTful web service API,
 * (using a java client library) rather than using the rsync tool.
 *
 * @author richardrodgers
 */
public class DuraCloudObjectStore implements ObjectStore {

    // DuraCloud store
    private ContentStore dcStore = null;

    public DuraCloudObjectStore() {
    }

    @Override
    public void init() throws IOException {
        // locate & login to Duracloud store
        ContentStoreManager storeManager = new ContentStoreManagerImpl(localProperty("host"), localProperty("port"),
                localProperty("context"));
        Credential credential = new Credential(localProperty("username"), localProperty("password"));
        storeManager.login(credential);
        try {
            //Get the primary content store (e.g. Amazon)   
            dcStore = storeManager.getPrimaryContentStore();
        } catch (ContentStoreException csE) {
            throw new IOException(
                    "Unable to connect to the DuraCloud Primary Content Store. Please check the DuraCloud connection/authentication settings in your 'duracloud.cfg' file.",
                    csE);
        }
    }

    @Override
    public long fetchObject(String group, String id, Path file) throws IOException {
        long size = 0L;
        try {
            // DEBUG REMOVE
            long start = System.currentTimeMillis();
            Content content = dcStore.getContent(getSpaceID(group), getContentPrefix(group) + id);
            // DEBUG REMOVE
            long elapsed = System.currentTimeMillis() - start;
            //System.out.println("DC fetch content: " + elapsed);
            size = Long.valueOf(content.getProperties().get(ContentStore.CONTENT_SIZE));
            //FileOutputStream out = new FileOutputStream(file);
            // DEBUG remove
            start = System.currentTimeMillis();
            InputStream in = content.getStream();
            Files.copy(in, file);
            in.close();
            //out.close();
            // DEBUG REMOVE
            elapsed = System.currentTimeMillis() - start;
            //System.out.println("DC fetch download: " + elapsed);
        } catch (NotFoundException nfE) {
            // no object - no-op
        } catch (ContentStoreException csE) {
            throw new IOException(csE);
        }
        return size;
    }

    @Override
    public boolean objectExists(String group, String id) throws IOException {
        try {
            return dcStore.getContentProperties(getSpaceID(group), getContentPrefix(group) + id) != null;
        } catch (NotFoundException nfE) {
            return false;
        } catch (ContentStoreException csE) {
            throw new IOException(csE);
        }
    }

    @Override
    public long removeObject(String group, String id) throws IOException {
        // get metadata before blowing away
        long size = 0L;
        try {
            Map<String, String> attrs = dcStore.getContentProperties(getSpaceID(group),
                    getContentPrefix(group) + id);
            size = Long.valueOf(attrs.get(ContentStore.CONTENT_SIZE));
            dcStore.deleteContent(getSpaceID(group), getContentPrefix(group) + id);
        } catch (NotFoundException nfE) {
            // no replica - no-op
        } catch (ContentStoreException csE) {
            throw new IOException(csE);
        }
        return size;
    }

    @Override
    public long transferObject(String group, Path file) throws IOException {
        long size = 0L;
        String chkSum = com.google.common.io.Files.hash(file.toFile(), Hashing.md5()).toString(); //Utils.checksum(file, "MD5");
        // make sure this is a different file from what replica store has
        // to avoid network I/O tax
        try {
            Map<String, String> attrs = dcStore.getContentProperties(getSpaceID(group),
                    getContentPrefix(group) + file.getFileName().toString());
            if (!chkSum.equals(attrs.get(ContentStore.CONTENT_CHECKSUM))) {
                size = uploadReplica(group, file, chkSum);
            }
        } catch (NotFoundException nfE) {
            // no extant replica - proceed
            size = uploadReplica(group, file, chkSum);
        } catch (ContentStoreException csE) {
            throw new IOException(csE);
        }
        // delete staging file
        Files.delete(file);
        return size;
    }

    private long uploadReplica(String group, Path file, String chkSum) throws IOException {
        try {
            //@TODO: We shouldn't need to pass a hardcoded MIME Type. Unfortunately, DuraCloud, 
            // as of 1.3, doesn't properly determine a file's MIME Type. In future it should.
            String mimeType = "application/octet-stream";
            String fileName = file.getFileName().toString();
            if (fileName.endsWith(".zip"))
                mimeType = "application/zip";
            else if (fileName.endsWith(".tgz"))
                mimeType = "application/x-gzip";
            else if (fileName.endsWith(".txt"))
                mimeType = "text/plain";

            dcStore.addContent(getSpaceID(group), getContentPrefix(group) + fileName,
                    new FileInputStream(file.toFile()), Files.size(file), mimeType, chkSum,
                    new HashMap<String, String>());

            return Files.size(file);
        } catch (ContentStoreException csE) {
            throw new IOException(csE);
        }
    }

    @Override
    public long moveObject(String srcGroup, String destGroup, String id) throws IOException {
        // get file-size metadata before moving the content
        long size = 0L;
        try {
            Map<String, String> attrs = dcStore.getContentProperties(getSpaceID(srcGroup),
                    getContentPrefix(srcGroup) + id);
            size = Long.valueOf(attrs.get(ContentStore.CONTENT_SIZE));
            dcStore.moveContent(getSpaceID(srcGroup), getContentPrefix(srcGroup) + id, getSpaceID(destGroup),
                    getContentPrefix(destGroup) + id);
        } catch (NotFoundException nfE) {
            // no replica - no-op
        } catch (ContentStoreException csE) {
            throw new IOException(csE);
        }
        return size;
    }

    @Override
    public String objectAttribute(String group, String id, String attrName) throws IOException {
        try {
            Map<String, String> attrs = dcStore.getContentProperties(getSpaceID(group),
                    getContentPrefix(group) + id);

            if ("checksum".equals(attrName)) {
                return attrs.get(ContentStore.CONTENT_CHECKSUM);
            } else if ("sizebytes".equals(attrName)) {
                return attrs.get(ContentStore.CONTENT_SIZE);
            } else if ("modified".equals(attrName)) {
                return attrs.get(ContentStore.CONTENT_MODIFIED);
            }
            return null;
        } catch (NotFoundException nfE) {
            return null;
        } catch (ContentStoreException csE) {
            throw new IOException(csE);
        }
    }

    private static String localProperty(String name) {
        return ConfigurationManager.getProperty("duracloud", name);
    }

    /**
     * Returns the Space ID where content should be stored in DuraCloud,
     * based on the passed in Group.
     * <P>
     * If the group contains a forward slash ('/'), then the substring
     * before the first slash is assumed to be the Space ID.
     * Otherwise, the entire group name is assumed to be the Space ID.
     * @param String group name
     * @return DuraCloud Space ID
     */
    private String getSpaceID(String group) {
        //If group contains a forward or backslash, then the
        //Space ID is whatever is before that slash
        if (group != null && group.contains("/"))
            return group.substring(0, group.indexOf("/"));
        else // otherwise, the passed in group is the Space ID
            return group;
    }

    /**
     * Returns the Content prefix that should be used when saving a file
     * to a DuraCloud space.
     * <P>
     * If the group contains a forward slash ('/'), then the substring
     * after the first slash is assumed to be the content naming prefix.
     * Otherwise, there is no content naming prefix.
     * @param String group name
     * @return content prefix (ending with a forward slash)
     */
    private String getContentPrefix(String group) {
        //If group contains a forward or backslash, then the
        // content prefix is whatever is after that slash
        if (group != null && group.contains("/"))
            return group.substring(group.indexOf("/") + 1) + "/";
        else // otherwise, no content prefix is specified
            return "";
    }
}