org.eclipse.linuxtools.tmf.totalads.dbms.DBMS.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.linuxtools.tmf.totalads.dbms.DBMS.java

Source

/*********************************************************************************************
 * Copyright (c) 2014  Software Behaviour Analysis Lab, Concordia University, Montreal, Canada
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of XYZ License which
 * accompanies this distribution, and is available at xyz.com/license
 *
 * Contributors:
 *    Syed Shariyar Murtaza
 **********************************************************************************************/
package org.eclipse.linuxtools.tmf.totalads.dbms;

import org.eclipse.linuxtools.tmf.totalads.exceptions.TotalADSDBMSException;
import org.eclipse.linuxtools.tmf.totalads.exceptions.TotalADSUIException;
//import org.eclipse.linuxtools.tmf.totalads.ui.ksm.*;

import java.lang.reflect.Field;
import java.net.ConnectException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import com.google.gson.JsonObject;
import com.mongodb.BasicDBObject;
import com.mongodb.CommandResult;
import com.mongodb.DB;
import com.mongodb.DBAddress;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import com.mongodb.MongoException;
import com.mongodb.WriteConcern;
import com.mongodb.WriteResult;
import com.mongodb.util.JSON;

/**
 * Database Management System (DBMS) class. This calss connects with MongoDB,
 * and performs  the manipulations required in a program with MongoDB 
 *  
 * @author <p> Syed Shariyar Murtaza justsshary@hotmail.com </p>
 *
 */
public class DBMS implements ISubject {

    private MongoClient mongoClient;
    private Boolean isConnected = false;
    private ArrayList<IObserver> observers;

    /**
     * Constructor
     */
    public DBMS() {
        observers = new ArrayList<IObserver>();
    }

    /**
     * Connects with MongoDB
     * @param host Host name 
     * @param port Port number
     * @return Returns an empty message if connection is made with the database, else returns the error message
     * @throws UnknownHostException
     */
    public String connect(String host, Integer port) {
        String message = "";
        try {
            if (isConnected) // Don't open multiple connections
                closeConnection();

            mongoClient = new MongoClient(host, port);
            mongoClient.setWriteConcern(WriteConcern.JOURNALED);

            mongoClient.getDatabaseNames(); // if this doesn't work then there is no running DB. 
            // Unfortunately,mongoClient doesn't tell whether there is a DB or not
        } catch (UnknownHostException ex) {
            isConnected = false;
            message = ex.getMessage();
            notifyObservers();
            return message;
        } catch (Exception ex) { // Just capture an exception and don't let the system crash when db is not there
            isConnected = false;
            message = "Unable to connect to MongoDB.";
            notifyObservers();
            return message;
        }

        isConnected = true;// if it reaches here then it is connected
        notifyObservers();
        return message;

    }

    /**
     * Connects with MongoDB using authentication mecahinsm
     * @param host Host name
     * @param port Port name
     * @param username User name
     * @param password Password
     * @return Empty message if connected or error message
     * @throws UnknownHostException
     */
    public String connect(String host, Integer port, String username, String password, String database) {

        String message = "";
        try {
            if (isConnected) // Don't open multiple connections
                closeConnection();

            mongoClient = new MongoClient(host, port);
            mongoClient.setWriteConcern(WriteConcern.JOURNALED);

            mongoClient.getDatabaseNames(); // if this doesn't work then there is no running DB. 
            // Unfortunately,mongoClient doesn't tell whether there is a DB or not
        } catch (UnknownHostException ex) {
            isConnected = false;
            message = ex.getMessage();
            //notifyObservers();
            //return message;
        } catch (Exception ex) { // Just capture an exception and don't let the system crash when db is not there
            isConnected = false;
            message = "Unable to connect to MongoDB.";
            //notifyObservers();
            //return message;
        } finally {

            if (message.isEmpty()) {
                // if there is a running db then check this
                DB db = mongoClient.getDB(database);

                if (db.authenticate(username, password.toCharArray()) == false) {
                    isConnected = false;
                    message = "Authentication failed with MongoDB using user id " + username + " and database "
                            + database + ".";
                } else {
                    isConnected = true;// if it reaches here then everything is fine

                }
            }
            notifyObservers();

        }
        return message;
    }

