org.obiba.magma.datasource.mongodb.MongoDBDatasource.java Source code

Java tutorial

Introduction

Here is the source code for org.obiba.magma.datasource.mongodb.MongoDBDatasource.java

Source

/*
 * Copyright (c) 2013 OBiBa. All rights reserved.
 *
 * This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0.
 *
 * 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 org.obiba.magma.datasource.mongodb;

import java.util.Date;
import java.util.Set;

import javax.validation.constraints.NotNull;

import org.bson.BSONObject;
import org.obiba.magma.MagmaRuntimeException;
import org.obiba.magma.Timestamped;
import org.obiba.magma.Timestamps;
import org.obiba.magma.Value;
import org.obiba.magma.ValueTable;
import org.obiba.magma.ValueTableWriter;
import org.obiba.magma.support.AbstractDatasource;
import org.obiba.magma.support.Initialisables;
import org.obiba.magma.support.UnionTimestamps;
import org.obiba.magma.type.DateTimeType;

import com.google.common.collect.ImmutableSet;
import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.WriteConcern;

public class MongoDBDatasource extends AbstractDatasource {

    public static final String TYPE = "mongodb";

    static final String TIMESTAMPS_FIELD = "_timestamps";

    static final String TIMESTAMPS_CREATED_FIELD = "created";

    static final String TIMESTAMPS_UPDATED_FIELD = "updated";

    private static final String DATASOURCE_COLLECTION = "datasource";

    private static final String VALUE_TABLE_COLLECTION = "value_table";

    @NotNull
    private final MongoDBFactory mongoDBFactory;

    private DBObject dbObject;

    /**
     * See <a href="http://docs.mongodb.org/manual/reference/connection-string">MongoDB connection string specifications</a>.
     *
     * @param name
     * @param mongoURI
     */
    public MongoDBDatasource(@NotNull String name, @NotNull MongoDBFactory mongoDBFactory) {
        super(name, TYPE);
        this.mongoDBFactory = mongoDBFactory;
    }

    @NotNull
    MongoDBFactory getMongoDBFactory() {
        return mongoDBFactory;
    }

    DBCollection getValueTableCollection() {
        return mongoDBFactory.execute(new MongoDBFactory.MongoDBCallback<DBCollection>() {
            @Override
            public DBCollection doWithDB(DB db) {
                DBCollection collection = db.getCollection(VALUE_TABLE_COLLECTION);
                collection.ensureIndex("datasource");
                collection.ensureIndex("name");
                return collection;
            }
        });
    }

    DBCollection getDatasourceCollection() {
        return mongoDBFactory.execute(new MongoDBFactory.MongoDBCallback<DBCollection>() {
            @Override
            public DBCollection doWithDB(DB db) {
                DBCollection collection = db.getCollection(DATASOURCE_COLLECTION);
                collection.ensureIndex("name");
                return collection;
            }
        });
    }

    DBObject asDBObject() {
        if (dbObject == null) {
            dbObject = getDatasourceCollection().findOne(BasicDBObjectBuilder.start() //
                    .add("name", getName()) //
                    .get());
            if (dbObject == null) {
                dbObject = BasicDBObjectBuilder.start() //
                        .add("name", getName()) //
                        .add(TIMESTAMPS_FIELD, createTimestampsObject()).get();
                getDatasourceCollection().insert(dbObject, WriteConcern.ACKNOWLEDGED);
            }
        }
        return dbObject;
    }

    void setLastUpdate(Date date) {
        ((BSONObject) asDBObject().get(TIMESTAMPS_FIELD)).put("updated", date);
        getDatasourceCollection().save(asDBObject());

    }

    static DBObject createTimestampsObject() {
        return BasicDBObjectBuilder.start() //
                .add(TIMESTAMPS_CREATED_FIELD, new Date()) //
                .add(TIMESTAMPS_UPDATED_FIELD, new Date()).get();
    }

    @Override
    protected void onInitialise() {
        mongoDBFactory.getMongoClient();
    }

    @Override
    protected void onDispose() {
        mongoDBFactory.close();
    }

    @Override
    public boolean canDropTable(String tableName) {
        return hasValueTable(tableName);
    }

    @Override
    public void dropTable(@NotNull String tableName) {
        MongoDBValueTable valueTable = (MongoDBValueTable) getValueTable(tableName);
        valueTable.drop();
        removeValueTable(tableName);
    }

    @Override
    public boolean canRenameTable(String tableName) {
        return hasValueTable(tableName);
    }

    @Override
    public void renameTable(String tableName, String newName) {
        if (hasValueTable(newName))
            throw new MagmaRuntimeException("A table already exists with the name: " + newName);

        MongoDBValueTable valueTable = (MongoDBValueTable) getValueTable(tableName);

        valueTable.asDBObject().put("name", newName);
        ((BSONObject) valueTable.asDBObject().get(TIMESTAMPS_FIELD)).put("updated", new Date());
        getValueTableCollection().save(valueTable.asDBObject(), WriteConcern.ACKNOWLEDGED);
        removeValueTable(valueTable);

        MongoDBValueTable newTable = new MongoDBValueTable(this, newName);
        Initialisables.initialise(newTable);
        addValueTable(newTable);
    }

    @Override
    @SuppressWarnings("MethodReturnAlwaysConstant")
    public boolean canDrop() {
        return true;
    }

    @Override
    public void drop() {
        for (String name : getValueTableNames()) {
            dropTable(name);
        }
        getDatasourceCollection().remove(BasicDBObjectBuilder.start().add("_id", getName()).get());
    }

    @NotNull
    @Override
    public ValueTableWriter createWriter(@NotNull String tableName, @NotNull String entityType) {
        MongoDBValueTable valueTable = null;
        if (getValueTableNames().isEmpty()) {
            // make sure datasource document exists
            asDBObject();
        }
        if (hasValueTable(tableName)) {
            valueTable = (MongoDBValueTable) getValueTable(tableName);
        } else {
            addValueTable(valueTable = new MongoDBValueTable(this, tableName, entityType));
            setLastUpdate(new Date());
        }
        return new MongoDBValueTableWriter(valueTable);
    }

    @Override
    protected Set<String> getValueTableNames() {
        ImmutableSet.Builder<String> builder = ImmutableSet.builder();
        try (DBCursor cursor = getValueTableCollection().find(
                BasicDBObjectBuilder.start().add("datasource", asDBObject().get("_id")).get(),
                BasicDBObjectBuilder.start().add("name", 1).get())) {
            while (cursor.hasNext()) {
                builder.add(cursor.next().get("name").toString());
            }
        }
        return builder.build();
    }

    @Override
    protected ValueTable initialiseValueTable(String tableName) {
        return new MongoDBValueTable(this, tableName);
    }

    @NotNull
    @Override
    public Timestamps getTimestamps() {
        ImmutableSet.Builder<Timestamped> builder = ImmutableSet.builder();
        builder.addAll(getValueTables()).add(new MongoDBDatasourceTimestamped());
        return new UnionTimestamps(builder.build());
    }

    private class MongoDBDatasourceTimestamped implements Timestamped {
        @NotNull
        @Override
        public Timestamps getTimestamps() {

            return new Timestamps() {

                private final BSONObject timestampsObject = (BSONObject) asDBObject().get(TIMESTAMPS_FIELD);

                @NotNull
                @Override
                public Value getLastUpdate() {
                    return DateTimeType.get().valueOf(timestampsObject.get(TIMESTAMPS_UPDATED_FIELD));
                }

                @NotNull
                @Override
                public Value getCreated() {
                    return DateTimeType.get().valueOf(timestampsObject.get(TIMESTAMPS_CREATED_FIELD));
                }
            };
        }
    }
}