| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with this |
| * work for additional information regarding copyright ownership. The ASF |
| * licenses this file to You 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.apache.hugegraph.variables; |
| |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Optional; |
| import java.util.Set; |
| |
| import org.apache.commons.lang3.ArrayUtils; |
| import org.apache.hugegraph.HugeGraphParams; |
| import org.apache.hugegraph.backend.query.Condition; |
| import org.apache.hugegraph.backend.query.ConditionQuery; |
| import org.apache.hugegraph.backend.query.Query; |
| import org.apache.hugegraph.backend.query.QueryResults; |
| import org.apache.hugegraph.backend.tx.GraphTransaction; |
| import org.apache.hugegraph.schema.PropertyKey; |
| import org.apache.hugegraph.schema.SchemaManager; |
| import org.apache.hugegraph.schema.VertexLabel; |
| import org.apache.hugegraph.type.HugeType; |
| import org.apache.hugegraph.type.define.Cardinality; |
| import org.apache.hugegraph.type.define.DataType; |
| import org.apache.hugegraph.type.define.HugeKeys; |
| import org.apache.tinkerpop.gremlin.structure.Graph; |
| import org.apache.tinkerpop.gremlin.structure.Graph.Hidden; |
| import org.apache.tinkerpop.gremlin.structure.Vertex; |
| import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator; |
| import org.apache.tinkerpop.gremlin.structure.util.StringFactory; |
| import org.slf4j.Logger; |
| |
| import org.apache.hugegraph.structure.HugeVertex; |
| import org.apache.hugegraph.util.Log; |
| |
| public class HugeVariables implements Graph.Variables { |
| |
| private static final Logger LOG = Log.logger(HugeVariables.class); |
| |
| // Variables vertex label |
| private static final String VARIABLES = "variables"; |
| |
| // Variables properties |
| private static final String VARIABLE_KEY = "varKey"; |
| private static final String VARIABLE_TYPE = "varType"; |
| |
| private static final String BYTE_VALUE = "B"; |
| private static final String BOOLEAN_VALUE = "Z"; |
| private static final String INTEGER_VALUE = "I"; |
| private static final String LONG_VALUE = "L"; |
| private static final String FLOAT_VALUE = "F"; |
| private static final String DOUBLE_VALUE = "D"; |
| private static final String STRING_VALUE = "S"; |
| |
| // Variables properties suffix |
| private static final String LIST = "L"; |
| private static final String SET = "S"; |
| |
| private static final String[] TYPES = { |
| Hidden.hide(BYTE_VALUE), |
| Hidden.hide(BOOLEAN_VALUE), |
| Hidden.hide(INTEGER_VALUE), |
| Hidden.hide(LONG_VALUE), |
| Hidden.hide(FLOAT_VALUE), |
| Hidden.hide(DOUBLE_VALUE), |
| Hidden.hide(STRING_VALUE), |
| Hidden.hide(BYTE_VALUE + LIST), |
| Hidden.hide(BOOLEAN_VALUE + LIST), |
| Hidden.hide(INTEGER_VALUE + LIST), |
| Hidden.hide(LONG_VALUE + LIST), |
| Hidden.hide(FLOAT_VALUE + LIST), |
| Hidden.hide(DOUBLE_VALUE + LIST), |
| Hidden.hide(STRING_VALUE + LIST), |
| Hidden.hide(BYTE_VALUE + SET), |
| Hidden.hide(BOOLEAN_VALUE + SET), |
| Hidden.hide(INTEGER_VALUE + SET), |
| Hidden.hide(LONG_VALUE + SET), |
| Hidden.hide(FLOAT_VALUE + SET), |
| Hidden.hide(DOUBLE_VALUE + SET), |
| Hidden.hide(STRING_VALUE + SET) |
| }; |
| |
| private final HugeGraphParams params; |
| |
| public HugeVariables(HugeGraphParams params) { |
| this.params = params; |
| } |
| |
| public synchronized void initSchemaIfNeeded() { |
| if (this.params.graph().existsVertexLabel(Hidden.hide(VARIABLES))) { |
| // Ignore if exist |
| return; |
| } |
| |
| createPropertyKey(Hidden.hide(VARIABLE_KEY), DataType.TEXT, |
| Cardinality.SINGLE); |
| createPropertyKey(Hidden.hide(VARIABLE_TYPE), DataType.TEXT, |
| Cardinality.SINGLE); |
| createPropertyKey(Hidden.hide(BYTE_VALUE), DataType.BYTE, |
| Cardinality.SINGLE); |
| createPropertyKey(Hidden.hide(BOOLEAN_VALUE), DataType.BOOLEAN, |
| Cardinality.SINGLE); |
| createPropertyKey(Hidden.hide(INTEGER_VALUE), DataType.INT, |
| Cardinality.SINGLE); |
| createPropertyKey(Hidden.hide(LONG_VALUE), DataType.LONG, |
| Cardinality.SINGLE); |
| createPropertyKey(Hidden.hide(FLOAT_VALUE), DataType.FLOAT, |
| Cardinality.SINGLE); |
| createPropertyKey(Hidden.hide(DOUBLE_VALUE), DataType.DOUBLE, |
| Cardinality.SINGLE); |
| createPropertyKey(Hidden.hide(STRING_VALUE), DataType.TEXT, |
| Cardinality.SINGLE); |
| createPropertyKey(Hidden.hide(BYTE_VALUE + LIST), |
| DataType.BYTE, Cardinality.LIST); |
| createPropertyKey(Hidden.hide(BOOLEAN_VALUE + LIST), |
| DataType.BOOLEAN, Cardinality.LIST); |
| createPropertyKey(Hidden.hide(INTEGER_VALUE + LIST), |
| DataType.INT, Cardinality.LIST); |
| createPropertyKey(Hidden.hide(LONG_VALUE + LIST), |
| DataType.LONG, Cardinality.LIST); |
| createPropertyKey(Hidden.hide(FLOAT_VALUE + LIST), |
| DataType.FLOAT, Cardinality.LIST); |
| createPropertyKey(Hidden.hide(DOUBLE_VALUE + LIST), |
| DataType.DOUBLE, Cardinality.LIST); |
| createPropertyKey(Hidden.hide(STRING_VALUE + LIST), |
| DataType.TEXT, Cardinality.LIST); |
| createPropertyKey(Hidden.hide(BYTE_VALUE + SET), |
| DataType.BYTE, Cardinality.SET); |
| createPropertyKey(Hidden.hide(BOOLEAN_VALUE + SET), |
| DataType.BOOLEAN, Cardinality.SET); |
| createPropertyKey(Hidden.hide(INTEGER_VALUE + SET), |
| DataType.INT, Cardinality.SET); |
| createPropertyKey(Hidden.hide(LONG_VALUE + SET), |
| DataType.LONG, Cardinality.SET); |
| createPropertyKey(Hidden.hide(FLOAT_VALUE + SET), |
| DataType.FLOAT, Cardinality.SET); |
| createPropertyKey(Hidden.hide(DOUBLE_VALUE + SET), |
| DataType.DOUBLE, Cardinality.SET); |
| createPropertyKey(Hidden.hide(STRING_VALUE + SET), |
| DataType.TEXT, Cardinality.SET); |
| |
| String[] properties = {Hidden.hide(VARIABLE_KEY), |
| Hidden.hide(VARIABLE_TYPE)}; |
| properties = ArrayUtils.addAll(properties, TYPES); |
| |
| SchemaManager schema = this.params.graph().schema(); |
| VertexLabel variables = schema.vertexLabel(Hidden.hide(VARIABLES)) |
| .properties(properties) |
| .usePrimaryKeyId() |
| .primaryKeys(Hidden.hide(VARIABLE_KEY)) |
| .nullableKeys(TYPES) |
| .build(); |
| this.params.schemaTransaction().addVertexLabel(variables); |
| |
| LOG.debug("Variables schema created"); |
| } |
| |
| private void createPropertyKey(String name, DataType dataType, |
| Cardinality cardinality) { |
| SchemaManager schema = this.params.graph().schema(); |
| PropertyKey propertyKey = schema.propertyKey(name) |
| .dataType(dataType) |
| .cardinality(cardinality) |
| .build(); |
| this.params.schemaTransaction().addPropertyKey(propertyKey); |
| } |
| |
| @Override |
| public Set<String> keys() { |
| Iterator<Vertex> vertices = this.queryAllVariableVertices(); |
| try { |
| Set<String> keys = new HashSet<>(); |
| while (vertices.hasNext()) { |
| keys.add(vertices.next().value(Hidden.hide(VARIABLE_KEY))); |
| Query.checkForceCapacity(keys.size()); |
| } |
| return keys; |
| } finally { |
| CloseableIterator.closeIterator(vertices); |
| } |
| } |
| |
| @Override |
| public <R> Optional<R> get(String key) { |
| if (key == null) { |
| throw Graph.Variables.Exceptions.variableKeyCanNotBeNull(); |
| } |
| if (key.isEmpty()) { |
| throw Graph.Variables.Exceptions.variableKeyCanNotBeEmpty(); |
| } |
| |
| Vertex vertex = this.queryVariableVertex(key); |
| if (vertex == null) { |
| return Optional.empty(); |
| } |
| |
| String type = vertex.value(Hidden.hide(VARIABLE_TYPE)); |
| if (!Arrays.asList(TYPES).contains(Hidden.hide(type))) { |
| throw Graph.Variables.Exceptions |
| .dataTypeOfVariableValueNotSupported(type); |
| } |
| // The value of key VARIABLE_TYPE is the name of variable value |
| return Optional.of(vertex.value(Hidden.hide(type))); |
| } |
| |
| @Override |
| public void set(String key, Object value) { |
| if (key == null) { |
| throw Graph.Variables.Exceptions.variableKeyCanNotBeNull(); |
| } |
| if (key.isEmpty()) { |
| throw Graph.Variables.Exceptions.variableKeyCanNotBeEmpty(); |
| } |
| if (value == null) { |
| throw Graph.Variables.Exceptions.variableValueCanNotBeNull(); |
| } |
| |
| this.createVariableVertex(key, value); |
| } |
| |
| @Override |
| public void remove(String key) { |
| if (key == null) { |
| throw Graph.Variables.Exceptions.variableKeyCanNotBeNull(); |
| } |
| if (key.isEmpty()) { |
| throw Graph.Variables.Exceptions.variableKeyCanNotBeEmpty(); |
| } |
| HugeVertex vertex = this.queryVariableVertex(key); |
| if (vertex != null) { |
| this.removeVariableVertex(vertex); |
| } |
| } |
| |
| @Override |
| public Map<String, Object> asMap() { |
| Iterator<Vertex> vertices = this.queryAllVariableVertices(); |
| try { |
| Map<String, Object> variables = new HashMap<>(); |
| while (vertices.hasNext()) { |
| Vertex vertex = vertices.next(); |
| String key = vertex.value(Hidden.hide(VARIABLE_KEY)); |
| String type = vertex.value(Hidden.hide(VARIABLE_TYPE)); |
| if (!Arrays.asList(TYPES).contains(Hidden.hide(type))) { |
| throw Graph.Variables.Exceptions |
| .dataTypeOfVariableValueNotSupported(type); |
| } |
| Object value = vertex.value(Hidden.hide(type)); |
| variables.put(key, value); |
| Query.checkForceCapacity(variables.size()); |
| } |
| return Collections.unmodifiableMap(variables); |
| } finally { |
| CloseableIterator.closeIterator(vertices); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return StringFactory.graphVariablesString(this); |
| } |
| |
| private void setProperty(HugeVertex vertex, String key, Object value) { |
| String suffix; |
| if (value instanceof List) { |
| suffix = LIST; |
| } else if (value instanceof Set) { |
| suffix = SET; |
| } else { |
| suffix = ""; |
| } |
| |
| vertex.property(Hidden.hide(VARIABLE_KEY), key); |
| Object object = HugeVariables.extractSingleObject(value); |
| if (object == null) { |
| vertex.property(Hidden.hide(STRING_VALUE + suffix), value); |
| vertex.property(Hidden.hide(VARIABLE_TYPE), STRING_VALUE + suffix); |
| return; |
| } |
| |
| if (object instanceof Byte) { |
| vertex.property(Hidden.hide(BYTE_VALUE + suffix), value); |
| vertex.property(Hidden.hide(VARIABLE_TYPE), BYTE_VALUE + suffix); |
| } else if (object instanceof Boolean) { |
| vertex.property(Hidden.hide(BOOLEAN_VALUE + suffix), value); |
| vertex.property(Hidden.hide(VARIABLE_TYPE), |
| BOOLEAN_VALUE + suffix); |
| } else if (object instanceof Integer) { |
| vertex.property(Hidden.hide(INTEGER_VALUE + suffix), value); |
| vertex.property(Hidden.hide(VARIABLE_TYPE), |
| INTEGER_VALUE + suffix); |
| } else if (object instanceof Long) { |
| vertex.property(Hidden.hide(LONG_VALUE + suffix), value); |
| vertex.property(Hidden.hide(VARIABLE_TYPE), LONG_VALUE + suffix); |
| } else if (object instanceof Float) { |
| vertex.property(Hidden.hide(FLOAT_VALUE + suffix), value); |
| vertex.property(Hidden.hide(VARIABLE_TYPE), FLOAT_VALUE + suffix); |
| } else if (object instanceof Double) { |
| vertex.property(Hidden.hide(DOUBLE_VALUE + suffix), value); |
| vertex.property(Hidden.hide(VARIABLE_TYPE), DOUBLE_VALUE + suffix); |
| } else if (object instanceof String) { |
| vertex.property(Hidden.hide(STRING_VALUE + suffix), value); |
| vertex.property(Hidden.hide(VARIABLE_TYPE), STRING_VALUE + suffix); |
| } else { |
| throw Graph.Variables.Exceptions |
| .dataTypeOfVariableValueNotSupported(value); |
| } |
| } |
| |
| private void createVariableVertex(String key, Object value) { |
| VertexLabel vl = this.variableVertexLabel(); |
| GraphTransaction tx = this.params.graphTransaction(); |
| |
| HugeVertex vertex = HugeVertex.create(tx, null, vl); |
| try { |
| this.setProperty(vertex, key, value); |
| } catch (IllegalArgumentException e) { |
| throw Graph.Variables.Exceptions |
| .dataTypeOfVariableValueNotSupported(value, e); |
| } |
| // PrimaryKey id |
| vertex.assignId(null); |
| |
| tx.addVertex(vertex); |
| } |
| |
| private void removeVariableVertex(HugeVertex vertex) { |
| this.params.graphTransaction().removeVertex(vertex); |
| } |
| |
| private HugeVertex queryVariableVertex(String key) { |
| GraphTransaction tx = this.params.graphTransaction(); |
| Query query = this.createVariableQuery(key); |
| Iterator<Vertex> vertices = tx.queryVertices(query); |
| return (HugeVertex) QueryResults.one(vertices); |
| } |
| |
| private Iterator<Vertex> queryAllVariableVertices() { |
| GraphTransaction tx = this.params.graphTransaction(); |
| Query query = this.createVariableQuery(null); |
| Iterator<Vertex> vertices = tx.queryVertices(query); |
| return vertices; |
| } |
| |
| private ConditionQuery createVariableQuery(String name) { |
| ConditionQuery query = new ConditionQuery(HugeType.VERTEX); |
| VertexLabel vl = this.variableVertexLabel(); |
| query.eq(HugeKeys.LABEL, vl.id()); |
| if (name != null) { |
| PropertyKey pkey = this.params.graph().propertyKey( |
| Hidden.hide(VARIABLE_KEY)); |
| query.query(Condition.eq(pkey.id(), name)); |
| } |
| query.showHidden(true); |
| return query; |
| } |
| |
| private VertexLabel variableVertexLabel() { |
| return this.params.graph().vertexLabel(Hidden.hide(VARIABLES)); |
| } |
| |
| private static Object extractSingleObject(Object value) { |
| if (value instanceof List || value instanceof Set) { |
| Collection<?> collection = (Collection<?>) value; |
| if (collection.isEmpty()) { |
| return null; |
| } |
| value = collection.iterator().next(); |
| } |
| return value; |
| } |
| } |