org.datavyu.models.db.MongoVariable.java Source code

Java tutorial

Introduction

Here is the source code for org.datavyu.models.db.MongoVariable.java

Source

/*
 * Copyright (c) 2011 Datavyu Foundation, http://datavyu.org
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package org.datavyu.models.db;

import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bson.types.ObjectId;
import org.datavyu.Datavyu;
import org.datavyu.models.db.Argument;
import org.datavyu.models.db.Cell;
import org.datavyu.models.db.UserWarningException;
import org.datavyu.models.db.Variable;
import org.datavyu.models.db.VariableListener;

/**
 * Maps a variable object to a mongo powered datastore.
 */
public final class MongoVariable extends BasicDBObject implements Variable {
    // All the listeners for variables in teh datastore.
    static Map<ObjectId, List<VariableListener>> allListeners = new HashMap<ObjectId, List<VariableListener>>();

    /**
     * @param variableId The ID of the variable we want the listeners for.
     *
     * @return The list of listeners for the specified variableId.
     */
    private static List<VariableListener> getListeners(ObjectId variableId) {
        List<VariableListener> result = allListeners.get(variableId);
        if (result == null) {
            result = new ArrayList<VariableListener>();
            allListeners.put(variableId, result);
        }

        return result;
    }

    /**
     * Removes all the listeners for all the variables.
     */
    public static void clearListeners() {
        allListeners.clear();
    }

    /**
     * Default constructor.
     */
    public MongoVariable() {
    }

    /**
     * Constructor.
     *
     * @param name The name to use for the variable being constructed.
     * @param type The type to use for the variable being constructed.
     */
    public MongoVariable(String name, Argument type) throws UserWarningException {
        this.setName(name);
        this.put("type", serializeArgument(type));
        this.put("hidden", false);
        this.put("selected", true);

        MongoDatastore.markDBAsChanged();

        this.save();
    }

    /**
     * Helper method to save this variable to the DB.
     * This must be run after any changes to the variable.
     */
    public final void save() {
        MongoDatastore.markDBAsChanged();
        MongoDatastore.getVariableCollection().save(this);
    }

    /**
     * @return The internal ID (mongo id) for this variable.
     */
    public ObjectId getID() {
        return (ObjectId) this.get("_id");
    }

    /**
     * Serializes the argument into a mongo object.
     *
     * @param type The Argument being serialized into a mongo object.
     *
     * @return The serialized argument.
     */
    private BasicDBObject serializeArgument(Argument type) {
        BasicDBObject serial_type = new BasicDBObject();

        serial_type.put("type_ordinal", type.type.ordinal());
        serial_type.put("name", type.name);
        serial_type.put("id", type.id);

        List<BasicDBObject> childArguments = new ArrayList<BasicDBObject>();
        if (type.childArguments.size() > 0) {

            for (Argument child : type.childArguments) {
                childArguments.add(serializeArgument(child));
            }
        }
        serial_type.put("child_arguments", childArguments);

        return serial_type;
    }

    /**
     * Deserializes a mongo object into an Argument.
     *
     * @param serial_type The serialized argument.
     *
     * @return The argument held inside the mongo object.
     */
    private Argument deserializeArgument(BasicDBObject serial_type) {

        String name = (String) serial_type.get("name");
        int type_ordinal = (Integer) serial_type.get("type_ordinal");
        Argument.Type type = Argument.Type.values()[type_ordinal];
        long id = (Long) serial_type.get("id");

        Argument arg = new Argument(name, type, id);

        if (type == Argument.Type.MATRIX) {
            List<BasicDBObject> DBchildArguments = (ArrayList<BasicDBObject>) serial_type.get("child_arguments");
            List<Argument> childArguments = new ArrayList<Argument>();

            for (BasicDBObject child : DBchildArguments) {
                childArguments.add(deserializeArgument(child));
            }
            arg.childArguments = childArguments;
        }

        return arg;
    }

    @Override
    public Cell createCell() {
        Cell c = new MongoCell((ObjectId) this.get("_id"), deserializeArgument((BasicDBObject) this.get("type")));
        DBCollection cell_collection = MongoDatastore.getDB().getCollection("cells");

        cell_collection.save((MongoCell) c);

        for (VariableListener vl : getListeners(getID())) {
            vl.cellInserted(c);
        }

        MongoDatastore.markDBAsChanged();
        return c;
    }

    @Override
    public void removeCell(final Cell cell) {
        DBCollection cell_collection = MongoDatastore.getDB().getCollection("cells");

        // Confirm we have the right cell
        BasicDBObject query = new BasicDBObject();

        query.put("_id", ((MongoCell) cell).getID());

        DBCursor cur = cell_collection.find(query);

        if (!cur.hasNext()) {
            System.err.println("ERROR: Cell not found. Nothing deleted.");
        } else {
            cell_collection.remove(cur.next());
        }

        MongoDatastore.markDBAsChanged();

        for (VariableListener vl : getListeners(getID())) {
            vl.cellRemoved(cell);
        }

    }

    @Override
    public List<Cell> getCells() {
        List<Cell> cells = new ArrayList<Cell>();

        DBCollection cell_collection = MongoDatastore.getDB().getCollection("cells");
        BasicDBObject query = new BasicDBObject();

        query.put("variable_id", this.get("_id")); // e.g. find all where i > 50

        DBCursor cur = cell_collection.find(query);

        while (cur.hasNext()) {
            cells.add((MongoCell) cur.next());
        }

        return cells;
    }

