Package com.jnj.fluxgraph

Source Code of com.jnj.fluxgraph.FluxElement

package com.jnj.fluxgraph;

import clojure.lang.Keyword;
import com.tinkerpop.blueprints.TimeAwareElement;
import com.tinkerpop.blueprints.util.ExceptionFactory;
import com.tinkerpop.blueprints.util.StringFactory;
import datomic.Database;
import datomic.Entity;
import datomic.Peer;
import datomic.Util;
import org.joda.time.DateTime;
import org.joda.time.Interval;

import java.util.*;

/**
* @author Davy Suvee (http://datablend.be)
*/
public abstract class FluxElement implements TimeAwareElement {

    protected final Database database;
    protected final FluxGraph fluxGraph;
    protected Object uuid;
    protected Object id;

    protected FluxElement(final FluxGraph fluxGraph, final Database database) {
        this.database = database;
        this.fluxGraph = fluxGraph;
        // UUID used to retrieve the actual datomic id later on
        uuid = Keyword.intern(UUID.randomUUID().toString());
        id = Peer.tempid(":graph");
    }

    @Override
    public Object getId() {
        return id;
    }

    @Override
    public Object getTimeId() {
        return FluxUtil.getActualTimeId(getDatabase(), this);
    }

    @Override
    public boolean isCurrentVersion() {
        return database == null;
    }

    @Override
    public boolean isDeleted() {
        // An element is deleted if we can no longer find any reference to it in the current version of the graph
        Collection<List<Object>> found = (Peer.q("[:find ?id " +
                                                  ":in $ ?id " +
                                                  ":where [?id _ _ ] ]", getDatabase(), id));
        return found.isEmpty();
    }

    @Override
    public Set<String> getPropertyKeys() {
        if (isDeleted()) {
            throw new IllegalArgumentException("It is not possible to get properties on a deleted element");
        }
        Set<String> finalproperties = new HashSet<String>();
        Set properties = getDatabase().entity(id).keySet();
        Iterator<Keyword> propertiesit = properties.iterator();
        while (propertiesit.hasNext()) {
            Keyword property = propertiesit.next();
            if (!FluxUtil.isReservedKey(property.toString())) {
                finalproperties.add(FluxUtil.getPropertyName(property));
            }
        }
        return finalproperties;
    }

    @Override
    public Object getProperty(final String key) {
        if (isDeleted()) {
            throw new IllegalArgumentException("It is not possible to get properties on a deleted element");
        }
        if (!FluxUtil.isReservedKey(key)) {
            Set properties = getDatabase().entity(id).keySet();
            Iterator<Keyword> propertiesit = properties.iterator();
            // We need to iterate, as we don't know the exact type (although we ensured that only one attribute will have that name)
            while (propertiesit.hasNext()) {
                Keyword property = propertiesit.next();
                String propertyname = FluxUtil.getPropertyName(property);
                if (key.equals(propertyname)) {
                    return getDatabase().entity(id).get(property);
                }
            }
            // We didn't find the value
            return null;
        }
        else {
            return getDatabase().entity(id).get(key);
        }
    }

    @Override
    public void setProperty(final String key, final Object value) {
        validate();
        if (key.equals(StringFactory.ID))
            throw ExceptionFactory.propertyKeyIdIsReserved();
        if (key.equals(StringFactory.LABEL))
            throw new IllegalArgumentException("Property key is reserved for all nodes and edges: " + StringFactory.LABEL);
        if (key.equals(StringFactory.EMPTY_STRING))
            throw ExceptionFactory.elementKeyCanNotBeEmpty();
        // A user-defined property
        if (!FluxUtil.isReservedKey(key)) {
            // If the property does not exist yet, create the attribute if required and create the appropriate transaction
            if (getProperty(key) == null) {
                // We first need to create the new attribute on the fly
                FluxUtil.createAttributeDefinition(key, value.getClass(), this.getClass(), fluxGraph);
                fluxGraph.addToTransaction(Util.map(":db/id", id,
                        FluxUtil.createKey(key, value.getClass(), this.getClass()), value));
            }
            else {
                // Value types match, just perform an update
                if (getProperty(key).getClass().equals(value.getClass())) {
                    fluxGraph.addToTransaction(Util.map(":db/id", id,
                            FluxUtil.createKey(key, value.getClass(), this.getClass()), value));
                }
                // Value types do not match. Retract original fact and add new one
                else {
                    FluxUtil.createAttributeDefinition(key, value.getClass(), this.getClass(), fluxGraph);
                    fluxGraph.addToTransaction(Util.list(":db/retract", id,
                            FluxUtil.createKey(key, value.getClass(), this.getClass()), getProperty(key)));
                    fluxGraph.addToTransaction(Util.map(":db/id", id,
                            FluxUtil.createKey(key, value.getClass(), this.getClass()), value));
                }
            }
        }
        // A datomic graph specific property
        else {
            fluxGraph.addToTransaction(Util.map(":db/id", id,
                    key, value));
        }
        fluxGraph.addTransactionInfo(this);
        fluxGraph.transact();
    }

    public Interval getTimeInterval() {
        DateTime startTime = new DateTime(FluxUtil.getTransactionDate(fluxGraph, getTimeId()));
        TimeAwareElement nextElement = this.getNextVersion();
        if (nextElement == null) {
            return new Interval(startTime, new DateTime(Long.MAX_VALUE));
        }
        else {
            DateTime stopTime = new DateTime(FluxUtil.getTransactionDate(fluxGraph, nextElement.getTimeId()));
            return new Interval(startTime, stopTime);
        }
    }

    @Override
    public Object removeProperty(final String key) {
        validate();
        Object oldvalue = getProperty(key);
        if (oldvalue != null) {
            if (!FluxUtil.isReservedKey(key)) {
                fluxGraph.addToTransaction(Util.list(":db/retract", id,
                                       FluxUtil.createKey(key, oldvalue.getClass(), this.getClass()), oldvalue));
            }
        }
        fluxGraph.addTransactionInfo(this);
        fluxGraph.transact();
        return oldvalue;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        FluxElement that = (FluxElement) o;
        if (id != null ? !id.equals(that.id) : that.id != null) return false;
        return true;
    }

    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }

    protected Database getDatabase() {
        if (database == null) {
            return fluxGraph.getRawGraph();
        }
        return database;
    }

    private void validate() {
        if (!isCurrentVersion()) {
            throw new IllegalArgumentException("It is not possible to set a property on a non-current version of the element");
        }
        if (isDeleted()) {
            throw new IllegalArgumentException("It is not possible to set a property on a deleted element");
        }
    }

    // Creates a collection containing the set of datomic facts describing this entity
    protected Set<Object> getFacts() {
        // Create the set of facts
        Set<Object> theFacts = new HashSet<Object>();
        // Get the entity
        Entity entity = getDatabase().entity(id);
        // Add the base facts associated with this edge
        Set properties = entity.keySet();
        Iterator<Keyword> propertiesIt = properties.iterator();
        while (propertiesIt.hasNext()) {
            Keyword property = propertiesIt.next();
            // Add all properties (except the ident property (is only originally used for retrieving the id of the created elements)
            if (!property.toString().equals(":db/ident")) {
                theFacts.add(FluxUtil.map(":db/id", id, property.toString(), entity.get(property).toString()));
            }
        }
        return theFacts;
    }

}
TOP

Related Classes of com.jnj.fluxgraph.FluxElement

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.