All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.agent.crnickl.mongodb.MongoDB Maven / Gradle / Ivy

There is a newer version: 2.0.1
Show newest version
/*
 *   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 nameVT = db.createValueType("name", false, "NAME");
		nameVT.applyUpdates();
		UpdatableValueType> typeVT = db.createValueType("type", true, "TYPE");
		typeVT.applyUpdates();
		UpdatableValueType 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 binaryVT = db.createValueType("binary", false, "BOOLEAN");
		binaryVT.applyUpdates();
		
		UpdatableProperty symbolProp = db.createProperty("Symbol", nameVT, false);
		symbolProp.applyUpdates();
		UpdatableProperty> typeProp = db.createProperty("Type", typeVT, false);
		typeProp.applyUpdates();
		UpdatableProperty calendarProp = db.createProperty("Calendar", tdVT, false);
		calendarProp.applyUpdates();
		UpdatableProperty 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());
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy