// Copyright 2017 JanusGraph Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.janusgraph.blueprints;
import com.google.common.collect.Sets;
import org.janusgraph.core.Cardinality;
import org.janusgraph.core.EdgeLabel;
import org.janusgraph.core.PropertyKey;
import org.janusgraph.core.JanusGraphFactory;
import org.janusgraph.core.JanusGraph;
import org.janusgraph.core.VertexLabel;
import org.janusgraph.core.schema.JanusGraphManagement;
import org.janusgraph.diskstorage.configuration.BasicConfiguration;
import org.janusgraph.diskstorage.configuration.ConfigElement;
import org.janusgraph.diskstorage.configuration.ModifiableConfiguration;
import org.janusgraph.diskstorage.configuration.WriteConfiguration;
import org.janusgraph.diskstorage.configuration.backend.CommonsConfiguration;
import org.janusgraph.graphdb.JanusGraphBaseTest;
import org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration;
import org.janusgraph.graphdb.database.StandardJanusGraph;
import org.janusgraph.graphdb.olap.computer.FulgoraElementTraversal;
import org.janusgraph.graphdb.olap.computer.FulgoraVertexProperty;
import org.janusgraph.graphdb.relations.CacheEdge;
import org.janusgraph.graphdb.relations.CacheVertexProperty;
import org.janusgraph.graphdb.relations.SimpleJanusGraphProperty;
import org.janusgraph.graphdb.relations.StandardEdge;
import org.janusgraph.graphdb.relations.StandardVertexProperty;
import org.janusgraph.graphdb.tinkerpop.JanusGraphVariables;
import org.janusgraph.graphdb.transaction.StandardJanusGraphTx;
import org.janusgraph.graphdb.types.VertexLabelVertex;
import org.janusgraph.graphdb.types.system.EmptyVertex;
import org.janusgraph.graphdb.types.vertices.EdgeLabelVertex;
import org.janusgraph.graphdb.types.vertices.PropertyKeyVertex;
import org.janusgraph.graphdb.types.vertices.JanusGraphSchemaVertex;
import org.janusgraph.graphdb.vertices.CacheVertex;
import org.janusgraph.graphdb.vertices.PreloadedVertex;
import org.janusgraph.graphdb.vertices.StandardVertex;
import org.apache.commons.configuration.Configuration;
import org.apache.tinkerpop.gremlin.AbstractGraphProvider;
import org.apache.tinkerpop.gremlin.LoadGraphWith;
import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.apache.tinkerpop.gremlin.process.traversal.engine.StandardTraversalEngine;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.TransactionTest;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.structure.util.wrapped.WrappedGraph;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
/**
* @author Matthias Broecheler (me@matthiasb.com)
*/
public abstract class AbstractJanusGraphProvider extends AbstractGraphProvider {
private static final Logger logger = LoggerFactory.getLogger(AbstractJanusGraphProvider.class);
private static final Set<Class> IMPLEMENTATION = Sets.newHashSet(
StandardJanusGraph.class,
StandardJanusGraphTx.class,
StandardVertex.class,
CacheVertex.class,
PreloadedVertex.class,
EdgeLabelVertex.class,
PropertyKeyVertex.class,
VertexLabelVertex.class,
JanusGraphSchemaVertex.class,
EmptyVertex.class,
StandardEdge.class,
CacheEdge.class,
EdgeLabel.class,
EdgeLabelVertex.class,
StandardVertexProperty.class,
CacheVertexProperty.class,
SimpleJanusGraphProperty.class,
CacheVertexProperty.class,
FulgoraVertexProperty.class,
JanusGraphVariables.class,
FulgoraElementTraversal.class);
@Override
public Set<Class> getImplementations() {
return IMPLEMENTATION;
}
@Override
public GraphTraversalSource traversal(final Graph graph) {
return GraphTraversalSource.standard().create(graph);
}
@Override
public GraphTraversalSource traversal(final Graph graph, final TraversalStrategy... strategies) {
final GraphTraversalSource.Builder builder = GraphTraversalSource.build().engine(StandardTraversalEngine.build());
Stream.of(strategies).forEach(builder::with);
return builder.create(graph);
}
// @Override
// public <ID> ID reconstituteGraphSONIdentifier(final Class<? extends Element> clazz, final Object id) {
// if (Edge.class.isAssignableFrom(clazz)) {
// // JanusGraphSONModule toStrings the edgeid - expect a String value for the id
// if (!(id instanceof String)) throw new RuntimeException("Expected a String value for the RelationIdentifier");
// return (ID) RelationIdentifier.parse((String) id);
// } else {
// return (ID) id;
// }
// }
@Override
public void clear(Graph g, final Configuration configuration) throws Exception {
if (null != g) {
while (g instanceof WrappedGraph) g = ((WrappedGraph<? extends Graph>) g).getBaseGraph();
JanusGraph graph = (JanusGraph) g;
if (graph.isOpen()) {
if (g.tx().isOpen()) g.tx().rollback();
try {
g.close();
} catch (IOException | IllegalStateException e) {
logger.warn("Titan graph may not have closed cleanly", e);
}
}
}
WriteConfiguration config = new CommonsConfiguration(configuration);
BasicConfiguration readConfig = new BasicConfiguration(GraphDatabaseConfiguration.ROOT_NS, config, BasicConfiguration.Restriction.NONE);
if (readConfig.has(GraphDatabaseConfiguration.STORAGE_BACKEND)) {
JanusGraphBaseTest.clearGraph(config);
}
}
@Override
public Map<String, Object> getBaseConfiguration(String graphName, Class<?> test, String testMethodName, final LoadGraphWith.GraphData loadGraphWith) {
ModifiableConfiguration conf = getJanusGraphConfiguration(graphName, test, testMethodName);
conf.set(GraphDatabaseConfiguration.COMPUTER_RESULT_MODE, "persist");
conf.set(GraphDatabaseConfiguration.AUTO_TYPE, "tp3");
Map<String, Object> result = new HashMap<>();
conf.getAll().entrySet().stream().forEach(e -> result.put(ConfigElement.getPath(e.getKey().element, e.getKey().umbrellaElements), e.getValue()));
result.put(Graph.GRAPH, JanusGraphFactory.class.getName());
return result;
}
public abstract ModifiableConfiguration getJanusGraphConfiguration(String graphName, Class<?> test, String testMethodName);
@Override
public void loadGraphData(final Graph g, final LoadGraphWith loadGraphWith, final Class testClass, final String testName) {
if (loadGraphWith != null) {
this.createIndices((JanusGraph) g, loadGraphWith.value());
} else {
if (TransactionTest.class.equals(testClass) && testName.equalsIgnoreCase("shouldExecuteWithCompetingThreads")) {
JanusGraphManagement mgmt = ((JanusGraph) g).openManagement();
mgmt.makePropertyKey("blah").dataType(Double.class).make();
mgmt.makePropertyKey("bloop").dataType(Integer.class).make();
mgmt.makePropertyKey("test").dataType(Object.class).make();
mgmt.makeEdgeLabel("friend").make();
mgmt.commit();
}
}
super.loadGraphData(g, loadGraphWith, testClass, testName);
}
private void createIndices(final JanusGraph g, final LoadGraphWith.GraphData graphData) {
JanusGraphManagement mgmt = g.openManagement();
if (graphData.equals(LoadGraphWith.GraphData.GRATEFUL)) {
VertexLabel artist = mgmt.makeVertexLabel("artist").make();
VertexLabel song = mgmt.makeVertexLabel("song").make();
PropertyKey name = mgmt.makePropertyKey("name").cardinality(Cardinality.LIST).dataType(String.class).make();
PropertyKey songType = mgmt.makePropertyKey("songType").cardinality(Cardinality.LIST).dataType(String.class).make();
PropertyKey performances = mgmt.makePropertyKey("performances").cardinality(Cardinality.LIST).dataType(Integer.class).make();
mgmt.buildIndex("artistByName", Vertex.class).addKey(name).indexOnly(artist).buildCompositeIndex();
mgmt.buildIndex("songByName", Vertex.class).addKey(name).indexOnly(song).buildCompositeIndex();
mgmt.buildIndex("songByType", Vertex.class).addKey(songType).indexOnly(song).buildCompositeIndex();
mgmt.buildIndex("songByPerformances", Vertex.class).addKey(performances).indexOnly(song).buildCompositeIndex();
} else if (graphData.equals(LoadGraphWith.GraphData.MODERN)) {
VertexLabel person = mgmt.makeVertexLabel("person").make();
VertexLabel software = mgmt.makeVertexLabel("software").make();
PropertyKey name = mgmt.makePropertyKey("name").cardinality(Cardinality.LIST).dataType(String.class).make();
PropertyKey lang = mgmt.makePropertyKey("lang").cardinality(Cardinality.LIST).dataType(String.class).make();
PropertyKey age = mgmt.makePropertyKey("age").cardinality(Cardinality.LIST).dataType(Integer.class).make();
mgmt.buildIndex("personByName", Vertex.class).addKey(name).indexOnly(person).buildCompositeIndex();
mgmt.buildIndex("softwareByName", Vertex.class).addKey(name).indexOnly(software).buildCompositeIndex();
mgmt.buildIndex("personByAge", Vertex.class).addKey(age).indexOnly(person).buildCompositeIndex();
mgmt.buildIndex("softwareByLang", Vertex.class).addKey(lang).indexOnly(software).buildCompositeIndex();
} else if (graphData.equals(LoadGraphWith.GraphData.CLASSIC)) {
PropertyKey name = mgmt.makePropertyKey("name").cardinality(Cardinality.LIST).dataType(String.class).make();
PropertyKey lang = mgmt.makePropertyKey("lang").cardinality(Cardinality.LIST).dataType(String.class).make();
PropertyKey age = mgmt.makePropertyKey("age").cardinality(Cardinality.LIST).dataType(Integer.class).make();
mgmt.buildIndex("byName", Vertex.class).addKey(name).buildCompositeIndex();
mgmt.buildIndex("byAge", Vertex.class).addKey(age).buildCompositeIndex();
mgmt.buildIndex("byLang", Vertex.class).addKey(lang).buildCompositeIndex();
} else {
// TODO: add CREW work here.
// TODO: add meta_property indices when meta_property graph is provided
//throw new RuntimeException("Could not load graph with " + graphData);
}
mgmt.commit();
}
}