com.imaginea.mongodb.services.impl.GridFSServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.imaginea.mongodb.services.impl.GridFSServiceImpl.java

Source

/*
 * Copyright (c) 2011 Imaginea Technologies Private Ltd. Hyderabad, India
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in
 * writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.
 */
package com.imaginea.mongodb.services.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import org.bson.BsonObjectId;
import org.bson.BsonValue;
import org.bson.Document;
import org.bson.codecs.BsonValueCodec;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.imaginea.mongodb.exceptions.ApplicationException;
import com.imaginea.mongodb.exceptions.CollectionException;
import com.imaginea.mongodb.exceptions.DatabaseException;
import com.imaginea.mongodb.exceptions.DocumentException;
import com.imaginea.mongodb.exceptions.ErrorCodes;
import com.imaginea.mongodb.exceptions.GridFSException;
import com.imaginea.mongodb.exceptions.InvalidMongoCommandException;
import com.imaginea.mongodb.exceptions.ValidationException;
import com.imaginea.mongodb.services.AuthService;
import com.imaginea.mongodb.services.CollectionService;
import com.imaginea.mongodb.services.DatabaseService;
import com.imaginea.mongodb.services.GridFSService;
import com.imaginea.mongodb.utils.JSON;
import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoException;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.gridfs.model.GridFSUploadOptions;
import com.mongodb.gridfs.GridFS;
import com.mongodb.gridfs.GridFSDBFile;
import com.mongodb.gridfs.GridFSInputFile;

/**
 * Defines services definitions for performing operations like create/drop on collections inside a
 * database present in mongo to which we are connected to. Also provides service to get list of all
 * collections present and Statistics of a particular file.
 *
 * @author Srinath Anantha
 */
public class GridFSServiceImpl implements GridFSService {

    /**
     * Mongo Instance to communicate with mongo
     */
    private MongoClient mongoInstance;

    private DatabaseService databaseService;
    private CollectionService collectionService;

    private static final AuthService AUTH_SERVICE = AuthServiceImpl.getInstance();
    private static final String FILES_COLLECTION_FIELD_STRING = "_filesCollection";
    private static final String CHUNKS_COLLECTION_FIELD_STRING = "_chunkCollection";

    /**
     * Creates an instance of MongoInstanceProvider which is used to get a mongo instance to perform
     * operations on files. The instance is created based on a userMappingKey which is received from
     * the file request dispatcher and is obtained from tokenId of user.
     *
     * @param connectionId A combination of username,mongoHost and mongoPort
     */
    public GridFSServiceImpl(String connectionId) throws ApplicationException {
        mongoInstance = AUTH_SERVICE.getMongoInstance(connectionId);
        databaseService = new DatabaseServiceImpl(connectionId);
        collectionService = new CollectionServiceImpl(connectionId);
    }

