ch.agent.crnickl.mongodb.MongoDB.java Source code

Java tutorial

Introduction

Here is the source code for ch.agent.crnickl.mongodb.MongoDB.java

Source

/*
 *   Copyright 2012-2013 Hauser Olsson GmbH
 *
 * 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 ch.agent.crnickl.mongodb;

import ch.agent.crnickl.T2DBException;
import ch.agent.crnickl.T2DBMsg;
import ch.agent.crnickl.T2DBMsg.E;
import ch.agent.crnickl.api.Database;
import ch.agent.crnickl.api.DatabaseConfiguration;
import ch.agent.crnickl.api.Surrogate;
import ch.agent.crnickl.api.UpdatableProperty;
import ch.agent.crnickl.api.UpdatableValueType;
import ch.agent.crnickl.api.ValueType;
import ch.agent.crnickl.mongodb.T2DBMMsg.J;
import ch.agent.t2.time.DateTime;
import ch.agent.t2.time.Day;
import ch.agent.t2.time.Month;
import ch.agent.t2.time.TimeDomain;
import ch.agent.t2.time.Workday;
import ch.agent.t2.time.Year;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.WriteConcern;

/**
 * MongoDB is a singleton encapsulating the MongoDB connection and the 
 * base collections used by CrNiCKL.
 * 
 * @author Jean-Paul Vetterli
 */
public class MongoDB {

    private static class Singleton {
        private static MongoDB mongo_connection;
        static {
            mongo_connection = new MongoDB();
        };
    }

    private enum WriteConcernKeyword {
        NONE, NORMAL, SAFE, MAJORITY, FSYNC_SAFE, JOURNAL_SAFE, REPLICAS_SAFE
    }

    private DatabaseConfiguration configuration;
    private Mongo connection = null;
    private DBCollection properties;
    private DBCollection valueTypes;
    private DBCollection schemas;
    private DBCollection chronicles;
    private DBCollection series;
    private DBCollection attributes;
    private String user;

    public static final String MONGODB_HOST = "mongodb.host";
    public static final String MONGODB_PORT = "mongodb.port";
    public static final String MONGODB_DB = "mongodb.db";
    public static final String MONGODB_WRITE_CONCERN = "mongodb.writeConcern";
    public static final String MONGODB_USER = "mongodb.user";
    public static final String MONGODB_PASSWORD = "mongodb.password";

    private MongoDB() {
    }

    /**
     * Construct a MongoDB session. This constructor can be invoked only once.
     * 
     * @param configuration a database configuration
     */
    public MongoDB(Database database, DatabaseConfiguration configuration) throws T2DBException {
        if (Singleton.mongo_connection.configuration != null)
            throw new IllegalStateException("already initialized");
        Singleton.mongo_connection.configuration = configuration;
        Singleton.mongo_connection.open(database);
    }

    /**
     * Return the MongoDB connection.
     * 
     * @return the MongoDB connection
     */
    public static MongoDB getInstance() {
        if (Singleton.mongo_connection.configuration == null)
            throw new IllegalStateException("not initialized");
        return Singleton.mongo_connection;
    }

    private void open(Database database) throws T2DBException {
        try {
            String host = configuration.getParameter(MONGODB_HOST, false);
            String port = configuration.getParameter(MONGODB_PORT, false);

            if (host != null) {
                if (port != null) {
                    connection = new Mongo(host, Integer.parseInt(port));
                } else {
                    connection = new Mongo(host);
                }
            } else {
                connection = new Mongo();
            }

            initialize(connection, database);

            // TODO: implement secure mode
            user = configuration.getParameter(MONGODB_USER, true);
            configuration.getParameter(MONGODB_PASSWORD, true);
            configuration.setParameter(MONGODB_USER, "zzzzz");
            configuration.setParameter(MONGODB_PASSWORD, "zzzzz");
        } catch (Exception e) {
            throw T2DBMMsg.exception(e, J.J80050, toString());
        }
    }

    private WriteConcern getWriteConcernFromKeyword(String keyword) throws T2DBException {
        WriteConcern wc = null;
        if (keyword == null)
            keyword = "SAFE";
        WriteConcernKeyword k = null;
        try {
            k = WriteConcernKeyword.valueOf(keyword);
        } catch (IllegalArgumentException e) {
            throw T2DBMMsg.exception(e, J.J81020, keyword);
        }
        switch (k) {
        case NONE:
            wc = WriteConcern.NONE;
            break;
        case NORMAL:
            wc = WriteConcern.NORMAL;
            break;
        case SAFE:
            wc = WriteConcern.SAFE;
            break;
        case MAJORITY:
            wc = WriteConcern.MAJORITY;
            break;
        case FSYNC_SAFE:
            wc = WriteConcern.FSYNC_SAFE;
            break;
        case JOURNAL_SAFE:
            wc = WriteConcern.JOURNAL_SAFE;
            break;
        case REPLICAS_SAFE:
            wc = WriteConcern.REPLICAS_SAFE;
            break;
        default:
            throw new RuntimeException("bug: " + k.name());
        }
        if (wc != WriteConcern.SAFE)
            throw T2DBMMsg.exception(J.J81021, keyword);
        return wc;
    }

