/********************************************************************************************* * Copyright (c) 2014-2015 Software Behaviour Analysis Lab, Concordia University, Montreal, Canada * * All rights reserved. This program and the accompanying materials * are made available under the terms of Eclipse Public License v1.0 License which * accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Syed Shariyar Murtaza -- Initial design and implementation **********************************************************************************************/ package org.eclipse.tracecompass.totalads.dbms; import org.eclipse.tracecompass.totalads.dbms.IDBCursor; import org.eclipse.tracecompass.totalads.dbms.IDBMSConnection; import org.eclipse.tracecompass.totalads.dbms.IDBMSObserver; import org.eclipse.tracecompass.totalads.dbms.IDataAccessObject; import org.eclipse.tracecompass.totalads.dbms.Messages; import org.eclipse.tracecompass.totalads.dbms.MongoDBCursor; import org.eclipse.tracecompass.totalads.exceptions.TotalADSDBMSException; import org.eclipse.osgi.util.NLS; 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.DBCollection; import com.mongodb.DBCursor; import com.mongodb.DBObject; import com.mongodb.MongoClient; import com.mongodb.WriteConcern; import com.mongodb.WriteResult; import com.mongodb.util.JSON; /** * This class connects with MongoDB, and performs the manipulations required in * a program with MongoDB. * * @author <p> * Syed Shariyar Murtaza justsshary@hotmail.com * </p> * */ class MongoDBMS implements IDataAccessObject, IDBMSConnection { private MongoClient mongoClient; private Boolean isConnected = false; private ArrayList<IDBMSObserver> observers; /** * Constructor */ public MongoDBMS() { observers = new ArrayList<>(); } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDBMSConnection#connect(java * .lang.String, java.lang.Integer) */ @Override public String connect(String host, Integer port) { String message = ""; //$NON-NLS-1$ synchronized (this) { try { 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 = Messages.MongoDBMS_NoConn; notifyObservers(); return message; } isConnected = true;// if it reaches here then it is connected notifyObservers(); } return message; } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDBMSConnection#connect(java * .lang.String, java.lang.Integer, java.lang.String, java.lang.String, * java.lang.String) */ @Override public String connect(String host, Integer port, String username, String password, String database) { String message = ""; //$NON-NLS-1$ synchronized (this) { try { mongoClient = new MongoClient(host, port); DB db = mongoClient.getDB(database); if (db.authenticate(username, password.toCharArray()) == false) { isConnected = false; message = NLS.bind(Messages.MongoDBMS_AuthFailed, username, database); } else { isConnected = true;// if it reaches here then everything is // fine } mongoClient.setWriteConcern(WriteConcern.JOURNALED); } catch (UnknownHostException ex) { isConnected = false; message = ex.getMessage(); } 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"; //$NON-NLS-1$ } finally { notifyObservers(); } } return message; } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDataAccessObject#isConnected() */ @Override public Boolean isConnected() { return isConnected; } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDataAccessObject#getDatabaseList * () */ @Override public List<String> getDatabaseList() { synchronized (this) { List<String> dbList = mongoClient.getDatabaseNames(); dbList.remove("admin"); //$NON-NLS-1$ dbList.remove("local"); //$NON-NLS-1$ return dbList; } } /* * @Override(non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDataAccessObject#datbaseExists * (java.lang.String) */ @Override public boolean datbaseExists(String database) { List<String> databaseNames = getDatabaseList(); for (int j = 0; j < databaseNames.size(); j++) { if (databaseNames.get(j).equals(database)) { return true; } } return false; } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDataAccessObject#createDatabase * (java.lang.String, java.lang.String[]) */ @Override public void createDatabase(String dataBase, String[] collectionNames) throws TotalADSDBMSException { synchronized (this) { if (datbaseExists(dataBase)) { if (isConnected == false) {// This code snippet is a check for // the breakage of connection during // the execution isConnected = true; // Reconnection occurs during // execution and notify all // observers notifyObservers(); } throw new TotalADSDBMSException(Messages.MongoDBMS_DBExists); } DB db = mongoClient.getDB(dataBase); DBObject options = com.mongodb.BasicDBObjectBuilder.start().add("capped", false).get(); //$NON-NLS-1$ for (int j = 0; j < collectionNames.length; j++) { db.createCollection(collectionNames[j], options); } isConnected = true; // If this code is executed after the breakage // of connection, make sure isConnected is true notifyObservers(); } } /* * (non-Javadoc) * * @see org.eclipse.tracecompass.totalads.dbms.IDataAccessObject# * createAscendingUniquesIndexes(java.lang.String, java.lang.String, * java.lang.String[]) */ @Override public void createAscendingUniquesIndexes(String dataBase, String collection, String[] fields) { DBCollection coll = mongoClient.getDB(dataBase).getCollection(collection); DBObject fieldsDB = new BasicDBObject(); for (int j = 0; j < fields.length; j++) { fieldsDB.put(fields[j], 1); } coll.ensureIndex(fieldsDB, new BasicDBObject("unique", true)); //$NON-NLS-1$ } /* * (non-Javadoc) * * @see org.eclipse.tracecompass.totalads.dbms.IDataAccessObject# * createDescendingUniquesIndexes(java.lang.String, java.lang.String, * java.lang.String[]) */ @Override public void createDescendingUniquesIndexes(String dataBase, String collection, String[] fields) { DBCollection coll = mongoClient.getDB(dataBase).getCollection(collection); DBObject fieldsDB = new BasicDBObject(); for (int j = 0; j < fields.length; j++) { fieldsDB.put(fields[j], -1); } coll.ensureIndex(fieldsDB, new BasicDBObject("unique", true)); //$NON-NLS-1$ } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDBMSConnection#closeConnection * () */ @Override public void closeConnection() { synchronized (this) { isConnected = false; mongoClient.close(); } } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDBMSConnection#deleteDatabase * (java.lang.String) */ @Override public void deleteDatabase(String database) { synchronized (this) { mongoClient.dropDatabase(database); notifyObservers(); } } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDataAccessObject#insertUsingJSON * (java.lang.String, com.google.gson.JsonObject, java.lang.String) */ @Override 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 // IDataAccessObject exception throw new TotalADSDBMSException(ex.getMessage()); } } /* * (non-Javadoc) * * @see org.eclipse.tracecompass.totalads.dbms.IDataAccessObject# * insertOrUpdateUsingJSON(java.lang.String, com.google.gson.JsonObject, * com.google.gson.JsonObject, java.lang.String) */ @Override 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()); //$NON-NLS-1$ } } /* * (non-Javadoc) * * @see org.eclipse.tracecompass.totalads.dbms.IDataAccessObject# * updateFieldsInExistingDocUsingJSON(java.lang.String, * com.google.gson.JsonObject, com.google.gson.JsonObject, java.lang.String) */ @Override public void updateFieldsInExistingDocUsingJSON(String database, JsonObject keytoSearch, JsonObject jsonObjectToUpdate, String collection) throws TotalADSDBMSException { DB db = mongoClient.getDB(database); DBCollection col = db.getCollection(collection); BasicDBObject query = (BasicDBObject) JSON.parse(keytoSearch.toString()); // new BasicDBObject(); // query.put("name", "MongoDB"); BasicDBObject newDocument = (BasicDBObject) JSON.parse(jsonObjectToUpdate.toString()); // newDocument.put("name", "MongoDB-updated"); BasicDBObject updateObj = new BasicDBObject(); updateObj.put("$set", newDocument); //$NON-NLS-1$ col.update(query, updateObj); } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDataAccessObject#selectMax( * java.lang.String, java.lang.String, java.lang.String) */ @Override public String selectMax(String key, String database, String collection) { String maxVal = ""; //$NON-NLS-1$ DB db = mongoClient.getDB(database); DBCollection coll = db.getCollection(collection); BasicDBObject query = new BasicDBObject(key, -1); try (DBCursor curs = coll.find().sort(query).limit(1)) { if (curs.hasNext()) { maxVal = curs.next().get(key).toString(); } } catch (Exception ex) { } return maxVal; } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDataAccessObject#select(java * .lang.String, java.lang.String, java.lang.Double, java.lang.String, * java.lang.String) */ @SuppressWarnings("resource") @Override public IDBCursor 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); // MongoDBCursor is AutoCloseable, we need not to worry about it here return new MongoDBCursor(cursor); } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDataAccessObject#select(java * .lang.String, java.lang.String, java.lang.String, java.lang.String, * java.lang.String) */ @SuppressWarnings("resource") @Override public IDBCursor 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); // MongoDBCursor is AutoCloseable, we need not to worry about it here return new MongoDBCursor(cursor); } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDataAccessObject#selectAll( * java.lang.String, java.lang.String) */ @SuppressWarnings("resource") @Override public IDBCursor selectAll(String database, String collection) { DBCursor cursor; DB db = mongoClient.getDB(database); DBCollection coll = db.getCollection(collection); cursor = coll.find(); // MongoDBCursor is AutoCloseable, we need not to worry about it here return new MongoDBCursor(cursor); } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDBMSSubject#addObserver(org * .eclipse.tracecompass.totalads.dbms.IDBMSObserver) */ @Override public void addObserver(IDBMSObserver observer) { observers.add(observer); } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDBMSSubject#removeObserver( * org.eclipse.tracecompass.totalads.dbms.IDBMSObserver) */ @Override public void removeObserver(IDBMSObserver observer) { observers.remove(observer); } /* * (non-Javadoc) * * @see * org.eclipse.tracecompass.totalads.dbms.IDBMSSubject#notifyObservers() */ @Override public void notifyObservers() { for (IDBMSObserver ob : observers) { ob.update(); } } }