ai.grakn.factory.OrientDBInternalFactory.java Source code

Java tutorial

Introduction

Here is the source code for ai.grakn.factory.OrientDBInternalFactory.java

Source

/*
 * Grakn - A Distributed Semantic Database
 * Copyright (C) 2016  Grakn Labs Limited
 *
 * Grakn is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Grakn is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Grakn. If not, see <http://www.gnu.org/licenses/gpl.txt>.
 */

package ai.grakn.factory;

import ai.grakn.Grakn;
import ai.grakn.graph.internal.GraknOrientDBGraph;
import ai.grakn.util.ErrorMessage;
import ai.grakn.util.Schema;
import com.orientechnologies.orient.core.metadata.schema.OImmutableClass;
import com.orientechnologies.orient.core.metadata.schema.OType;
import org.apache.commons.configuration.BaseConfiguration;
import org.apache.tinkerpop.gremlin.orientdb.OrientGraph;
import org.apache.tinkerpop.gremlin.orientdb.OrientGraphFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.Set;

import static ai.grakn.util.ErrorMessage.INVALID_DATATYPE;

/**
 * <p>
 *     A Grakn Graph on top of {@link OrientGraph}
 * </p>
 *
 * <p>
 *     This produces an grakn graph on top of {@link OrientGraph}.
 *     The base construction process defined by {@link AbstractInternalFactory} ensures the graph factories are singletons.
 * </p>
 *
 * @author fppt
 */
public class OrientDBInternalFactory extends AbstractInternalFactory<GraknOrientDBGraph, OrientGraph> {
    private final Logger LOG = LoggerFactory.getLogger(OrientDBInternalFactory.class);
    private final Map<String, OrientGraphFactory> openFactories;

    public OrientDBInternalFactory(String keyspace, String engineUrl, Properties properties) {
        super(keyspace, engineUrl, properties);
        openFactories = new HashMap<>();
    }

    @Override
    GraknOrientDBGraph buildGraknGraphFromTinker(OrientGraph graph) {
        return new GraknOrientDBGraph(graph, super.keyspace, super.engineUrl, super.properties);
    }

    @Override
    OrientGraph buildTinkerPopGraph(boolean batchLoading) {
        LOG.warn(ErrorMessage.CONFIG_IGNORED.getMessage("properties", properties));
        return configureGraph(super.keyspace, super.engineUrl);
    }

    //TODO: Fix this later
    @Override
    protected OrientGraph getGraphWithNewTransaction(OrientGraph graph, boolean batchloading) {
        return graph;
    }

    private OrientGraph configureGraph(String name, String address) {
        boolean schemaDefinitionRequired = false;
        OrientGraphFactory factory = getFactory(name, address);
        OrientGraph graph = factory.getNoTx();

        //Check if the schema has been created
        for (Schema.BaseType baseType : Schema.BaseType.values()) {
            try {
                graph.database().browseClass(OImmutableClass.VERTEX_CLASS_NAME + "_" + baseType);
            } catch (IllegalArgumentException e) {
                schemaDefinitionRequired = true;
                break;
            }
        }

        //Create the schema if needed
        if (schemaDefinitionRequired) {
            graph = createGraphWithSchema(factory, graph);
        }

        return graph;
    }

    private OrientGraph createGraphWithSchema(OrientGraphFactory factory, OrientGraph graph) {
        for (Schema.BaseType baseType : Schema.BaseType.values()) {
            graph.createVertexClass(baseType.name());
        }

        for (Schema.EdgeLabel edgeLabel : Schema.EdgeLabel.values()) {
            graph.createEdgeClass(edgeLabel.name());
        }

        graph = createIndicesVertex(graph);

        graph.commit();

        return factory.getNoTx();
    }

    private OrientGraph createIndicesVertex(OrientGraph graph) {
        ResourceBundle keys = ResourceBundle.getBundle("indices-vertices");
        Set<String> labels = keys.keySet();

        for (String label : labels) {
            String[] configs = keys.getString(label).split(",");

            for (String propertyConfig : configs) {
                String[] propertyConfigs = propertyConfig.split(":");
                Schema.VertexProperty property = Schema.VertexProperty.valueOf(propertyConfigs[0]);
                boolean isUnique = Boolean.parseBoolean(propertyConfigs[1]);

                OType orientDataType = getOrientDataType(property);
                BaseConfiguration indexConfig = new BaseConfiguration();
                indexConfig.setProperty("keytype", orientDataType);
                //TODO: Figure out why this is not working when the Orient Guys say it should
                //indexConfig.setProperty("metadata.ignoreNullValues", true);

                if (isUnique) {
                    indexConfig.setProperty("type", "UNIQUE");
                }

                if (!graph.getVertexIndexedKeys(label).contains(property.name())) {
                    graph.createVertexIndex(property.name(), label, indexConfig);
                }
            }
        }

        return graph;
    }

    private OType getOrientDataType(Schema.VertexProperty property) {
        Class propertyDataType = property.getDataType();

        if (propertyDataType.equals(String.class)) {
            return OType.STRING;
        } else if (propertyDataType.equals(Long.class)) {
            return OType.LONG;
        } else if (propertyDataType.equals(Double.class)) {
            return OType.DOUBLE;
        } else if (propertyDataType.equals(Boolean.class)) {
            return OType.BOOLEAN;
        } else {
            String options = String.class.getName() + ", " + Long.class.getName() + ", " + Double.class.getName()
                    + ", or " + Boolean.class.getName();
            throw new RuntimeException(INVALID_DATATYPE.getMessage(propertyDataType.getName(), options));
        }
    }

    private OrientGraphFactory getFactory(String name, String address) {
        if (Grakn.IN_MEMORY.equals(address)) {
            address = "memory";
            //name = "/tmp/" + name;
        }

        String key = name + address;
        if (!openFactories.containsKey(key)) {
            openFactories.put(key, new OrientGraphFactory(address + ":" + name));
        }
        return openFactories.get(key);
    }
}