    @Override
    public Cell getCellTemporally(final int index) {
        DBCollection cell_collection = MongoDatastore.getDB().getCollection("cells");
        BasicDBObject query = new BasicDBObject();
        BasicDBObject sort = new BasicDBObject();

        query.put("variable_id", this.get("_id")); // e.g. find all where i > 50
        sort.put("onset", 1);

        DBCursor cur = cell_collection.find(query).sort(sort);

        int i = 0;
        while (cur.hasNext()) {
            if (i == index) {
                return (MongoCell) cur.next();
            }
            cur.next();
            i++;
        }

        return null;
    }

    @Override
    public Argument getVariableType() {
        return deserializeArgument((BasicDBObject) this.get("type"));
    }

    @Override
    public void setVariableType(final Argument newType) {
        this.put("type", serializeArgument(newType));
        this.save();
    }

    @Override
    public List<Cell> getCellsTemporally() {
        List<Cell> cells = new ArrayList<Cell>();

        DBCollection cell_collection = MongoDatastore.getDB().getCollection("cells");
        BasicDBObject query = new BasicDBObject();
        BasicDBObject sort = new BasicDBObject();

        query.put("variable_id", this.get("_id")); // e.g. find all where i > 50
        sort.put("onset", 1);

        DBCursor cur = cell_collection.find(query).sort(sort);

        while (cur.hasNext()) {
            cells.add((MongoCell) cur.next());
        }

        return cells;
    }

    @Override
    public boolean contains(final Cell c) {
        DBCollection cell_collection = MongoDatastore.getDB().getCollection("cells");
        DBCursor cur = cell_collection.find((MongoCell) c);

        if (cur.hasNext()) {
            MongoCell found = (MongoCell) cur.next();
            if (found.getVariableID().equals(this.getID())) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void setSelected(final boolean selected) {
        this.put("selected", selected);
        this.save();
    }

    @Override
    public boolean isSelected() {
        return (Boolean) this.get("selected");
    }

    @Override
    public void setHidden(final boolean hidden) {
        this.put("hidden", hidden);
        this.save();

        for (VariableListener vl : getListeners(getID())) {
            vl.visibilityChanged(hidden);
        }
    }

    @Override
    public boolean isHidden() {
        return (Boolean) this.get("hidden");
    }

    @Override
    public String getName() {
        return (String) this.get("name");
    }

    @Override
    public void setName(final String newName) throws UserWarningException {
        // Pre-conditions, the newName must have at least one character.
        if (newName.length() < 1) {
            throw new UserWarningException("Unable to add variable, a name must be supplied.");
        }

        // Pre-conditions, check to make sure newName doesn't contain invalid chars.
        if (newName.contains("(") || newName.contains(")") || newName.contains("<") || newName.contains(">")
                || newName.contains(",") || newName.contains("\"")) {
            throw new UserWarningException("Unable to add variable, name must not contain any: ') ( > < , \"'");
        }

        this.put("name", newName.trim());
        this.save();

        for (VariableListener vl : getListeners(getID())) {
            vl.nameChanged(newName);
        }
    }

    @Override
    public Argument addArgument(final Argument.Type type) {
        Argument arg = getVariableType();
        arg.addChildArgument(type);

        for (Cell cell : getCells()) {
            cell.addMatrixValue(type);
        }

        this.setVariableType(arg);
        this.save();

        return arg.childArguments.get(arg.childArguments.size() - 1);
    }

    @Override
    public void moveArgument(final int old_index, final int new_index) {
        Argument arg = getVariableType();

        // Test to see if this is out of bounds
        if (new_index > arg.childArguments.size() - 1 || new_index < 0) {
            return;
        }

        Argument moved_arg = arg.childArguments.get(old_index);
        arg.childArguments.remove(moved_arg);
        arg.childArguments.add(new_index, moved_arg);

        // Move in all cells
        for (Cell cell : getCells()) {
            cell.moveMatrixValue(old_index, new_index);
        }
        this.setVariableType(arg);
        this.save();

        // TODO: Notify listeners
    }

    @Override
    public void moveArgument(final String name, final int new_index) {
        int old_index = getArgumentIndex(name);
        moveArgument(old_index, new_index);
    }

    @Override
    public void removeArgument(final String name) {
        Argument arg = getVariableType();
        int arg_index = getArgumentIndex(name);
        arg.childArguments.remove(arg_index);

        // Now send this change to the cells
        for (Cell cell : getCells()) {
            cell.removeMatrixValue(arg_index);
        }

        this.setVariableType(arg);
        this.save();

        // TODO: Notify appropriate listeners that this happened.
    }

    @Override
    public int getArgumentIndex(final String name) {
        Argument arg = getVariableType();
        for (int i = 0; i < arg.childArguments.size(); i++) {
            if (arg.childArguments.get(i).name.equals(name)) {
                return i;
            }
        }
        return -1;
    }

    @Override
    public void addListener(final VariableListener listener) {
        getListeners(getID()).add(listener);
    }

    @Override
    public void removeListener(final VariableListener listener) {
        getListeners(getID()).remove(listener);
    }
}