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

Java tutorial

Introduction

Here is the source code for org.obiba.magma.datasource.mongodb.MongoDBValueTable.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.Iterator;
import java.util.Map;
import java.util.SortedSet;

import javax.annotation.Nullable;
import javax.validation.constraints.NotNull;

import org.bson.BSONObject;
import org.bson.types.ObjectId;
import org.obiba.magma.Datasource;
import org.obiba.magma.NoSuchValueSetException;
import org.obiba.magma.Timestamps;
import org.obiba.magma.TimestampsBean;
import org.obiba.magma.Value;
import org.obiba.magma.ValueSet;
import org.obiba.magma.VariableEntity;
import org.obiba.magma.VariableValueSource;
import org.obiba.magma.datasource.mongodb.converter.ValueConverter;
import org.obiba.magma.support.AbstractValueTable;
import org.obiba.magma.support.NullTimestamps;
import org.obiba.magma.type.DateTimeType;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
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;
import com.mongodb.gridfs.GridFS;

public class MongoDBValueTable extends AbstractValueTable {

    private static final String VARIABLE_SUFFIX = "_variable";

    private static final String VALUE_SET_SUFFIX = "_value_set";

    private DBObject dbObject;

    public MongoDBValueTable(@NotNull Datasource datasource, @NotNull String name) {
        this(datasource, name, null);
    }

    public MongoDBValueTable(@NotNull Datasource datasource, @NotNull String name, @Nullable String entityType) {
        super(datasource, name);
        setVariableEntityProvider(new MongoDBVariableEntityProvider(this, entityType));
        // ensure corresponding document is stored
        asDBObject();
    }

    MongoDBFactory getMongoDBFactory() {
        return getMongoDBDatasource().getMongoDBFactory();
    }

    DBCollection getValueTableCollection() {
        return getMongoDBDatasource().getValueTableCollection();
    }

    DBCollection getVariablesCollection() {
        return getMongoDBFactory().execute(new MongoDBFactory.MongoDBCallback<DBCollection>() {
            @Override
            public DBCollection doWithDB(DB db) {
                DBCollection collection = db.getCollection(getId() + VARIABLE_SUFFIX);
                collection.ensureIndex("name");
                return collection;
            }
        });
    }

    DBCollection getValueSetCollection() {
        return getMongoDBFactory().execute(new MongoDBFactory.MongoDBCallback<DBCollection>() {
            @Override
            public DBCollection doWithDB(DB db) {
                return db.getCollection(getId() + VALUE_SET_SUFFIX);
            }
        });
    }

    DBObject asDBObject() {
        if (dbObject == null) {
            dbObject = getValueTableCollection().findOne(BasicDBObjectBuilder.start() //
                    .add("datasource", getMongoDBDatasource().asDBObject().get("_id")) //
                    .add("name", getName()) //
                    .get());
            // create DBObject if not found
            if (dbObject == null) {
                dbObject = BasicDBObjectBuilder.start() //
                        .add("datasource", getMongoDBDatasource().asDBObject().get("_id")) //
                        .add("name", getName()) //
                        .add("entityType", getEntityType()) //
                        .add(MongoDBDatasource.TIMESTAMPS_FIELD, MongoDBDatasource.createTimestampsObject()).get();
                getValueTableCollection().insert(dbObject, WriteConcern.ACKNOWLEDGED);
            }
        }
        return dbObject;
    }

    void setLastUpdate(Date date) {
        ((BSONObject) asDBObject().get(MongoDBDatasource.TIMESTAMPS_FIELD)).put("updated", date);
        getValueTableCollection().save(asDBObject());
        getMongoDBDatasource().setLastUpdate(date);
    }

    private String getId() {
        return asDBObject().get("_id").toString();
    }

    private ObjectId getIdAsObjectId() {
        return new ObjectId(getId());
    }

    @Override
    protected void addVariableValueSource(VariableValueSource source) {
        super.addVariableValueSource(source);
    }

    @Override
    protected void removeVariableValueSource(String variableName) {
        super.removeVariableValueSource(variableName);
    }

    @Override
    public void initialise() {
        addVariableValueSources(new MongoDBVariableValueSourceFactory(this));
        super.initialise();
    }

    @Override
    public Timestamps getValueSetTimestamps(VariableEntity entity) throws NoSuchValueSetException {
        if (!hasValueSet(entity)) {
            throw new NoSuchValueSetException(this, entity);
        }
        return super.getValueSetTimestamps(entity);
    }

