Java tutorial
/** * 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(); } } }