    /**
     * Determines the connected state
     * @return true or false
     */
    public Boolean isConnected() {
        return isConnected;
    }

    /**
     * Get database list
     * @return The list of database
     */
    public List<String> getDatabaseList() {
        List<String> dbList = mongoClient.getDatabaseNames();
        // remove system databases
        dbList.remove("admin");
        dbList.remove("local");
        return dbList;

    }

    /**
     * Checks the existence of the database
     * @param database
     * @return
     */
    public boolean datbaseExists(String database) {
        List<String> databaseNames = getDatabaseList();

        for (int j = 0; j < databaseNames.size(); j++) // For comparison, we have to iterate manually
            if (databaseNames.get(j).equals(database))
                return true;
        return false;

    }

    /**
     * Creates a database and all collections in it
     * @param dataBase Database name
     * @param collectionNames Array of collection names
     * @throws TotalADSDBMSException
     */
    public void createDatabase(String dataBase, String[] collectionNames) throws TotalADSDBMSException {

        if (datbaseExists(dataBase)) {
            if (isConnected == false) {// This code sinppet is a check for the breakage of connection during the excution
                isConnected = true; // if reconnection occurs  during execution it will notify all obervers
                notifyObservers();
            }
            throw new TotalADSDBMSException("Database already exists!");

        }

        DB db = mongoClient.getDB(dataBase);
        DBObject options = com.mongodb.BasicDBObjectBuilder.start().add("capped", false).get();

        for (int j = 0; j < collectionNames.length; j++)
            db.createCollection(collectionNames[j], options);
        //db.createCollection(Configuration.settingsCollection, options);
        isConnected = true; // if this code is executed after the breakage of connection, make sure isConnected is true if it h
        notifyObservers();
    }

    /**
     * Creates an index on a collection (table)
     * @param database Database name
     * @param collection Collection name
     * @param field Field name on which to create an index
     */
    public void createAscendingIndex(String dataBase, String collection, String field) {
        DBCollection coll = mongoClient.getDB(dataBase).getCollection(collection);
        coll.createIndex(new BasicDBObject(field, 1));
    }

    /**
     * Close the connection
     */
    public void closeConnection() {
        isConnected = false;
        mongoClient.close();
    }

    /**
     * Deletes a database
     * @param database Database name
     */
    public void deleteDatabase(String database) {
        mongoClient.dropDatabase(database);
        notifyObservers();
    }

    /**
     * Extracts keys and values from public fields of a class's object using reflection and assign it
     * to the document object based on the data types
     * @param record Object from which to extract fields
     * @param document Document object in a collection which will store these fields and values
     * @throws IllegalAccessException 
     * @throws IllegalArgumentException 
     */
    private void extractKeysAndValuesfromTheObject(Object record, BasicDBObject document)
            throws IllegalArgumentException, IllegalAccessException {

        for (Field field : record.getClass().getDeclaredFields()) {

            String key = field.getName();
            field.setAccessible(true);
            if (field.getType() == String.class) {
                String val = (String) field.get(record);
                document.append(key, val);
            } else if (field.getType() == Integer.class) {
                Integer val = (Integer) field.get(record);
                document.append(key, val);
            } else if (field.getType() == Double.class) {
                Double val = (Double) field.get(record);
                document.append(key, val);
            } else if (field.getType() == Boolean.class) {
                Boolean val = (Boolean) field.get(record);
                document.append(key, val);
            }
        }
    }