    @Override
    public Iterable<Timestamps> getValueSetTimestamps(final SortedSet<VariableEntity> entities) {

        if (entities.isEmpty()) {
            return ImmutableList.of();
        }
        return new Iterable<Timestamps>() {
            @Override
            public Iterator<Timestamps> iterator() {
                return new TimestampsIterator(entities.iterator());
            }
        };
    }

    @Override
    public ValueSet getValueSet(VariableEntity entity) throws NoSuchValueSetException {
        if (!hasValueSet(entity)) {
            throw new NoSuchValueSetException(this, entity);
        }
        return new MongoDBValueSet(this, entity);
    }

    @NotNull
    @Override
    public Timestamps getTimestamps() {
        return new Timestamps() {

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

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

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

    public void drop() {
        // drop associated collections
        dropFiles();
        getValueSetCollection().drop();
        getVariablesCollection().drop();
        getValueTableCollection().remove(BasicDBObjectBuilder.start().add("_id", getIdAsObjectId()).get());
        getMongoDBDatasource().setLastUpdate(new Date());
        dbObject = null;
    }

    DBObject findVariable(String variableName) {
        return getVariablesCollection().findOne(BasicDBObjectBuilder.start("name", variableName).get());
    }

    @Override
    public int getVariableCount() {
        return (int) getVariablesCollection().count();
    }

    @Override
    public int getValueSetCount() {
        return (int) getValueSetCollection().count();
    }

    @Override
    public int getVariableEntityCount() {
        return (int) getValueSetCollection().count();
    }

    @Override
    public boolean canDropValueSets() {
        return true;
    }

    @Override
    public void dropValueSets() {
        dropFiles();
        getValueSetCollection().drop();
        setLastUpdate(new Date());
    }

    private MongoDBDatasource getMongoDBDatasource() {
        return ((MongoDBDatasource) getDatasource());
    }

    /**
     * Drop the files from the {@link com.mongodb.gridfs.GridFS} for this table.
     */
    private void dropFiles() {
        GridFS gridFS = getMongoDBDatasource().getMongoDBFactory().getGridFS();
        BasicDBObjectBuilder metaDataQuery = BasicDBObjectBuilder.start() //
                .add("metadata.datasource", getDatasource().getName()) //
                .add("metadata.table", getName());
        gridFS.remove(metaDataQuery.get());
    }

    private class TimestampsIterator implements Iterator<Timestamps> {

        private final Iterator<VariableEntity> entities;

        private final DBCursor cursor;

        private final Map<String, Timestamps> timestampsMap = Maps.newHashMap();

        private TimestampsIterator(Iterator<VariableEntity> entities) {
            this.entities = entities;
            DBObject fields = BasicDBObjectBuilder.start(MongoDBDatasource.TIMESTAMPS_FIELD, 1).get();
            cursor = getValueSetCollection().find(new BasicDBObject(), fields);
        }

        @Override
        public boolean hasNext() {
            return entities.hasNext();
        }

        @Override
        public Timestamps next() {
            VariableEntity entity = entities.next();

            if (timestampsMap.containsKey(entity.getIdentifier()))
                return getTimestampsFromMap(entity);

            boolean found = false;
            while (cursor.hasNext() && !found) {
                DBObject obj = cursor.next();
                String id = obj.get("_id").toString();
                BSONObject timestamps = (BSONObject) obj.get(MongoDBDatasource.TIMESTAMPS_FIELD);
                timestampsMap.put(id,
                        new TimestampsBean(ValueConverter.unmarshall(DateTimeType.get(), timestamps.get("created")),
                                ValueConverter.unmarshall(DateTimeType.get(), timestamps.get("updated"))));
                found = id.equals(entity.getIdentifier());
            }

            if (timestampsMap.containsKey(entity.getIdentifier()))
                return getTimestampsFromMap(entity);
            return NullTimestamps.get();
        }

        /**
         * No duplicate of entities, so remove timestamps from map once get.
         *
         * @param entity
         * @return
         */
        private Timestamps getTimestampsFromMap(VariableEntity entity) {
            Timestamps value = timestampsMap.get(entity.getIdentifier());
            timestampsMap.remove(entity.getIdentifier());
            return value;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}