All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.duracloud.stitch.impl.FileStitcherImpl Maven / Gradle / Ivy

/*
 * 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.stitch.impl;

import org.duracloud.chunk.manifest.ChunksManifest;
import org.duracloud.chunk.manifest.ChunksManifestBean;
import org.duracloud.chunk.manifest.xml.ManifestDocumentBinding;
import org.duracloud.common.model.ContentItem;
import org.duracloud.domain.Content;
import org.duracloud.stitch.FileStitcher;
import org.duracloud.stitch.datasource.DataSource;
import org.duracloud.stitch.error.InvalidManifestException;
import org.duracloud.stitch.stream.MultiContentInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import static org.duracloud.storage.provider.StorageProvider.PROPERTIES_CONTENT_CHECKSUM;
import static org.duracloud.storage.provider.StorageProvider.PROPERTIES_CONTENT_MD5;
import static org.duracloud.storage.provider.StorageProvider.PROPERTIES_CONTENT_MIMETYPE;
import static org.duracloud.storage.provider.StorageProvider.PROPERTIES_CONTENT_SIZE;

/**
 * This class implements the FileStitcher interface.
 *
 * @author Andrew Woods
 *         Date: 9/2/11
 */
public class FileStitcherImpl implements FileStitcher {

    private Logger log = LoggerFactory.getLogger(FileStitcherImpl.class);

    private DataSource dataSource;

    public FileStitcherImpl(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public Content getContentFromManifest(String spaceId, String contentId)
        throws InvalidManifestException {
        log.debug("getContentFromManifest({}, {})", spaceId, contentId);

        // verify contentId corresponds to the manifest naming convention.
        if (!isManifest(contentId)) {
            log.error("Invalid manifest name: {}", contentId);
            throw new InvalidManifestException(spaceId, contentId);
        }

        Content manifestContent = this.dataSource.getContent(spaceId, contentId);
        // get deserialized manifest.
        ChunksManifest manifest = getManifest(manifestContent, spaceId, contentId);

        // collect ordered sequence of chunk streams.
        InputStream multiStream = getChunkSequenceStream(spaceId, manifest);

        // package the chunks as the reconstituted content item.
        Content content = new Content();
        content.setStream(multiStream);
        content.setId(manifest.getHeader().getSourceContentId());
        
        //merge properties by overlaying stitched props over manifest props
        Map stitchedProps = getContentProperties(manifest);
        Map manifestProps = manifestContent.getProperties();
        if(manifestProps == null){
            manifestProps = stitchedProps;
        }else{
            manifestProps.putAll(stitchedProps);
        }
        content.setProperties(manifestProps);
        return content;
    }
    
    private boolean isManifest(String contentId) {
        return null != contentId &&
            contentId.endsWith(ChunksManifest.manifestSuffix);
    }

    @Override
    public ChunksManifest getManifest(String spaceId, String manifestId)
        throws InvalidManifestException {
        return getManifest(dataSource.getContent(spaceId, manifestId), spaceId, manifestId);
    }
    
    private ChunksManifest getManifest(Content content, String spaceId, String manifestId)
        throws InvalidManifestException {
        if (null == content) {
            String msg = "No content found!";
            log.error(msg);
            throw new InvalidManifestException(spaceId, manifestId, msg);
        }

        try {
            return ManifestDocumentBinding.createManifestFrom(content.getStream());

        } catch (Exception e) {
            String msg = "Error deserializing manifest!";
            log.error(msg);
            throw new InvalidManifestException(spaceId, manifestId, msg, e);
        }
    }

    private InputStream getChunkSequenceStream(String spaceId,
                                               ChunksManifest manifest)
        throws InvalidManifestException {
        // sort chunks by their index.
        Map sortedChunkIds = new TreeMap();
        for (ChunksManifestBean.ManifestEntry entry : manifest.getEntries()) {
            sortedChunkIds.put(entry.getIndex(), entry.getChunkId());
        }

        // collect ordered sequence of chunk streams.
        List chunks = new ArrayList();
        for (String chunkId : sortedChunkIds.values()) {
            chunks.add(new ContentItem(spaceId, chunkId));
        }

        if (chunks.size() == 0) {
            String msg = "No chunk streams found!";
            log.error(msg);
            String contentId = manifest.getHeader().getSourceContentId();
            throw new InvalidManifestException(spaceId, contentId, msg);
        }

        return new MultiContentInputStream(dataSource, chunks);
    }

    private Map getContentProperties(ChunksManifest manifest) {
        Map props = new HashMap<>();
        ChunksManifestBean.ManifestHeader header = manifest.getHeader();
        String contentSize = Long.toString(header.getSourceByteSize());
        props.put(PROPERTIES_CONTENT_SIZE, contentSize);
        props.put(PROPERTIES_CONTENT_MIMETYPE, header.getSourceMimetype());
        props.put(PROPERTIES_CONTENT_MD5, header.getSourceMD5());
        props.put(PROPERTIES_CONTENT_CHECKSUM, header.getSourceMD5());
        return props;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy