org.eclipselabs.mongoemf.handlers.MongoURIHandlerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipselabs.mongoemf.handlers.MongoURIHandlerImpl.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Bryan Hunt & Ed Merks.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Bryan Hunt & Ed Merks - initial API and implementation
 *******************************************************************************/

package org.eclipselabs.mongoemf.handlers;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.impl.URIHandlerImpl;
import org.eclipselabs.emongo.MongoDatabaseProvider;
import org.eclipselabs.mongoemf.InputStreamFactory;
import org.eclipselabs.mongoemf.Keywords;
import org.eclipselabs.mongoemf.MongoUtils;
import org.eclipselabs.mongoemf.Options;
import org.eclipselabs.mongoemf.OutputStreamFactory;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.ReadPreference;

/**
 * This EMF URI handler interfaces to MongoDB. This URI handler can handle URIs with the "mongodb"
 * scheme. The URI path must have exactly 3 segments and be of the form /database/collection/{id}
 * where id is optional the first time the EMF object is saved. When building queries, do not
 * specify an id, but make sure path has 3 segments by placing a "/" after the collection.
 * 
 * Note that if the id is not specified when the object is first saved, MongoDB will assign the id
 * and the URI of the EMF Resource will be modified to include the id in the URI. Examples of valid
 * URIs:
 * 
 * mongodb://localhost/data/people/
 * mongodb://localhost/data/people/4d0a3e259095b5b334a59df0
 * 
 * This class is intended to be used with the IResourceSetFactory service. If you are not using the
 * factory service, you will have to supply instances of IMongoLocator, IIntputStreamFActory, and
 * IOutputStreamFactory.
 * 
 * @author bhunt
 * 
 */
public class MongoURIHandlerImpl extends URIHandlerImpl {
    /**
     * 
     * @param databaseLocator an instance of the mongo locator service
     * @param inputStreamFactory an instance of the input stream factory service
     * @param outputStreamFactory an instance of the output stream factory service
     */
    public MongoURIHandlerImpl(Map<String, MongoDatabaseProvider> mongoDatabaseProviders,
            InputStreamFactory inputStreamFactory, OutputStreamFactory outputStreamFactory) {

        this.mongoDatabaseProviders = mongoDatabaseProviders;
        this.inputStreamFactory = inputStreamFactory;
        this.outputStreamFactory = outputStreamFactory;
    }

    @Override
    public boolean canHandle(URI uri) {
        // This handler should only accept URIs with the scheme "mongodb"

        return "mongodb".equalsIgnoreCase(uri.scheme());
    }

    @Override
    public OutputStream createOutputStream(final URI uri, final Map<?, ?> options) throws IOException {
        // This function may be called with a URI path with or without an id. If an id is not specified
        // the EMF resource URI will be modified to include the id generated by MongoDB.

        return outputStreamFactory.createOutputStream(uri, options, getCollection(uri, options),
                getResponse(options));
    }

    @Override
    public InputStream createInputStream(final URI uri, final Map<?, ?> options) throws IOException {
        return inputStreamFactory.createInputStream(uri, options, getCollection(uri, options),
                getResponse(options));
    }

    @Override
    public void delete(URI uri, Map<?, ?> options) throws IOException {
        // It is assumed that delete is called with the URI path /database/collection/id

        DBCollection collection = getCollection(uri, options);
        collection.findAndRemove(new BasicDBObject(Keywords.ID_KEY, MongoUtils.getID(uri)));
    }

    @Override
    public boolean exists(URI uri, Map<?, ?> options) {
        if (uri.query() != null)
            return false;

        try {
            DBCollection collection = getCollection(uri, options);
            return collection.findOne(new BasicDBObject(Keywords.ID_KEY, MongoUtils.getID(uri))) != null;
        } catch (Throwable exception) {
            return false;
        }
    }

    /**
     * This function locates the MongoDB collection instance corresponding to the collection
     * identifier extracted from the URI. The URI path must have exactly 3 segments and be of the form
     * mongodb://host:[port]/database/collection/{id} where id is optional.
     * 
     * @param uri the MongoDB collection identifier
     * @param options the load or save options as appropriate
     * @return the MongoDB collection corresponding to the URI
     * @throws IOException if the URI is malformed or the collection could not otherwise be resolved
     */
    private DBCollection getCollection(URI uri, Map<?, ?> options) throws IOException {
        // We assume that the URI path has the form /database/collection/{id} making the
        // collection segment # 1.

        if (uri.segmentCount() != 3)
            throw new IOException("The URI is not of the form 'mongodb:/database/collection/{id}");

        MongoDatabaseProvider mongoDatabaseProvider = mongoDatabaseProviders
                .get(uri.trimQuery().trimFragment().trimSegments(2).toString());

        if (mongoDatabaseProvider == null)
            throw new IOException("Database is not available");

        DB database = mongoDatabaseProvider.getDB();

        if (database == null)
            throw new IOException("Database is not available");

        DBCollection dbCollection = database.getCollection(uri.segment(1));

        ReadPreference readPreference = (ReadPreference) options.get(Options.OPTION_READ_PREFERENCE);

        if (readPreference != null)
            dbCollection.setReadPreference(readPreference);

        return dbCollection;
    }

    private Map<String, MongoDatabaseProvider> mongoDatabaseProviders;
    private InputStreamFactory inputStreamFactory;
    private OutputStreamFactory outputStreamFactory;
}