com.seajas.search.contender.service.storage.StorageService.java Source code

Java tutorial

Introduction

Here is the source code for com.seajas.search.contender.service.storage.StorageService.java

Source

/**
 * Copyright (C) 2013 Seajas, the Netherlands.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3, as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.seajas.search.contender.service.storage;

import com.mongodb.gridfs.GridFS;
import com.mongodb.gridfs.GridFSDBFile;
import com.mongodb.gridfs.GridFSInputFile;
import com.seajas.search.bridge.jms.model.CompositeEntry;
import com.seajas.search.bridge.jms.model.state.CompositeState;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.EnumSet;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import static org.springframework.data.mongodb.core.query.Criteria.where;

/**
 * Storage service used to retrieve and persist composite entries.
 *
 * @author Jasper van Veghel <jasper@seajas.com>
 */
@Service
public class StorageService {
    /**
     * The logger.
     */
    private static final Logger logger = LoggerFactory.getLogger(StorageService.class);

    /**
     * Constants.
     */
    private static final String MONGO_COLLECTION = "entries";

    /**
     * The Mongo template.
     */
    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * The default collection.
     */
    @Value("${bridged.project.mongo.db.collection}")
    private String defaultCollection;

    /**
     * The GridFS database.
     */
    private GridFS gridFs;

    /**
     * Default constructor.
     *
     * @param dbFactory
     */
    @Autowired
    public StorageService(final MongoDbFactory dbFactory) {
        this.gridFs = new GridFS(dbFactory.getDb());
    }

    /**
     * Retrieve a CompositeEntry document by its ID.
     *
     * @param id
     * @return CompositeEntry
     */
    public CompositeEntry retrieveEntryById(final ObjectId id) {
        CompositeEntry entry = mongoTemplate.findById(id, CompositeEntry.class, defaultCollection);

        if (entry != null && !EnumSet.of(CompositeState.Source, CompositeState.SourceElement)
                .contains(entry.getCurrentState())) {
            if (entry.getOriginalContent() != null) {
                GridFSDBFile file = gridFs.find(entry.getOriginalContent().getId());

                entry.getOriginalContent().setContent(new BufferedInputStream(file.getInputStream()));
            } else if (entry.getModifiedContent() != null) {
                GridFSDBFile file = gridFs.find(entry.getModifiedContent().getId());

                entry.getModifiedContent().setContent(new BufferedInputStream(file.getInputStream()));
            } else
                logger.error(
                        "Content retrieval is relevant given this entry's current state, but no content has been stored");
        }

        return entry;
    }

    /**
     * Retrieve a CompositeEntry document by its ID.
     *
     * @param compositeUrl
     * @return CompositeEntry
     */
    public CompositeEntry retrieveEntryByCompositeUrl(final String compositeUrl) {
        Query query = new Query().addCriteria(where("enricherElement._id").is(compositeUrl));

        CompositeEntry entry = mongoTemplate.findOne(query, CompositeEntry.class, defaultCollection);

        if (entry != null && !EnumSet.of(CompositeState.Source, CompositeState.SourceElement)
                .contains(entry.getCurrentState())) {
            if (entry.getOriginalContent() != null) {
                GridFSDBFile file = gridFs.find(entry.getOriginalContent().getId());

                entry.getOriginalContent().setContent(new BufferedInputStream(file.getInputStream()));
            } else if (entry.getModifiedContent() != null) {
                GridFSDBFile file = gridFs.find(entry.getModifiedContent().getId());

                entry.getModifiedContent().setContent(new BufferedInputStream(file.getInputStream()));
            } else
                logger.error(
                        "Content retrieval is relevant given this entry's current state, but no content has been stored");
        }

        return entry;
    }

    /**
     * Close any outstanding streams for the given entry.
     *
     * @param entry
     */
    public void closeEntry(final CompositeEntry entry) {
        if (entry.getOriginalContent() != null && entry.getOriginalContent().getContent() != null)
            IOUtils.closeQuietly(entry.getOriginalContent().getContent());
        if (entry.getModifiedContent() != null && entry.getModifiedContent().getContent() != null)
            IOUtils.closeQuietly(entry.getModifiedContent().getContent());
    }

    /**
     * Store (create or update) the given entry.
     *
     * @param entry
     * @return boolean
     */
    public boolean saveEntry(final CompositeEntry entry) {
        // First we save the original and modified content, if applicable

        if (entry.getCurrentState().equals(CompositeState.Content)) {
            if (entry.getOriginalContent() == null && entry.getModifiedContent() == null) {
                logger.error(
                        "Content storage is relevant given this entry's current state, but no content was set");

                return false;
            }

            // Only store the content in case the ID hasn't been set yet

            if (entry.getOriginalContent() != null && entry.getOriginalContent().getId() == null) {
                ObjectId id = storeContent(entry.getOriginalContent().getContent());

                if (id != null)
                    entry.getOriginalContent().setId(id);
            }

            // Re-store the content in case the ID /has/ been set

            if (entry.getModifiedContent() != null && entry.getModifiedContent().getContent() != null) {
                ObjectId existingId = entry.getModifiedContent().getId();
                ObjectId id = storeContent(entry.getModifiedContent().getContent());

                if (id != null)
                    entry.getModifiedContent().setId(id);

                if (existingId != null) {
                    logger.warn(
                            "The modified content of the given entry has been stored previously - removing the original reference with ID "
                                    + existingId);

                    gridFs.remove(existingId);
                }
            }
        }

        // Then we save the entire entry

        mongoTemplate.save(entry, defaultCollection);

        return true;
    }

    /**
     * Remove the content object with the given ID.
     *
     * @param id
     * @return boolean
     */
    public boolean removeContent(final ObjectId id) {
        try {
            gridFs.remove(id);
        } catch (RuntimeException e) {
            logger.error("Unable to remove object with ID: " + id, e);

            return false;
        }

        return true;
    }

    /**
     * Store the given content in GridFS and return the relevant ObjectId.
     *
     * @param content
     * @return ObjectId
     */
    private ObjectId storeContent(final InputStream content) {
        if (content == null)
            throw new IllegalArgumentException("Content storage was requested but no content was given");

        if (!content.markSupported())
            logger.warn(
                    "Marking of the (original) content stream is not supported - will not reset the stream after storage");

        GridFSInputFile inputFile = gridFs.createFile(content, false);

        try {
            inputFile.save();
        } finally {
            if (content.markSupported())
                try {
                    content.reset();
                } catch (IOException e) {
                    logger.error("Unable to reset the given stream, despite mark() being supported", e);
                }

            return (ObjectId) inputFile.getId();
        }
    }
}