    private void initialize(Mongo mongo, Database database) throws T2DBException {
        DB db = mongo.getDB(configuration.getParameter(MONGODB_DB, true));
        db.setWriteConcern(getWriteConcernFromKeyword(configuration.getParameter(MONGODB_WRITE_CONCERN, false)));
        if (!db.collectionExists(MongoDatabase.COLL_VT)) {
            valueTypes = createCollection(db, MongoDatabase.COLL_VT, MongoDatabase.FLD_VT_NAME);
            properties = createCollection(db, MongoDatabase.COLL_PROP, MongoDatabase.FLD_PROP_NAME);
            schemas = createCollection(db, MongoDatabase.COLL_SCHEMA, MongoDatabase.FLD_SCHEMA_NAME);
            chronicles = createCollection(db, MongoDatabase.COLL_CHRON, MongoDatabase.FLD_CHRON_PARENT,
                    MongoDatabase.FLD_CHRON_NAME);
            series = createCollection(db, MongoDatabase.COLL_SER, MongoDatabase.FLD_SER_CHRON,
                    MongoDatabase.FLD_SER_NUM);
            /* can't index on variable keys ... this is yet another NO GO for MONGO)
            createIndex(series, MongoDatabase.FLD_SER_CHRON, MongoDatabase.FLD_SER_NUM, 
                  MongoDatabase.FLD_SER_VALUES ... errr); */
            attributes = createCollection(db, MongoDatabase.COLL_ATTR, MongoDatabase.FLD_ATTR_CHRON,
                    MongoDatabase.FLD_ATTR_PROP);
            createIndex(attributes, MongoDatabase.FLD_ATTR_PROP, MongoDatabase.FLD_ATTR_VALUE);
            createBuiltInValueTypes(database);
        } else {
            valueTypes = db.getCollection(MongoDatabase.COLL_VT);
            properties = db.getCollection(MongoDatabase.COLL_PROP);
            schemas = db.getCollection(MongoDatabase.COLL_SCHEMA);
            chronicles = db.getCollection(MongoDatabase.COLL_CHRON);
            series = db.getCollection(MongoDatabase.COLL_SER);
            attributes = db.getCollection(MongoDatabase.COLL_ATTR);
        }
    }

    private void createBuiltInValueTypes(Database db) throws T2DBException {
        UpdatableValueType<String> nameVT = db.createValueType("name", false, "NAME");
        nameVT.applyUpdates();
        UpdatableValueType<ValueType<?>> typeVT = db.createValueType("type", true, "TYPE");
        typeVT.applyUpdates();
        UpdatableValueType<TimeDomain> tdVT = db.createValueType("timedomain", true, "TIMEDOMAIN");
        tdVT.addValue(Day.DOMAIN, "daily");
        tdVT.addValue(DateTime.DOMAIN, "date and time with second precision");
        tdVT.addValue(Month.DOMAIN, "monthly");
        tdVT.addValue(Workday.DOMAIN, "working days Monday-Friday");
        tdVT.addValue(Year.DOMAIN, "yearly");
        tdVT.applyUpdates();
        UpdatableValueType<Boolean> binaryVT = db.createValueType("binary", false, "BOOLEAN");
        binaryVT.applyUpdates();

        UpdatableProperty<String> symbolProp = db.createProperty("Symbol", nameVT, false);
        symbolProp.applyUpdates();
        UpdatableProperty<ValueType<?>> typeProp = db.createProperty("Type", typeVT, false);
        typeProp.applyUpdates();
        UpdatableProperty<TimeDomain> calendarProp = db.createProperty("Calendar", tdVT, false);
        calendarProp.applyUpdates();
        UpdatableProperty<Boolean> sparseProp = db.createProperty("Sparsity", binaryVT, false);
        sparseProp.applyUpdates();
    }

    private DBCollection createCollection(DB db, String name, String... keys) throws T2DBException {
        DBCollection coll = db.getCollection(name);
        if (keys.length > 0) {
            DBObject index = new BasicDBObject();
            DBObject options = new BasicDBObject();
            for (String key : keys) {
                index.put(key, 1);
            }
            options.put("unique", 1);
            coll.ensureIndex(index, options);
        }
        return coll;
    }

    private void createIndex(DBCollection coll, String... keys) throws T2DBException {
        if (keys.length > 0) {
            DBObject index = new BasicDBObject();
            for (String key : keys)
                index.put(key, 1);
            coll.ensureIndex(index);
        }
    }

    /**
     * Close the MongoDB connection if it is open.
     */
    public void close(boolean ignoreException) throws T2DBException {
        try {
            if (connection != null)
                connection.close();
            connection = null;
        } catch (Exception e) {
            if (!ignoreException)
                throw T2DBMsg.exception(E.E00110, toString());
        }
    }

    /**
     * Operation not supported by MongoDB.
     * Always throws an exception.
     * 
     * @throws T2DBException
     */
    public void commit() throws T2DBException {
        throw T2DBMMsg.exception(J.J80100);
    }

    /**
     * Operation not supported by MongoDB.
     * Always throws an exception.
     * 
     * @throws T2DBException
     */
    public void rollback() throws T2DBException {
        throw T2DBMMsg.exception(J.J80100);
    }

    public String getUser() {
        return user;
    }

    public DBCollection getValueTypes() {
        return valueTypes;
    }

    public DBCollection getProperties() {
        return properties;
    }

    public DBCollection getSchemas() {
        return schemas;
    }

    public DBCollection getChronicles() {
        return chronicles;
    }

    public DBCollection getSeries() {
        return series;
    }

    public DBCollection getAttributes() {
        return attributes;
    }

    public DBCollection getCollection(Surrogate s) throws T2DBException {
        switch (s.getDBObjectType()) {
        case CHRONICLE:
            return chronicles;
        case SERIES:
            return series;
        case SCHEMA:
            return schemas;
        case PROPERTY:
            return properties;
        case VALUE_TYPE:
            return valueTypes;
        default:
            throw new RuntimeException("bug " + s.getDBObjectType());
        }
    }

    /**
     * Return a string displaying the session with the connection and the user id.
     * 
     * @return a string displaying the session
     */
    @Override
    public String toString() {
        return String.format("%s@%s", user, connection.toString());
    }

}