    /**
     * Service implementation for creating GridFS store in the specified database.
     *
     * @param dbName Name of Database
     * @param bucketName Name of GridFS Bucket
     * @return Status message.
     */
    public String createStore(String dbName, String bucketName)
            throws DatabaseException, CollectionException, GridFSException {
        if (dbName == null) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database Name Is Null");
        }
        if (dbName.equals("")) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database Name Empty");
        }
        if (bucketName == null) {
            throw new CollectionException(ErrorCodes.COLLECTION_NAME_EMPTY, "Bucket name is null");
        }
        if (bucketName.equals("")) {
            throw new CollectionException(ErrorCodes.COLLECTION_NAME_EMPTY, "Bucket Name Empty");
        }
        if (getAllBuckets(dbName).contains(bucketName)) {
            throw new CollectionException(ErrorCodes.COLLECTION_ALREADY_EXISTS,
                    "Collection [" + bucketName + "] already exists in Database [" + dbName + "]");
        } else {
            try {

                GridFSBucket gridFSBucket = GridFSBuckets.create(mongoInstance.getDatabase(dbName), bucketName);

                // Get the input stream
                InputStream streamToUploadFrom = new FileInputStream(new File("/home/maheshk/sample.txt"));

                // Create some custom options
                GridFSUploadOptions options = new GridFSUploadOptions().chunkSizeBytes(1024)
                        .metadata(new Document("type", "presentation"));

                ObjectId fileId = gridFSBucket.uploadFromStream("temp-file", streamToUploadFrom, options);

            } catch (MongoException e) {
                throw new GridFSException(ErrorCodes.GRIDFS_CREATION_EXCEPTION, e.getMessage());
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return "GridFS bucket [" + bucketName + "] added to database [" + dbName + "].";
        }
    }

    /**
     * Service implementation for getting the list of files stored in GridFS of specified database.
     *
     * @param dbName Name of Database
     * @param bucketName Name of GridFS Bucket
     * @param bucketType
     * @param command
     * @param query
     * @param skip
     * @param limit
     * @param sortBy
     * @return JSON representation of list of all files as a String.
     */
    public JSONObject executeQuery(String dbName, String bucketName, String bucketType, String command,
            String query, String skip, String limit, String sortBy) throws ApplicationException, JSONException {
        if (dbName == null) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database Name Is Null");
        }
        if (dbName.equals("")) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database Name Empty");
        }
        if (bucketName == null) {
            throw new CollectionException(ErrorCodes.BUCKET_NAME_EMPTY, "Bucket name is null");
        }
        if (bucketName.equals("")) {
            throw new CollectionException(ErrorCodes.BUCKET_NAME_EMPTY, "Bucket Name Empty");
        }
        if (bucketType == null) {
            throw new CollectionException(ErrorCodes.COLLECTION_NAME_EMPTY, "Collection name is null");
        }
        if (bucketType.equals("")) {
            throw new CollectionException(ErrorCodes.COLLECTION_NAME_EMPTY, "Collection Name Empty");
        }
        // if (!databaseService.getDbList().contains(dbName)) {
        //   throw new DatabaseException(ErrorCodes.DB_DOES_NOT_EXISTS,
        //       "Database with dbName [ " + dbName + "] does not exist");
        // }
        MongoDatabase db = mongoInstance.getDatabase(dbName);

        GridFSBucket gridFS = GridFSBuckets.create(db, bucketName);

        // MongoCollection<Document> filesCollection =
        // getGridFSCollection(gridFS, bucketType);
        try {
            if (command.equals("find")) {
                return executeFind(gridFS, query, sortBy, limit, skip);
            } else if (command.equals("drop")) {
                return executeDrop(db, bucketName);
            } else {
                throw new InvalidMongoCommandException(ErrorCodes.COMMAND_NOT_SUPPORTED,
                        "This command is not supported in GridFS");
            }
        } catch (MongoException e) {
            throw new GridFSException(ErrorCodes.QUERY_EXECUTION_EXCEPTION, e.getMessage());
        }
    }

    private JSONObject executeFind(GridFSBucket gridFS, String query, String sortBy, String limit, String skip)
            throws JSONException {
        Document queryObj = Document.parse(query);
        Document sortObj = Document.parse(sortBy);
        int filesLimit = Integer.parseInt(limit);
        int filesSkip = Integer.parseInt(skip);
        // Partial Keys cant be fetched for a file

        MongoCursor<GridFSFile> it = gridFS.find(queryObj).sort(sortObj).skip(filesSkip).limit(filesLimit)
                .iterator();

        JSONArray fileList = new JSONArray();
        while (it.hasNext()) {
            GridFSFile fsFile = it.next();

            JSONObject file = new JSONObject();

            file.put("_id", fsFile.getId().asObjectId().getValue());
            file.put("fileName", fsFile.getFilename());
            file.put("length", fsFile.getLength());
            file.put("chunkSize", fsFile.getChunkSize());
            file.put("uploadDate", fsFile.getUploadDate());
            file.put("md5", fsFile.getMD5());
            if (fsFile.getMetadata() != null) {
                file.put("metadata", fsFile.getMetadata());
            }

            fileList.put(file);

        }
        JSONObject result = new JSONObject();
        long count = fileList.length();
        result.put("documents", fileList);
        result.put("editable", true);
        result.put("count", count);
        return result;
    }

    private JSONObject executeDrop(MongoDatabase db, String bucketName) throws JSONException {
        db.getCollection(bucketName + ".files").drop();
        db.getCollection(bucketName + ".chunks").drop();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("success", true);
        return jsonObject;
    }

    // private MongoCollection<Document> getGridFSCollection(GridFSBucket
    // gridFS, String collectionName) throws ApplicationException {
    // String collectionField = null;
    // if (collectionName.equals("files")) {
    // collectionField = FILES_COLLECTION_FIELD_STRING;
    // } else if (collectionName.equals("chunks")) {
    // throw new CollectionException(ErrorCodes.COMMAND_NOT_SUPPORTED, "Commands
    // on chunks are not yet supported");
    // } else {
    // throw new CollectionException(ErrorCodes.COLLECTION_DOES_NOT_EXIST,
    // "Collection does not exist for bucket");
    // }
    // Field field = null;
    // try {
    // field = GridFSBucket.class.getDeclaredField(collectionField);
    // field.setAccessible(true);
    // return (MongoCollection<Document>) field.get(gridFS);
    // } catch (Exception e) {
    // throw new ApplicationException(ErrorCodes.INVALID_ARGUMENT,
    // e.getMessage());
    // }
    // }

    /**
     * Service implementation for retrieving the specified file stored in GridFS.
     *
     * @param dbName Name of Database
     * @param bucketName Name of GridFS Bucket
     * @param _id ObjectId of the file to be retrieved
     * @return Requested multipartfile for viewing or download based on 'download' param.
     */
    public File getFile(String dbName, String bucketName, String _id)
            throws ValidationException, DatabaseException, CollectionException {
        if (dbName == null) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database Name Is Null");
        }
        if (dbName.equals("")) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database Name Empty");
        }
        File tempFile = null;
        try {
            // if (!databaseService.getDbList().contains(dbName)) {
            //   throw new DatabaseException(ErrorCodes.DB_DOES_NOT_EXISTS,

            //       "Database with dbName [ " + dbName + "] does not exist");
            // }

            ObjectId objectId = new ObjectId(_id);

            MongoDatabase db = mongoInstance.getDatabase(dbName);

            GridFSBucket gridFS = GridFSBuckets.create(db, bucketName);

            Document id = new Document();

            id.put("_id", objectId);

            GridFSFile fsFile = gridFS.find(id).first();

            if (fsFile != null) {

                String tempDir = System.getProperty("java.io.tmpdir");

                tempFile = new File(tempDir + "/" + fsFile.getFilename());

                FileOutputStream streamToDownloadTo = new FileOutputStream(tempFile);

                gridFS.downloadToStream(objectId, streamToDownloadTo);

                streamToDownloadTo.close();

            }

        } catch (MongoException m) {
            throw new CollectionException(ErrorCodes.GET_COLLECTION_LIST_EXCEPTION, m.getMessage());
        } catch (IOException e) {
            throw new CollectionException(ErrorCodes.GET_COLLECTION_LIST_EXCEPTION, e.getMessage());
        }
        return tempFile;
    }

    /**
     * Service implementation for uploading a file to GridFS.
     *
     * @param dbName Name of Database
     * @param bucketName Name of GridFS Bucket
     * @param formData formDataBodyPart of the uploaded file
     * @param inputStream inputStream of the uploaded file
     * @param connectionId ConnectionId of the connection
     * @return Success message with additional file details such as name, size, download url &
     *         deletion url as JSON Array string.
     */
    public JSONArray insertFile(String dbName, String bucketName, String connectionId, InputStream inputStream,
            FormDataContentDisposition fileData) throws ApplicationException {
        if (dbName == null) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database name is null");

        }
        if (dbName.equals("")) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database Name Empty");
        }

        if (bucketName == null) {
            throw new CollectionException(ErrorCodes.COLLECTION_NAME_EMPTY, "Bucket name is null");
        }
        if (bucketName.equals("")) {
            throw new CollectionException(ErrorCodes.COLLECTION_NAME_EMPTY, "Bucket Name Empty");
        }

        JSONArray result = new JSONArray();

        try {
            // if (!databaseService.getDbList().contains(dbName)) {
            //   throw new DatabaseException(ErrorCodes.DB_DOES_NOT_EXISTS,
            //       "DB [" + dbName + "] DOES NOT EXIST");
            // }

            MongoDatabase db = mongoInstance.getDatabase(dbName);

            GridFSBucket gridFS = GridFSBuckets.create(db, bucketName);

            GridFSUploadOptions options = new GridFSUploadOptions().chunkSizeBytes(1024)
                    .metadata(new Document("type", "presentation"));

            ObjectId fileId = gridFS.uploadFromStream(fileData.getFileName(), inputStream, options);

            String objectId = JSON.serialize(fileId);
            JSONObject obj = new JSONObject();
            obj.put("name", fileData.getFileName());
            // obj.put("size", fileData.);
            obj.put("url", String.format("services/%s/%s/gridfs/getfile?id=%s&download=%s&connectionId=%s&ts=%s",
                    dbName, bucketName, objectId, false, connectionId, new Date()));
            obj.put("delete_url", String.format("services/%s/%s/gridfs/dropfile?id=%s&connectionId=%s&ts=%s",
                    dbName, bucketName, objectId, connectionId, new Date().getTime()));
            obj.put("delete_type", "GET");
            result.put(obj);

        } catch (MongoException e) {
            throw new CollectionException(ErrorCodes.UPLOAD_FILE_EXCEPTION, e.getMessage());
        } catch (JSONException e) {
            throw new ApplicationException(ErrorCodes.JSON_EXCEPTION, "Error creating json response obj",
                    e.getCause());
        }
        return result;
    }

    /**
     * Service implementation for dropping a file from GridFS.
     *
     * @param dbName Name of Database
     * @param bucketName Name of GridFS Bucket
     * @param _id Object id of file to be deleted
     * @return Status message.
     */
    public String deleteFile(String dbName, String bucketName, String _id)
            throws DatabaseException, DocumentException, CollectionException, ValidationException {
        if (dbName == null) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database name is null");

        }
        if (dbName.equals("")) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database Name Empty");
        }

        if (bucketName == null) {
            throw new CollectionException(ErrorCodes.COLLECTION_NAME_EMPTY, "Bucket name is null");
        }
        if (bucketName.equals("")) {
            throw new CollectionException(ErrorCodes.COLLECTION_NAME_EMPTY, "Bucket Name Empty");
        }

        String result = null;
        GridFSFile gridFSFile = null;
        try {
            // if (!databaseService.getDbList().contains(dbName)) {
            //   throw new DatabaseException(ErrorCodes.DB_DOES_NOT_EXISTS,
            //       "DB [" + dbName + "] DOES NOT EXIST");
            // }
            if (_id == null) {
                throw new DocumentException(ErrorCodes.DOCUMENT_EMPTY, "File is empty");
            }

            ObjectId objectId = new ObjectId(_id);

            MongoDatabase db = mongoInstance.getDatabase(dbName);

            GridFSBucket gridFS = GridFSBuckets.create(db, bucketName);

            Document id = new Document();

            id.put("_id", objectId);

            gridFSFile = gridFS.find(id).first();
            if (gridFSFile == null) {
                throw new DocumentException(ErrorCodes.DOCUMENT_DOES_NOT_EXIST, "Document does not exist !");
            }

            gridFS.delete(objectId);

        } catch (MongoException e) {
            throw new DocumentException(ErrorCodes.DOCUMENT_DELETION_EXCEPTION, e.getMessage());
        }
        result = "File [" + gridFSFile.getFilename() + "] has been deleted.";
        return result;
    }

    @Override
    public Set<String> getAllBuckets(String dbName) throws DatabaseException, CollectionException {
        if (dbName == null) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database name is null");

        }
        if (dbName.equals("")) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database Name Empty");
        }

        // if (!databaseService.getDbList().contains(dbName)) {
        //   throw new DatabaseException(ErrorCodes.DB_DOES_NOT_EXISTS,
        //       "DB [" + dbName + "] DOES NOT EXIST");
        // }

        MongoCursor<String> iterator = mongoInstance.getDatabase(dbName).listCollectionNames().iterator();

        Set<String> bucketsList = new HashSet<String>();
        if (iterator.hasNext()) {
            while (iterator.hasNext()) {

                String collection = iterator.next();

                int pos = collection.lastIndexOf(".files");
                if (pos > 0) {
                    bucketsList.add(collection.substring(0, pos));
                }
            }
        }
        return bucketsList;
    }

    /**
     * Service implementation for dropping all files from a GridFS bucket.
     *
     * @param dbName Name of Database
     * @param bucketName Name of GridFS Bucket
     * @return Status message.
     */
    public String dropBucket(String dbName, String bucketName)
            throws DatabaseException, DocumentException, CollectionException, ValidationException, JSONException {
        if (dbName == null) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database name is null");

        }
        if (dbName.equals("")) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database Name Empty");
        }

        if (bucketName == null) {
            throw new CollectionException(ErrorCodes.COLLECTION_NAME_EMPTY, "Bucket name is null");
        }
        if (bucketName.equals("")) {
            throw new CollectionException(ErrorCodes.COLLECTION_NAME_EMPTY, "Bucket Name Empty");
        }

        String result = null;
        try {
            // if (!databaseService.getDbList().contains(dbName)) {
            //   throw new DatabaseException(ErrorCodes.DB_DOES_NOT_EXISTS,
            //       "DB [" + dbName + "] DOES NOT EXIST");
            // }
            executeDrop(mongoInstance.getDatabase(dbName), bucketName);
        } catch (MongoException e) {
            throw new DocumentException(ErrorCodes.DOCUMENT_DELETION_EXCEPTION, e.getMessage());
        }
        result = "Bucket [" + bucketName + "] has been deleted from Database [" + dbName + "].";
        return result;
    }

    /**
     * Service handler for getting count of all files in a GridFS bucket.
     *
     * @param dbName Name of Database
     * @param bucketName Name of GridFS Bucket
     * @return Status message.
     */
    public JSONObject getCount(String dbName, String bucketName)
            throws DatabaseException, DocumentException, ValidationException, CollectionException {
        if (dbName == null) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database name is null");

        }
        if (dbName.equals("")) {
            throw new DatabaseException(ErrorCodes.DB_NAME_EMPTY, "Database Name Empty");
        }

        if (bucketName == null) {
            throw new CollectionException(ErrorCodes.COLLECTION_NAME_EMPTY, "Bucket name is null");
        }
        if (bucketName.equals("")) {
            throw new CollectionException(ErrorCodes.COLLECTION_NAME_EMPTY, "Bucket Name Empty");
        }

        JSONObject result = new JSONObject();
        try {
            // if (!databaseService.getDbList().contains(dbName)) {
            //   throw new DatabaseException(ErrorCodes.DB_DOES_NOT_EXISTS,
            //       "DB [" + dbName + "] DOES NOT EXIST");
            // }

            long count = mongoInstance.getDB(dbName).getCollection(bucketName + ".files").count();
            result.put("count", count);

        } catch (Exception e) {
            throw new DocumentException(ErrorCodes.GET_COLLECTION_LIST_EXCEPTION, e.getMessage());
        }
        return result;
    }

}