    /**
     *  Insert an object's field with only one level of nesting. The object's class should  only
     *  have public data fields when calling this function. For example, create a class A{String b; Integer b},
     *  assign values after instantiating the object and pass it to the function
     * @param record Object from which to extract fields and values
     * @param database Database name
     * @param collection Collection name
     * @throws TotalADSDBMSException,
     * @throws IllegalAccessException
     * @throws IllegalAccessException
     */
    public void insert(Object record, String database, String collection)
            throws TotalADSDBMSException, IllegalAccessException, IllegalAccessException {

        WriteResult writeRes = null;
        String exception = "";
        DB db = mongoClient.getDB(database);
        DBCollection coll = db.getCollection(collection);

        BasicDBObject document = new BasicDBObject();
        extractKeysAndValuesfromTheObject(record, document);

        try {
            writeRes = coll.insert(document);
        } catch (MongoException e) {
            exception = "Caught MongoException cause: " + e.getMessage();
        }

        CommandResult cmdResult = writeRes.getLastError();
        if (!cmdResult.ok())
            exception += "\n error : " + cmdResult.getErrorMessage();

        if (!exception.isEmpty())
            throw new TotalADSDBMSException(exception);

    }

    /**
     * Inserts an object in the form of JSON representation into the database. Any kind of complex
     *  data structure can be converted to JSON  using gson library and passed to this function 
     * @param database Database name
     * @param jsonObject JSON Object
     * @param collection Collection name in which to insert 
     * @throws TotalADSDBMSException
     */
    public void insertUsingJSON(String database, JsonObject jsonObject, String collection)
            throws TotalADSDBMSException {
        try {
            DB db = mongoClient.getDB(database);
            DBCollection coll = db.getCollection(collection);
            BasicDBObject obj = (BasicDBObject) JSON.parse(jsonObject.toString());
            coll.insert(obj);
        } catch (Exception ex) { // If there is any exception here cast it as DBMS exception
            throw new TotalADSDBMSException(ex.getMessage());
        }
    }

    /**
     * Inserts or updates (if already exists) an object in the form of JSON representation into the database. Any kind of complex
     *  data structure can be converted to JSON using gson library and passed to this function 
     * @param database Database name
     * @param jsonObject JSON Object
     * @param collection collection name
     */
    public void insertOrUpdateUsingJSON(String database, JsonObject keytoSearch, JsonObject jsonObjectToUpdate,
            String collection) throws TotalADSDBMSException {
        DB db = mongoClient.getDB(database);
        DBCollection coll = db.getCollection(collection);

        BasicDBObject docToUpdate = (BasicDBObject) JSON.parse(jsonObjectToUpdate.toString());

        BasicDBObject keyToSearch = (BasicDBObject) JSON.parse(keytoSearch.toString());

        WriteResult writeRes = coll.update(keyToSearch, docToUpdate, true, false);

        CommandResult cmdResult = writeRes.getLastError();
        if (!cmdResult.ok())
            throw new TotalADSDBMSException("Error : " + cmdResult.getErrorMessage());

    }

    /**
     * Selects a max value from a collection (table)
     * @param key Field name to return the max of. Use an index key otherwise the results will be slow
     * @param database Database name
     * @param collection Collection name
     * @return Maximum value as a string
     */

    public String selectMax(String key, String database, String collection) {
        String maxVal = "";
        DB db = mongoClient.getDB(database);
        DBCollection coll = db.getCollection(collection);
        BasicDBObject query = new BasicDBObject(key, -1);
        DBCursor curs = coll.find().sort(query).limit(1);
        if (curs.hasNext())
            maxVal = curs.next().get(key).toString();
        curs.close();

        return maxVal;
    }

    /**
     * Returns a set of documents based on a key search
     * @param key Field name in the document of a collection. Should be an indexed key for faster processing.
     * @param operator Comparison operators if any. Leave it empty if exact match is needed
     * @param value Double value of the field
     * @param database Database name
     * @param collection Collection name in the database
     * @return A DBCursor object which you can iterate through
     */
    public DBCursor select(String key, String operator, Double value, String database, String collection) {
        DBCursor cursor;
        BasicDBObject query;

        DB db = mongoClient.getDB(database);
        DBCollection coll = db.getCollection(collection);

        if (operator == null || operator.isEmpty())
            query = new BasicDBObject(key, value);
        else
            query = new BasicDBObject(key, new BasicDBObject(operator, value));

        cursor = coll.find(query);
        if (!cursor.hasNext())
            cursor = null;
        return cursor;
    }

    /**
     * Returns a set of documents based on a key search
     * @param key Field name in the document of a collection. Should be an indexed key for faster processing.
     * @param operator Comparison operators if any. Leave it empty if exact match is needed
     * @param value String value of the field
     * @param database Database name
     * @param collection Collection name in the database
     * @return A DBCursor object which you can iterate through
     */
    public DBCursor select(String key, String operator, String value, String database, String collection) {
        DBCursor cursor;
        BasicDBObject query;

        DB db = mongoClient.getDB(database);
        DBCollection coll = db.getCollection(collection);

        if (operator == null || operator.isEmpty())
            query = new BasicDBObject(key, value);
        else
            query = new BasicDBObject(key, new BasicDBObject(operator, value));

        cursor = coll.find(query);
        if (!cursor.hasNext())
            cursor = null;
        return cursor;
    }

    /**
     * Selects all the documents as a DBCursor Object which can be used to iterate through them
     * @param database Database name
     * @param collection Collection name
     * @return DBCursor object
     */
    public DBCursor selectAll(String database, String collection) {
        DBCursor cursor;
        BasicDBObject query;

        DB db = mongoClient.getDB(database);
        DBCollection coll = db.getCollection(collection);

        cursor = coll.find();
        if (!cursor.hasNext())
            cursor = null;
        return cursor;
    }

    /**
     * This function is used to update the values of individual fields--specified by the replacementFieldsAndValue object--
     *  in documents--specified by the searchFieldsandValues object. Pass two objects of  classes that only has primitive data types
     *   as fields--no methods. Each object's fields' values  and their data types will be automatically extracted and used
     *   in the update. If no document matches the criteria then new document will be inserted
     * @param searchKeyAndItsValue Search fields
     * @param replacementFieldsAndValues Replacement fields
     * @param database Database name
     * @param collection Collection name
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public void replaceFields(Object searchKeyAndItsValue, Object replacementFieldsAndValues, String database,
            String collection) throws IllegalArgumentException, IllegalAccessException, TotalADSDBMSException {

        DB db = mongoClient.getDB(database);
        DBCollection coll = db.getCollection(collection);

        BasicDBObject replacementDocument = new BasicDBObject();
        BasicDBObject setFieldValDocument = new BasicDBObject();

        extractKeysAndValuesfromTheObject(replacementFieldsAndValues, setFieldValDocument);

        replacementDocument.append("$set", setFieldValDocument);

        BasicDBObject searchQueryDocument = new BasicDBObject();
        //.append("hosting", "hostB");
        extractKeysAndValuesfromTheObject(searchKeyAndItsValue, searchQueryDocument);

        WriteResult writeRes = coll.update(searchQueryDocument, replacementDocument, true, false);

        CommandResult cmdResult = writeRes.getLastError();
        if (!cmdResult.ok())
            throw new TotalADSDBMSException("Error : " + cmdResult.getErrorMessage());

    }

    //////////////////////////////////////////////////////////////////////////////// 
    //Implementing the ISubject Interface 
    ///////////////////////////////////////////////////////////////
    /**
     * Adds an observer of type {@link IObserver}
     * @param observer
     */
    @Override
    public void addObserver(IObserver observer) {
        observers.add(observer);

    }

    /**
     * Removes an observer of type {@link IObserver}
     * @param observer
     */
    @Override
    public void removeObserver(IObserver observer) {
        observers.remove(observer);

    }

    /**
     * Notifies all observers of type {@link IObserver}
     */
    @Override
    public void notifyObservers() {
        for (IObserver ob : observers)
            ob.update();
    }

}