edges) {
+ this.edges = edges;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GraphLineage that = (GraphLineage) o;
+ return Objects.equals(current, that.current)
+ && Objects.equals(vertices, that.vertices)
+ && Objects.equals(edges, that.edges);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(current, vertices, edges);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer stringBuffer = new StringBuffer("GraphLineage{");
+ stringBuffer.append("current=").append(current);
+ stringBuffer.append(", vertices=").append(vertices);
+ stringBuffer.append(", edges=").append(edges);
+ stringBuffer.append('}');
+ return stringBuffer.toString();
+ }
+}
diff --git a/graph-common/src/main/java/org/studiox/graph/common/GraphVertex.java b/graph-common/src/main/java/org/studiox/graph/common/GraphVertex.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d001ec914fca9eab315c1058754f573ea064497
--- /dev/null
+++ b/graph-common/src/main/java/org/studiox/graph/common/GraphVertex.java
@@ -0,0 +1,82 @@
+package org.studiox.graph.common;
+
+import java.util.Objects;
+
+/** The Define of Common Graph Vertex */
+public class GraphVertex {
+
+ /** the unique name of the vertex */
+ private String uniq;
+
+ /** the type of the vertex */
+ private String type;
+
+ /** the status of the vertex */
+ private Boolean deleted;
+
+ /** the create time of the vertex */
+ private Long createTime;
+
+ public String getUniq() {
+ return uniq;
+ }
+
+ public void setUniq(String uniq) {
+ this.uniq = uniq;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public Boolean getDeleted() {
+ return deleted;
+ }
+
+ public void setDeleted(Boolean deleted) {
+ this.deleted = deleted;
+ }
+
+ public Long getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(Long createTime) {
+ this.createTime = createTime;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GraphVertex that = (GraphVertex) o;
+ return Objects.equals(uniq, that.uniq)
+ && Objects.equals(type, that.type)
+ && Objects.equals(deleted, that.deleted)
+ && Objects.equals(createTime, that.createTime);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(uniq, type, deleted, createTime);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer stringBuffer = new StringBuffer("GraphVertex{");
+ stringBuffer.append("uniq='").append(uniq).append('\'');
+ stringBuffer.append(", type='").append(type).append('\'');
+ stringBuffer.append(", deleted=").append(deleted);
+ stringBuffer.append(", createTime=").append(createTime);
+ stringBuffer.append('}');
+ return stringBuffer.toString();
+ }
+}
diff --git a/graph-common/src/main/java/org/studiox/graph/common/IGraphFactory.java b/graph-common/src/main/java/org/studiox/graph/common/IGraphFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..129b8ddf00eca08b09b4874df4957d5e6770e8d9
--- /dev/null
+++ b/graph-common/src/main/java/org/studiox/graph/common/IGraphFactory.java
@@ -0,0 +1,13 @@
+package org.studiox.graph.common;
+
+/** the interface of the common graph factory */
+public interface IGraphFactory {
+
+ /**
+ * Get the define type of the graph instance
+ *
+ * @param graphType
+ * @return
+ */
+ IGraphWrapper getGraphWarpper(String graphType);
+}
diff --git a/graph-common/src/main/java/org/studiox/graph/common/IGraphWrapper.java b/graph-common/src/main/java/org/studiox/graph/common/IGraphWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f9cadebccc8fe6963b3fc3044e94b98d93a0b71
--- /dev/null
+++ b/graph-common/src/main/java/org/studiox/graph/common/IGraphWrapper.java
@@ -0,0 +1,306 @@
+package org.studiox.graph.common;
+
+import org.studiox.graph.common.exception.GraphException;
+
+import java.util.List;
+import java.util.Map;
+
+/** the interface of the common graph */
+public interface IGraphWrapper {
+
+ /** init method */
+ void open() throws GraphException;
+
+ /** close method */
+ void close();
+
+ /**
+ * Create new vertex
+ *
+ * uniq is the unique name to one vertex
+ *
+ * @param uniq
+ * @param type
+ * @param createTime
+ * @return Vertex ID(Long)
+ */
+ Long createVertex(String uniq, String type, Long createTime);
+
+ /**
+ * Create new vertex without pre-check
+ *
+ *
uniq is the unique name to one vertex
+ *
+ * @param uniq
+ * @param type
+ * @param createTime
+ * @return Vertex ID(Long)
+ */
+ Long createVertexNotPreCheck(String uniq, String type, Long createTime);
+
+ /**
+ * Update the existed vertex
+ *
+ *
uniq is the unique name to one vertex
+ *
+ * @param uniq
+ * @param type
+ * @param createTime
+ * @return
+ */
+ boolean updateVertex(String uniq, String type, Long createTime);
+
+ /**
+ * Update the existed vertex, also update the graph edge property
+ *
+ *
oldUniq is the unique name to the old vertex
+ *
+ *
newUniq is the unique name change from the old vertex unique name
+ *
+ * @param oldUniq
+ * @param newUniq
+ * @param type
+ * @param createTime
+ * @return
+ */
+ boolean updateVertex(String oldUniq, String newUniq, String type, Long createTime);
+
+ /**
+ * Soft delete the existed vertices
+ *
+ *
uniq is the unique name to one vertex
+ *
+ *
type could point to multi vertices
+ *
+ * @param uniq
+ * @param type
+ * @return
+ */
+ boolean softDeleteVertices(String uniq, String type);
+
+ /**
+ * Recover the deleted vertices
+ *
+ *
uniq is the unique name to one vertex
+ *
+ *
type could point to multi vertices
+ *
+ * @param uniq
+ * @param type
+ * @return
+ */
+ boolean recoverDeletedVertices(String uniq, String type);
+
+ /**
+ * Hard delete the existed vertices
+ *
+ *
uniq is the unique name to one vertex
+ *
+ *
type could point to multi vertices
+ *
+ * @param uniq
+ * @param type
+ * @return
+ */
+ boolean hardDeleteVertices(String uniq, String type);
+
+ /**
+ * Create new edge
+ *
+ *
uniq is the unique name to one edge
+ *
+ * @param uniq
+ * @param type
+ * @param sourceVertexUniq
+ * @param targetVertexUniq
+ * @param createTime
+ * @return Edge ID(String)
+ */
+ String createEdge(
+ String uniq, String type, String sourceVertexUniq, String targetVertexUniq, Long createTime);
+
+ /**
+ * Create new edge without pre-check
+ *
+ *
uniq is the unique name to one edge
+ *
+ * @param uniq
+ * @param type
+ * @param sourceVertexId
+ * @param targetVertexId
+ * @param createTime
+ * @return Edge ID(String)
+ */
+ String createEdgeNotPreCheck(
+ String uniq, String type, Long sourceVertexId, Long targetVertexId, Long createTime);
+
+ /**
+ * Soft delete the existed edges
+ *
+ *
uniq is the unique name to one edge
+ *
+ *
type、sourceVertexUniq and targetVertexUniq could point to multi edges
+ *
+ * @param uniq
+ * @param type
+ * @param sourceVertexUniq
+ * @param targetVertexUniq
+ * @return
+ */
+ boolean softDeleteEdges(
+ String uniq, String type, String sourceVertexUniq, String targetVertexUniq);
+
+ /**
+ * Recover the deleted edges
+ *
+ *
uniq is the unique name to one edge
+ *
+ *
type、sourceVertexUniq and targetVertexUniq could point to multi edges
+ *
+ * @param uniq
+ * @param type
+ * @param sourceVertexUniq
+ * @param targetVertexUniq
+ * @return
+ */
+ boolean recoverDeletedEdges(
+ String uniq, String type, String sourceVertexUniq, String targetVertexUniq);
+
+ /**
+ * Hard delete the existed edges
+ *
+ *
uniq is the unique name to one edge
+ *
+ *
type、sourceVertexUniq and targetVertexUniq could point to multi edges
+ *
+ * @param uniq
+ * @param type
+ * @param sourceVertexUniq
+ * @param targetVertexUniq
+ * @return
+ */
+ boolean hardDeleteEdges(
+ String uniq, String type, String sourceVertexUniq, String targetVertexUniq);
+
+ /**
+ * Get the chosen vertex by uniq
+ *
+ *
uniq is the unique name to one vertex
+ *
+ * @param uniq
+ * @return
+ */
+ GraphVertex getVertex(String uniq);
+
+ /**
+ * Get some vertices by type property
+ *
+ *
type is the property value belong to the vertex
+ *
+ * @param type
+ * @return
+ */
+ List getVerticesByType(String type);
+
+ /**
+ * Get the chosen edge by uniq
+ *
+ * uniq is the unique name to one edge
+ *
+ * @param uniq
+ * @return
+ */
+ GraphEdge getEdge(String uniq);
+
+ /**
+ * Get the chosen edges
+ *
+ *
type、sourceVertexUniq and targetVertexUniq could point to multi edges
+ *
+ * @param type
+ * @param sourceVertexUniq
+ * @param targetVertexUniq
+ * @return
+ */
+ List getEdges(String type, String sourceVertexUniq, String targetVertexUniq);
+
+ /**
+ * Get source vertices and edges
+ *
+ * vertexUniq is the unique value to the vertex
+ *
+ * @param vertexUniq
+ * @return
+ */
+ Map getSourceVertexEdgeMap(String vertexUniq);
+
+ /**
+ * Get target vertices and edges
+ *
+ * vertexUniq is the unique value to the vertex
+ *
+ * @param vertexUniq
+ * @return
+ */
+ Map getTargetVertexEdgeMap(String vertexUniq);
+
+ /**
+ * Get Graph Impact Info
+ *
+ * vertexUniq is the unique value to the vertex
+ *
+ *
when depth <= 0, means traverse the entire graph
+ *
+ *
when depth > 0, means the define depth result
+ *
+ *
skipDeleted=false, return all the vertices(include the deleted vertices)
+ *
+ *
skipDeleted=true, return undeleted the vertices
+ *
+ * @param vertexUniq
+ * @param depth
+ * @param skipDeleted
+ * @return
+ */
+ GraphLineage getImpact(String vertexUniq, Integer depth, boolean skipDeleted);
+
+ /**
+ * Get Graph Lineage Info
+ *
+ *
vertexUniq is the unique value to the vertex
+ *
+ *
when depth <= 0, means traverse the entire graph
+ *
+ *
when depth > 0, means the define depth result
+ *
+ *
skipDeleted=false, return all the vertices(include the deleted vertices)
+ *
+ *
skipDeleted=true, return undeleted the vertices
+ *
+ * @param vertexUniq
+ * @param depth
+ * @param skipDeleted
+ * @return
+ */
+ GraphLineage getLineage(String vertexUniq, Integer depth, boolean skipDeleted);
+
+ /**
+ * Get Both Graph Impact and Lineage Info
+ *
+ *
vertexUniq is the unique value to the vertex
+ *
+ *
when depth <= 0, means traverse the entire graph
+ *
+ *
when depth > 0, means the define depth result
+ *
+ *
skipDeleted=false, return all the vertices(include the deleted vertices)
+ *
+ *
skipDeleted=true, return undeleted the vertices
+ *
+ * @param vertexUniq
+ * @param depth
+ * @param skipDeleted
+ * @return
+ */
+ GraphLineage getFullLineage(String vertexUniq, Integer depth, boolean skipDeleted);
+}
diff --git a/graph-common/src/main/java/org/studiox/graph/common/exception/GraphException.java b/graph-common/src/main/java/org/studiox/graph/common/exception/GraphException.java
new file mode 100644
index 0000000000000000000000000000000000000000..6deda786a4f781ae9e205b632b4764349f931669
--- /dev/null
+++ b/graph-common/src/main/java/org/studiox/graph/common/exception/GraphException.java
@@ -0,0 +1,52 @@
+package org.studiox.graph.common.exception;
+
+public class GraphException extends Exception {
+
+ private GraphExceptionCode exceptionCode;
+
+ public GraphException(GraphExceptionCode exceptionCode) {
+ super();
+ this.setExceptionCode(exceptionCode);
+ }
+
+ public GraphException(String message, GraphExceptionCode exceptionCode) {
+ super(exceptionCode.getExceptionMsg(message));
+ this.setExceptionCode(exceptionCode);
+ }
+
+ public GraphException(Throwable cause, GraphExceptionCode exceptionCode) {
+ super(cause);
+ this.setExceptionCode(exceptionCode);
+ }
+
+ public GraphException(String message, Throwable cause, GraphExceptionCode exceptionCode) {
+ super(exceptionCode.getExceptionMsg(message), cause);
+ this.setExceptionCode(exceptionCode);
+ }
+
+ public GraphException(
+ String message,
+ Throwable cause,
+ boolean enableSuppression,
+ boolean writableStackTrace,
+ GraphExceptionCode exceptionCode) {
+ super(exceptionCode.getExceptionMsg(message), cause, enableSuppression, writableStackTrace);
+ this.setExceptionCode(exceptionCode);
+ }
+
+ public GraphExceptionCode getExceptionCode() {
+ return exceptionCode;
+ }
+
+ public void setExceptionCode(GraphExceptionCode exceptionCode) {
+ this.exceptionCode = exceptionCode;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer stringBuffer = new StringBuffer("GraphException{");
+ stringBuffer.append("exceptionCode=").append(exceptionCode);
+ stringBuffer.append('}');
+ return stringBuffer.toString();
+ }
+}
diff --git a/graph-common/src/main/java/org/studiox/graph/common/exception/GraphExceptionCode.java b/graph-common/src/main/java/org/studiox/graph/common/exception/GraphExceptionCode.java
new file mode 100644
index 0000000000000000000000000000000000000000..2e9da32fa44beee1cef3249cbb01a4e49003ce2b
--- /dev/null
+++ b/graph-common/src/main/java/org/studiox/graph/common/exception/GraphExceptionCode.java
@@ -0,0 +1,59 @@
+package org.studiox.graph.common.exception;
+
+public enum GraphExceptionCode {
+ CONFIG_FILE_NOT_EXIST("GE0001", "图库配置文件不存在,请仔细检查!"),
+
+ CONFIG_PREFIX_NOT_EXIST("GE0002", "图库配置项前缀不存在,请仔细检查!"),
+
+ CONFIG_FORMAT_NOT_CORRECT("GE0003", "图库配置文件格式不正确,请仔细检查!"),
+
+ JANUS_GRAPH_EXCEPTION("GE0004", "JanusGraphs实例方法调用异常,请详细查看异常栈等日志信息!");
+
+ private String code;
+
+ private String desc;
+
+ GraphExceptionCode(String code, String desc) {
+ this.setCode(code);
+ this.setDesc(desc);
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public String getExceptionMsg() {
+ return "Graph Exception code='" + getCode() + "' and desc='" + getDesc() + "'.";
+ }
+
+ public String getExceptionMsg(String detailMsg) {
+ return "Graph Exception code='"
+ + getCode()
+ + "' and desc='"
+ + getDesc()
+ + "', with the detail msg='"
+ + detailMsg
+ + "'.";
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer stringBuffer = new StringBuffer("GraphExceptionCode{");
+ stringBuffer.append("code='").append(code).append('\'');
+ stringBuffer.append(", desc='").append(desc).append('\'');
+ stringBuffer.append('}');
+ return stringBuffer.toString();
+ }
+}
diff --git a/graph-common/src/main/java/org/studiox/graph/common/exception/GraphRuntimeException.java b/graph-common/src/main/java/org/studiox/graph/common/exception/GraphRuntimeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..955dbe44f3e2ba9034f69be0f5733e037a4df6e0
--- /dev/null
+++ b/graph-common/src/main/java/org/studiox/graph/common/exception/GraphRuntimeException.java
@@ -0,0 +1,52 @@
+package org.studiox.graph.common.exception;
+
+public class GraphRuntimeException extends RuntimeException {
+
+ private GraphExceptionCode exceptionCode;
+
+ public GraphRuntimeException(GraphExceptionCode exceptionCode) {
+ super();
+ this.exceptionCode = exceptionCode;
+ }
+
+ public GraphRuntimeException(String message, GraphExceptionCode exceptionCode) {
+ super(exceptionCode.getExceptionMsg(message));
+ this.exceptionCode = exceptionCode;
+ }
+
+ public GraphRuntimeException(Throwable cause, GraphExceptionCode exceptionCode) {
+ super(cause);
+ this.exceptionCode = exceptionCode;
+ }
+
+ public GraphRuntimeException(String message, Throwable cause, GraphExceptionCode exceptionCode) {
+ super(exceptionCode.getExceptionMsg(message), cause);
+ this.exceptionCode = exceptionCode;
+ }
+
+ public GraphRuntimeException(
+ String message,
+ Throwable cause,
+ boolean enableSuppression,
+ boolean writableStackTrace,
+ GraphExceptionCode exceptionCode) {
+ super(exceptionCode.getExceptionMsg(message), cause, enableSuppression, writableStackTrace);
+ this.exceptionCode = exceptionCode;
+ }
+
+ public GraphExceptionCode getExceptionCode() {
+ return exceptionCode;
+ }
+
+ public void setExceptionCode(GraphExceptionCode exceptionCode) {
+ this.exceptionCode = exceptionCode;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer stringBuffer = new StringBuffer("GraphRuntimeException{");
+ stringBuffer.append("exceptionCode=").append(exceptionCode);
+ stringBuffer.append('}');
+ return stringBuffer.toString();
+ }
+}
diff --git a/graph-common/src/test/java/org/studiox/graph/common/GraphConfigTest.java b/graph-common/src/test/java/org/studiox/graph/common/GraphConfigTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c69d962d21bef516628c8b06cfebffdd4a1d43f8
--- /dev/null
+++ b/graph-common/src/test/java/org/studiox/graph/common/GraphConfigTest.java
@@ -0,0 +1,32 @@
+package org.studiox.graph.common;
+
+import org.apache.commons.configuration.Configuration;
+import org.junit.*;
+import org.junit.runners.MethodSorters;
+import org.studiox.graph.common.exception.GraphException;
+
+import static org.studiox.graph.common.GraphConstant.JanusGraphConfigConstant.GREMLIN_GRAPH;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class GraphConfigTest {
+
+ private static Configuration config = null;
+
+ @BeforeClass
+ public static void setUp() {
+ GraphConfig.forceReload();
+ }
+
+ @AfterClass
+ public static void tearDown() {
+ config = null;
+ }
+
+ @Test
+ public void test_01_getDefaultGraphConfig() throws GraphException {
+ config = GraphConfig.getGraphConfig();
+ Assert.assertNotNull(config);
+ String actualGremlinGraph = config.getString(GREMLIN_GRAPH);
+ Assert.assertEquals("org.janusgraph.core.JanusGraphFactory", actualGremlinGraph);
+ }
+}
diff --git a/graph-common/src/test/resources/graph.properties b/graph-common/src/test/resources/graph.properties
new file mode 100755
index 0000000000000000000000000000000000000000..c42c92eae0e647da813529c00d0be4d4051c1ba8
--- /dev/null
+++ b/graph-common/src/test/resources/graph.properties
@@ -0,0 +1,30 @@
+###################################################################
+graph.force-index=true
+graph.schema.default=none
+graph.storage.batch-loading=true
+###################################################################
+graph.gremlin.graph=org.janusgraph.core.JanusGraphFactory
+###################################################################
+#graph.storage.backend=inmemory
+###################################################################
+graph.cache.db-cache=false
+graph.ids.block-size=20000000
+graph.ids.renew-timeout=3600000
+graph.storage.buffer-size=20240
+graph.storage.read-attempts=100
+graph.storage.write-attempts=100
+graph.storage.attempt-wait=1000
+###################################################################
+graph.storage.backend=hbase
+graph.storage.hostname=localhost
+graph.storage.hbase.table=graph_table_1
+graph.storage.hbase.ext.zookeeper.znode.parent=/hbase1
+graph.storage.hbase.ext.hbase.rpc.timeout=300000
+graph.storage.hbase.ext.hbase.client.operation.timeout=300000
+graph.storage.hbase.ext.hbase.client.scanner.timeout.period=300000
+graph.storage.hbase.region-count=9
+graph.storage.hbase.regions-per-server=3
+###################################################################
+graph.index.search.backend=elasticsearch
+graph.index.search.hostname=localhost:9200
+###################################################################
diff --git a/graph-janusgraph/janusgraph-common/pom.xml b/graph-janusgraph/janusgraph-common/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c1998d975c2e0b4b989dfb76286057125ae64702
--- /dev/null
+++ b/graph-janusgraph/janusgraph-common/pom.xml
@@ -0,0 +1,26 @@
+
+
+ 4.0.0
+
+ org.studiox.graph
+ graph-janusgraph
+ 1.0.5-SNAPSHOT
+
+ org.studiox.graph.janusgraph
+ janusgraph-common
+ 1.0.5-SNAPSHOT
+ jar
+
+
+ junit
+ junit
+ provided
+
+
+ org.studiox.graph
+ graph-common
+
+
+
diff --git a/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/AbstractJanusGraph.java b/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/AbstractJanusGraph.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a77f1666e17564828e641fbafe0bc1f2553972e
--- /dev/null
+++ b/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/AbstractJanusGraph.java
@@ -0,0 +1,470 @@
+package org.studiox.graph.janusgraph.common;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.lang.StringUtils;
+import org.studiox.graph.common.GraphConfig;
+import org.studiox.graph.common.IGraphWrapper;
+import org.studiox.graph.common.exception.GraphException;
+
+import java.util.Iterator;
+import java.util.concurrent.ExecutionException;
+
+import static org.studiox.graph.common.GraphConstant.JanusGraphConfigConstant.*;
+import static org.studiox.graph.common.GraphConstant.JanusGraphInstanceConstant.GRAPH_UNIQUE_INSTANCE_ID;
+import static org.studiox.graph.common.GraphConstant.JanusGraphInstanceConstant.GRAPH_UNIQUE_INSTANCE_PREFIX;
+import static org.studiox.graph.common.GraphConstant.JanusGraphLabelPropertyKeyIndexConstant.*;
+import static org.studiox.graph.common.GraphConstant.Separator.DOT;
+import static org.studiox.graph.common.exception.GraphExceptionCode.JANUS_GRAPH_EXCEPTION;
+
+/**
+ * 遍历操作
+ *
+ *
out()、in()、both()、outE()、inE()、bothE()、outV()、inV()、bothV()、otherV()
+ *
+ *
遍历(以定点为基础)
+ *
+ *
1.out(label):根据指定的 Edge Label 来访问顶点的 OUT 方向邻接点(可以是零个 Edge Label,代表所有类型边
+ *
+ *
也可以一个或多个 Edge Label,代表任意给定 Edge Label 的边,下同)
+ *
+ *
2.in(label):根据指定的 Edge Label 来访问顶点的 IN 方向邻接点
+ *
+ *
3.both(label):根据指定的 Edge Label 来访问顶点的双向邻接点
+ *
+ *
4.outE(label): 根据指定的 Edge Label 来访问顶点的 OUT 方向邻接边
+ *
+ *
5.inE(label):根据指定的 Edge Label 来访问顶点的 IN 方向邻接边
+ *
+ *
6.bothE(label):根据指定的 Edge Label 来访问顶点的双向邻接边
+ *
+ *
遍历(以边为基础)
+ *
+ *
1.outV():访问边的出顶点,出顶点是指边的起始顶点
+ *
+ *
2.inV():访问边的入顶点,入顶点是指边的目标顶点,也就是箭头指向的顶点
+ *
+ *
3.bothV():访问边的双向顶点
+ *
+ *
4.otherV():访问边的伙伴顶点,即相对于基准顶点而言的另一端的顶点
+ *
+ *
查询路径path
+ *
+ *
path()、simplePath()、cyclicPath() 路径:就是经过的顶点成为路径
+ *
+ *
Path说明
+ *
+ *
在使用Gremlin对图进行分析时,关注点有时并不仅仅在最终到达的顶点、边或者属性上,通过什么样的路径到达最终的顶点、边和属性同样重要
+ *
+ *
此时可以借助path()来获取经过的路径信息。
+ *
+ *
path()返回当前遍历过的所有路径。有时需要对路径进行过滤,只选择没有环路的路径或者选择包含环路的路径
+ *
+ *
Gremlin针对这种需求提供了两种过滤路径的step:simplePath()和cyclicPath()
+ *
+ *
path()返回所有路径,包含有环路径和无环路径 simplePath(),过滤掉路径中含有环路的对象,只保留路径中不含有环路的对象
+ *
+ *
cyclicPath(),过滤掉路径中不含有环路的对象,只保留路径中含有环路的对象
+ *
+ *
循环操作
+ *
+ *
repeat()、times()、until()、emit()、loops()
+ *
+ *
repeat+times 根据次数来重复执行语句
+ *
+ *
repeat() + until() 根据条件来重复执行语句
+ *
+ *
repeat() + emit() 收集执行过程中的数据
+ *
+ *
repeat() + loops() 根据最大次数限制来重复执行语句
+ */
+public abstract class AbstractJanusGraph implements IGraphWrapper {
+
+ private static final String VERTEX_UNIQ_ONLY_INDEX = "VERTEX_UNIQ_ONLY_INDEX";
+
+ private static final String VERTEX_UNIQ_INDEX = "VERTEX_UNIQ_INDEX";
+
+ private static final String VERTEX_TYPE_INDEX = "VERTEX_TYPE_INDEX";
+
+ private static final String VERTEX_DELETED_INDEX = "VERTEX_DELETED_INDEX";
+
+ private static final String VERTEX_CREATE_TIME_INDEX = "VERTEX_CREATE_TIME_INDEX";
+
+ private static final String EDGE_UNIQ_INDEX = "EDGE_UNIQ_INDEX";
+
+ private static final String EDGE_TYPE_INDEX = "EDGE_TYPE_INDEX";
+
+ private static final String EDGE_DELETED_INDEX = "EDGE_DELETED_INDEX";
+
+ private static final String EDGE_SOURCE_UNIQ_INDEX = "EDGE_SOURCE_UNIQ_INDEX";
+
+ private static final String EDGE_TARGET_UNIQ_INDEX = "EDGE_TARGET_UNIQ_INDEX";
+
+ private static final String EDGE_CREATE_TIME_INDEX = "EDGE_CREATE_TIME_INDEX";
+
+ private static final String EDGE_SOURCE_TARGET_UNIQ_INDEX = "EDGE_SOURCE_TARGET_UNIQ_INDEX";
+
+ private static final String EDGE_TYPE_SOURCE_UNIQ_INDEX = "EDGE_TYPE_SOURCE_UNIQ_INDEX";
+
+ private static final String EDGE_TYPE_TARGET_UNIQ_INDEX = "EDGE_TYPE_TARGET_UNIQ_INDEX";
+
+ private static final String EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX =
+ "EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX";
+
+ public abstract void setBuilderConfig(String key, Object value);
+
+ public void buildGraphConfig() throws GraphException {
+ Configuration graphConfig = GraphConfig.getGraphConfig();
+ Iterator iterator = graphConfig.getKeys();
+ while (iterator.hasNext()) {
+ String key = iterator.next();
+ setBuilderConfig(key, graphConfig.getProperty(key));
+ }
+ }
+
+ public void buildGraphConfig(Configuration config, String hbaseTableName) {
+ if (!config.containsKey(STORAGE_BACKEND)
+ || config.getString(STORAGE_BACKEND).equalsIgnoreCase(BACKEND_MEMORY)) {
+ setBuilderConfig(STORAGE_BACKEND, BACKEND_MEMORY);
+ setBuilderConfig(GREMLIN_GRAPH, JANUSGRAPH_FACTORY);
+ return;
+ }
+ Iterator iterator = config.getKeys();
+ while (iterator.hasNext()) {
+ String key = iterator.next();
+ if (key.substring(0, key.indexOf(DOT)).equalsIgnoreCase(INDEX_PREFIX)) {
+ continue;
+ }
+ setBuilderConfig(key, config.getProperty(key));
+ }
+ if (StringUtils.isNotBlank(hbaseTableName)) {
+ setBuilderConfig(STORAGE_HBASE_TABLE, hbaseTableName);
+ }
+ setBuilderConfig(
+ GRAPH_UNIQUE_INSTANCE_ID, GRAPH_UNIQUE_INSTANCE_PREFIX + System.currentTimeMillis());
+ }
+
+ public abstract boolean mgmtNotContainsVertexLabel(String vertexLabelName);
+
+ public abstract void mgmtMakeVertexLabel(String vertexLabelName);
+
+ public abstract boolean mgmtNotContainsEdgeLabel(String edgeLabelName);
+
+ public abstract void mgmtMakeEdgeLabel(String edgeLabelName);
+
+ private void buildGraphLabel() {
+ if (mgmtNotContainsVertexLabel(LABEL_VERTEX)) {
+ mgmtMakeVertexLabel(LABEL_VERTEX);
+ }
+ if (mgmtNotContainsEdgeLabel(LABEL_EDGE)) {
+ mgmtMakeEdgeLabel(LABEL_EDGE);
+ }
+ }
+
+ public abstract boolean mgmtNotContainsPropertyKey(String propertyKeyName);
+
+ public abstract void mgmtMakePropertyKey(String propertyKeyName, Class> zlass);
+
+ private void buildGraphPropertyKey() {
+ if (mgmtNotContainsPropertyKey(VERTEX_PROPERTY_UNIQ)) {
+ mgmtMakePropertyKey(VERTEX_PROPERTY_UNIQ, String.class);
+ }
+ if (mgmtNotContainsPropertyKey(VERTEX_PROPERTY_TYPE)) {
+ mgmtMakePropertyKey(VERTEX_PROPERTY_TYPE, String.class);
+ }
+ if (mgmtNotContainsPropertyKey(VERTEX_PROPERTY_DELETED)) {
+ mgmtMakePropertyKey(VERTEX_PROPERTY_DELETED, Boolean.class);
+ }
+ if (mgmtNotContainsPropertyKey(VERTEX_PROPERTY_CREATE_TIME)) {
+ mgmtMakePropertyKey(VERTEX_PROPERTY_CREATE_TIME, Long.class);
+ }
+
+ if (mgmtNotContainsPropertyKey(EDGE_PROPERTY_UNIQ)) {
+ mgmtMakePropertyKey(EDGE_PROPERTY_UNIQ, String.class);
+ }
+ if (mgmtNotContainsPropertyKey(EDGE_PROPERTY_TYPE)) {
+ mgmtMakePropertyKey(EDGE_PROPERTY_TYPE, String.class);
+ }
+ if (mgmtNotContainsPropertyKey(EDGE_PROPERTY_DELETED)) {
+ mgmtMakePropertyKey(EDGE_PROPERTY_DELETED, Boolean.class);
+ }
+ if (mgmtNotContainsPropertyKey(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ)) {
+ mgmtMakePropertyKey(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ, String.class);
+ }
+ if (mgmtNotContainsPropertyKey(EDGE_PROPERTY_TARGET_VERTEX_UNIQ)) {
+ mgmtMakePropertyKey(EDGE_PROPERTY_TARGET_VERTEX_UNIQ, String.class);
+ }
+ if (mgmtNotContainsPropertyKey(EDGE_PROPERTY_CREATE_TIME)) {
+ mgmtMakePropertyKey(EDGE_PROPERTY_CREATE_TIME, Long.class);
+ }
+ }
+
+ public abstract boolean mgmtNotContainsGraphIndex(String indexName);
+
+ public abstract void mgmtBuildVertexIndexOnlyWithOneKeyUnique(
+ String indexName, String propertyKeyName, String labelName);
+
+ public abstract void mgmtBuildVertexIndexWithOneKey(String indexName, String propertyKeyName);
+
+ public abstract void mgmtBuildEdgeIndexWithOneKey(String indexName, String propertyKeyName);
+
+ public abstract void mgmtBuildEdgeIndexWithTwoKey(
+ String indexName, String firstPropertyKeyName, String secondPropertyKeyName);
+
+ public abstract void mgmtBuildEdgeIndexWithThreeKey(
+ String indexName,
+ String firstPropertyKeyName,
+ String secondPropertyKeyName,
+ String thirdPropertyKeyName);
+
+ public abstract boolean mgmtNotContainsRelationIndex(
+ String edgeLabelName, String relationIndexName);
+
+ public abstract void mgmtBuildRelationIndexWithOneKey(
+ String edgeLabelName, String relationIndexName, String propertyKeyName);
+
+ public abstract void mgmtBuildRelationIndexWithTwoKey(
+ String edgeLabelName,
+ String relationIndexName,
+ String firstPropertyKeyName,
+ String secondPropertyKeyName);
+
+ public abstract void mgmtBuildRelationIndexWithThreeKey(
+ String edgeLabelName,
+ String relationIndexName,
+ String firstPropertyKeyName,
+ String secondPropertyKeyName,
+ String thirdPropertyKeyName);
+
+ private void buildGraphVertexIndex() {
+ if (mgmtNotContainsGraphIndex(VERTEX_UNIQ_ONLY_INDEX)) {
+ mgmtBuildVertexIndexOnlyWithOneKeyUnique(
+ VERTEX_UNIQ_ONLY_INDEX, VERTEX_PROPERTY_UNIQ, LABEL_VERTEX);
+ }
+ if (mgmtNotContainsGraphIndex(VERTEX_UNIQ_INDEX)) {
+ mgmtBuildVertexIndexWithOneKey(VERTEX_UNIQ_INDEX, VERTEX_PROPERTY_UNIQ);
+ }
+ if (mgmtNotContainsGraphIndex(VERTEX_TYPE_INDEX)) {
+ mgmtBuildVertexIndexWithOneKey(VERTEX_TYPE_INDEX, VERTEX_PROPERTY_TYPE);
+ }
+ if (mgmtNotContainsGraphIndex(VERTEX_DELETED_INDEX)) {
+ mgmtBuildVertexIndexWithOneKey(VERTEX_DELETED_INDEX, VERTEX_PROPERTY_DELETED);
+ }
+ if (mgmtNotContainsGraphIndex(VERTEX_CREATE_TIME_INDEX)) {
+ mgmtBuildVertexIndexWithOneKey(VERTEX_CREATE_TIME_INDEX, VERTEX_PROPERTY_CREATE_TIME);
+ }
+ }
+
+ private void buildGraphEdgeIndex() {
+ if (mgmtNotContainsGraphIndex(EDGE_UNIQ_INDEX)) {
+ mgmtBuildEdgeIndexWithOneKey(EDGE_UNIQ_INDEX, EDGE_PROPERTY_UNIQ);
+ }
+ if (mgmtNotContainsGraphIndex(EDGE_TYPE_INDEX)) {
+ mgmtBuildEdgeIndexWithOneKey(EDGE_TYPE_INDEX, EDGE_PROPERTY_TYPE);
+ }
+ if (mgmtNotContainsGraphIndex(EDGE_DELETED_INDEX)) {
+ mgmtBuildEdgeIndexWithOneKey(EDGE_DELETED_INDEX, EDGE_PROPERTY_DELETED);
+ }
+ if (mgmtNotContainsGraphIndex(EDGE_SOURCE_UNIQ_INDEX)) {
+ mgmtBuildEdgeIndexWithOneKey(EDGE_SOURCE_UNIQ_INDEX, EDGE_PROPERTY_SOURCE_VERTEX_UNIQ);
+ }
+ if (mgmtNotContainsGraphIndex(EDGE_TARGET_UNIQ_INDEX)) {
+ mgmtBuildEdgeIndexWithOneKey(EDGE_TARGET_UNIQ_INDEX, EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
+ }
+ if (mgmtNotContainsGraphIndex(EDGE_CREATE_TIME_INDEX)) {
+ mgmtBuildEdgeIndexWithOneKey(EDGE_CREATE_TIME_INDEX, EDGE_PROPERTY_CREATE_TIME);
+ }
+
+ if (mgmtNotContainsGraphIndex(EDGE_SOURCE_TARGET_UNIQ_INDEX)) {
+ mgmtBuildEdgeIndexWithTwoKey(
+ EDGE_SOURCE_TARGET_UNIQ_INDEX,
+ EDGE_PROPERTY_SOURCE_VERTEX_UNIQ,
+ EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
+ }
+ if (mgmtNotContainsGraphIndex(EDGE_TYPE_SOURCE_UNIQ_INDEX)) {
+ mgmtBuildEdgeIndexWithTwoKey(
+ EDGE_TYPE_SOURCE_UNIQ_INDEX, EDGE_PROPERTY_TYPE, EDGE_PROPERTY_SOURCE_VERTEX_UNIQ);
+ }
+ if (mgmtNotContainsGraphIndex(EDGE_TYPE_TARGET_UNIQ_INDEX)) {
+ mgmtBuildEdgeIndexWithTwoKey(
+ EDGE_TYPE_TARGET_UNIQ_INDEX, EDGE_PROPERTY_TYPE, EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
+ }
+
+ if (mgmtNotContainsGraphIndex(EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX)) {
+ mgmtBuildEdgeIndexWithThreeKey(
+ EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX,
+ EDGE_PROPERTY_TYPE,
+ EDGE_PROPERTY_SOURCE_VERTEX_UNIQ,
+ EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
+ }
+ }
+
+ private void buildGraphRelationIndex() {
+ if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_UNIQ_INDEX)) {
+ mgmtBuildRelationIndexWithOneKey(LABEL_EDGE, EDGE_UNIQ_INDEX, EDGE_PROPERTY_UNIQ);
+ }
+ if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_TYPE_INDEX)) {
+ mgmtBuildRelationIndexWithOneKey(LABEL_EDGE, EDGE_TYPE_INDEX, EDGE_PROPERTY_TYPE);
+ }
+ if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_DELETED_INDEX)) {
+ mgmtBuildRelationIndexWithOneKey(LABEL_EDGE, EDGE_DELETED_INDEX, EDGE_PROPERTY_DELETED);
+ }
+ if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_SOURCE_UNIQ_INDEX)) {
+ mgmtBuildRelationIndexWithOneKey(
+ LABEL_EDGE, EDGE_SOURCE_UNIQ_INDEX, EDGE_PROPERTY_SOURCE_VERTEX_UNIQ);
+ }
+ if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_TARGET_UNIQ_INDEX)) {
+ mgmtBuildRelationIndexWithOneKey(
+ LABEL_EDGE, EDGE_TARGET_UNIQ_INDEX, EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
+ }
+ if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_CREATE_TIME_INDEX)) {
+ mgmtBuildRelationIndexWithOneKey(
+ LABEL_EDGE, EDGE_CREATE_TIME_INDEX, EDGE_PROPERTY_CREATE_TIME);
+ }
+
+ if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_SOURCE_TARGET_UNIQ_INDEX)) {
+ mgmtBuildRelationIndexWithTwoKey(
+ LABEL_EDGE,
+ EDGE_SOURCE_TARGET_UNIQ_INDEX,
+ EDGE_PROPERTY_SOURCE_VERTEX_UNIQ,
+ EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
+ }
+ if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_TYPE_SOURCE_UNIQ_INDEX)) {
+ mgmtBuildRelationIndexWithTwoKey(
+ LABEL_EDGE,
+ EDGE_TYPE_SOURCE_UNIQ_INDEX,
+ EDGE_PROPERTY_TYPE,
+ EDGE_PROPERTY_SOURCE_VERTEX_UNIQ);
+ }
+ if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_TYPE_TARGET_UNIQ_INDEX)) {
+ mgmtBuildRelationIndexWithTwoKey(
+ LABEL_EDGE,
+ EDGE_TYPE_TARGET_UNIQ_INDEX,
+ EDGE_PROPERTY_TYPE,
+ EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
+ }
+
+ if (mgmtNotContainsRelationIndex(LABEL_EDGE, EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX)) {
+ mgmtBuildRelationIndexWithThreeKey(
+ LABEL_EDGE,
+ EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX,
+ EDGE_PROPERTY_TYPE,
+ EDGE_PROPERTY_SOURCE_VERTEX_UNIQ,
+ EDGE_PROPERTY_TARGET_VERTEX_UNIQ);
+ }
+ }
+
+ public abstract void mgmtCommit();
+
+ public abstract void mgmtRollback();
+
+ public abstract void updateGraphIndexWithReindex(String indexName)
+ throws ExecutionException, InterruptedException;
+
+ public abstract void updateRelationIndexWithReindex(
+ String edgeLabelName, String relationIndexName)
+ throws ExecutionException, InterruptedException;
+
+ private void updateGraphIndex() throws ExecutionException, InterruptedException {
+ try {
+ updateGraphIndexWithReindex(VERTEX_UNIQ_ONLY_INDEX);
+ updateGraphIndexWithReindex(VERTEX_UNIQ_INDEX);
+ updateGraphIndexWithReindex(VERTEX_TYPE_INDEX);
+ updateGraphIndexWithReindex(VERTEX_DELETED_INDEX);
+ updateGraphIndexWithReindex(VERTEX_CREATE_TIME_INDEX);
+
+ updateGraphIndexWithReindex(EDGE_UNIQ_INDEX);
+ updateGraphIndexWithReindex(EDGE_TYPE_INDEX);
+ updateGraphIndexWithReindex(EDGE_DELETED_INDEX);
+ updateGraphIndexWithReindex(EDGE_SOURCE_UNIQ_INDEX);
+ updateGraphIndexWithReindex(EDGE_TARGET_UNIQ_INDEX);
+ updateGraphIndexWithReindex(EDGE_CREATE_TIME_INDEX);
+ updateGraphIndexWithReindex(EDGE_SOURCE_TARGET_UNIQ_INDEX);
+ updateGraphIndexWithReindex(EDGE_TYPE_SOURCE_UNIQ_INDEX);
+ updateGraphIndexWithReindex(EDGE_TYPE_TARGET_UNIQ_INDEX);
+ updateGraphIndexWithReindex(EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX);
+
+ mgmtCommit();
+ } catch (ExecutionException | InterruptedException e) {
+ mgmtRollback();
+ throw e;
+ }
+ }
+
+ private void updateGraphRelationIndex() throws ExecutionException, InterruptedException {
+ try {
+ updateRelationIndexWithReindex(LABEL_EDGE, EDGE_UNIQ_INDEX);
+ updateRelationIndexWithReindex(LABEL_EDGE, EDGE_TYPE_INDEX);
+ updateRelationIndexWithReindex(LABEL_EDGE, EDGE_DELETED_INDEX);
+ updateRelationIndexWithReindex(LABEL_EDGE, EDGE_SOURCE_UNIQ_INDEX);
+ updateRelationIndexWithReindex(LABEL_EDGE, EDGE_TARGET_UNIQ_INDEX);
+ updateRelationIndexWithReindex(LABEL_EDGE, EDGE_CREATE_TIME_INDEX);
+ updateRelationIndexWithReindex(LABEL_EDGE, EDGE_SOURCE_TARGET_UNIQ_INDEX);
+ updateRelationIndexWithReindex(LABEL_EDGE, EDGE_TYPE_SOURCE_UNIQ_INDEX);
+ updateRelationIndexWithReindex(LABEL_EDGE, EDGE_TYPE_TARGET_UNIQ_INDEX);
+ updateRelationIndexWithReindex(LABEL_EDGE, EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX);
+
+ mgmtCommit();
+ } catch (ExecutionException | InterruptedException e) {
+ mgmtRollback();
+ throw e;
+ }
+ }
+
+ public abstract void awaitGraphIndexStatusWithEnabled(String indexName)
+ throws InterruptedException;
+
+ public abstract void awaitRelationIndexStatusWithEnabled(
+ String edgeLabelName, String relationIndexName) throws InterruptedException;
+
+ private void awaitGraphIndexStatus() throws InterruptedException {
+ awaitGraphIndexStatusWithEnabled(VERTEX_UNIQ_ONLY_INDEX);
+ awaitGraphIndexStatusWithEnabled(VERTEX_UNIQ_INDEX);
+ awaitGraphIndexStatusWithEnabled(VERTEX_TYPE_INDEX);
+ awaitGraphIndexStatusWithEnabled(VERTEX_DELETED_INDEX);
+ awaitGraphIndexStatusWithEnabled(VERTEX_CREATE_TIME_INDEX);
+
+ awaitGraphIndexStatusWithEnabled(EDGE_UNIQ_INDEX);
+ awaitGraphIndexStatusWithEnabled(EDGE_TYPE_INDEX);
+ awaitGraphIndexStatusWithEnabled(EDGE_DELETED_INDEX);
+ awaitGraphIndexStatusWithEnabled(EDGE_SOURCE_UNIQ_INDEX);
+ awaitGraphIndexStatusWithEnabled(EDGE_TARGET_UNIQ_INDEX);
+ awaitGraphIndexStatusWithEnabled(EDGE_CREATE_TIME_INDEX);
+ awaitGraphIndexStatusWithEnabled(EDGE_SOURCE_TARGET_UNIQ_INDEX);
+ awaitGraphIndexStatusWithEnabled(EDGE_TYPE_SOURCE_UNIQ_INDEX);
+ awaitGraphIndexStatusWithEnabled(EDGE_TYPE_TARGET_UNIQ_INDEX);
+ awaitGraphIndexStatusWithEnabled(EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX);
+ }
+
+ private void awaitGraphRelationIndexStatus() throws InterruptedException {
+ awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_UNIQ_INDEX);
+ awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_TYPE_INDEX);
+ awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_DELETED_INDEX);
+ awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_SOURCE_UNIQ_INDEX);
+ awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_TARGET_UNIQ_INDEX);
+ awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_CREATE_TIME_INDEX);
+ awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_SOURCE_TARGET_UNIQ_INDEX);
+ awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_TYPE_SOURCE_UNIQ_INDEX);
+ awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_TYPE_TARGET_UNIQ_INDEX);
+ awaitRelationIndexStatusWithEnabled(LABEL_EDGE, EDGE_TYPE_SOURCE_TARGET_UNIQ_INDEX);
+ }
+
+ @Override
+ public void open() throws GraphException {
+ try {
+ buildGraphLabel();
+ buildGraphPropertyKey();
+ buildGraphVertexIndex();
+ buildGraphEdgeIndex();
+ buildGraphRelationIndex();
+ mgmtCommit();
+ // updateGraphIndex();
+ // updateGraphRelationIndex();
+ // awaitGraphIndexStatus();
+ // awaitGraphRelationIndexStatus();
+ } catch (Throwable t) {
+ throw new GraphException(t, JANUS_GRAPH_EXCEPTION);
+ }
+ }
+
+ public abstract Long getJanusGraphVertexId(String uniq);
+}
diff --git a/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/JanusGraphEdge.java b/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/JanusGraphEdge.java
new file mode 100644
index 0000000000000000000000000000000000000000..d125fa3a3ff7dd7a8e03c1fa3e42d83db066a7c2
--- /dev/null
+++ b/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/JanusGraphEdge.java
@@ -0,0 +1,76 @@
+package org.studiox.graph.janusgraph.common;
+
+import org.studiox.graph.common.GraphEdge;
+
+import java.util.Objects;
+
+public class JanusGraphEdge extends GraphEdge {
+
+ private String id;
+
+ private Long sourceVertexId;
+
+ private Long targetVertexId;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public Long getSourceVertexId() {
+ return sourceVertexId;
+ }
+
+ public void setSourceVertexId(Long sourceVertexId) {
+ this.sourceVertexId = sourceVertexId;
+ }
+
+ public Long getTargetVertexId() {
+ return targetVertexId;
+ }
+
+ public void setTargetVertexId(Long targetVertexId) {
+ this.targetVertexId = targetVertexId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ JanusGraphEdge that = (JanusGraphEdge) o;
+ return Objects.equals(id, that.id)
+ && Objects.equals(sourceVertexId, that.sourceVertexId)
+ && Objects.equals(targetVertexId, that.targetVertexId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), id, sourceVertexId, targetVertexId);
+ }
+
+ @Override
+ public String toString() {
+ return "JanusGraphEdge{"
+ + "id='"
+ + id
+ + '\''
+ + ", sourceVertexId="
+ + sourceVertexId
+ + ", targetVertexId="
+ + targetVertexId
+ + '}'
+ + ",GraphEdge{"
+ + super.toString()
+ + "}";
+ }
+}
diff --git a/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/JanusGraphVertex.java b/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/JanusGraphVertex.java
new file mode 100644
index 0000000000000000000000000000000000000000..3b2ff93247d77cd4ed9404b3e8ffc178d505dac8
--- /dev/null
+++ b/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/JanusGraphVertex.java
@@ -0,0 +1,43 @@
+package org.studiox.graph.janusgraph.common;
+
+import org.studiox.graph.common.GraphVertex;
+
+import java.util.Objects;
+
+public class JanusGraphVertex extends GraphVertex {
+
+ private Long id;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ JanusGraphVertex that = (JanusGraphVertex) o;
+ return Objects.equals(id, that.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), id);
+ }
+
+ @Override
+ public String toString() {
+ return "JanusGraphVertex{" + "id=" + id + '}' + ",GraphVertex{" + super.toString() + "}";
+ }
+}
diff --git a/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/test/JanusGraphTest.java b/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/test/JanusGraphTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..378a47bf1251e1a5228945c752c3d57f60f202ac
--- /dev/null
+++ b/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/test/JanusGraphTest.java
@@ -0,0 +1,551 @@
+package org.studiox.graph.janusgraph.common.test;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+import org.studiox.graph.common.GraphEdge;
+import org.studiox.graph.common.GraphLineage;
+import org.studiox.graph.common.GraphVertex;
+import org.studiox.graph.common.exception.GraphException;
+import org.studiox.graph.janusgraph.common.AbstractJanusGraph;
+
+import java.util.List;
+import java.util.Map;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class JanusGraphTest {
+
+ private static AbstractJanusGraph janusGraph;
+
+ public AbstractJanusGraph getJanusGraph() {
+ return janusGraph;
+ }
+
+ public void setJanusGraph(AbstractJanusGraph janusGraph) {
+ JanusGraphTest.janusGraph = janusGraph;
+ }
+
+ public static void init(AbstractJanusGraph janusGraph) throws GraphException {
+ JanusGraphTest.janusGraph = janusGraph;
+ janusGraph.open();
+ janusGraph.hardDeleteVertices(null, "type1");
+ janusGraph.hardDeleteEdges(null, "type1", null, null);
+ }
+
+ @AfterClass
+ public static void clean() {
+ janusGraph.close();
+ }
+
+ @Test
+ public void test_01_createVertexTest() {
+ Long vertexId1 = janusGraph.createVertex("qualifiedName1", "type1", null);
+ Assert.assertNotNull(vertexId1);
+ Long vertexId2 = janusGraph.createVertex("qualifiedName1", "type1", null);
+ Assert.assertNull(vertexId2);
+ Assert.assertEquals(janusGraph.getVerticesByType("type1").size(), 1);
+ }
+
+ @Test
+ public void test_02_createVertexNotPreCheckTest() {
+ Long vertexId = janusGraph.createVertexNotPreCheck("qualifiedName2", "type1", null);
+ Assert.assertNotNull(vertexId);
+ Assert.assertEquals(janusGraph.getVerticesByType("type1").size(), 2);
+ }
+
+ @Test
+ public void test_03_updateVertexTest() {
+ boolean flag1 = janusGraph.updateVertex("qualifiedName2", "type2", null);
+ Assert.assertEquals(flag1, true);
+ GraphVertex vertex = janusGraph.getVertex("qualifiedName2");
+ Assert.assertEquals(vertex.getType(), "type2");
+ Long vertexId = janusGraph.createVertex("qualifiedName3", "type1", null);
+ Assert.assertNotNull(vertexId);
+ boolean flag2 = janusGraph.updateVertex("qualifiedName2", "type1", null);
+ Assert.assertEquals(flag2, true);
+ }
+
+ @Test
+ public void test_04_softDeleteVerticesTest() {
+ GraphVertex vertex = janusGraph.getVertex("qualifiedName3");
+ Assert.assertEquals(vertex.getDeleted(), false);
+ boolean flag = janusGraph.softDeleteVertices("qualifiedName3", null);
+ Assert.assertEquals(flag, true);
+ vertex = janusGraph.getVertex("qualifiedName3");
+ Assert.assertEquals(vertex.getDeleted(), true);
+ }
+
+ @Test
+ public void test_05_recoverDeletedVerticesTest() {
+ boolean flag = janusGraph.recoverDeletedVertices("qualifiedName3", null);
+ Assert.assertEquals(flag, true);
+ GraphVertex vertex = janusGraph.getVertex("qualifiedName3");
+ Assert.assertEquals(vertex.getDeleted(), false);
+ }
+
+ @Test
+ public void test_06_hardDeleteVerticesTest() {
+ GraphVertex vertex = janusGraph.getVertex("qualifiedName3");
+ Assert.assertNotNull(vertex);
+ boolean flag = janusGraph.hardDeleteVertices("qualifiedName3", null);
+ Assert.assertEquals(flag, true);
+ vertex = janusGraph.getVertex("qualifiedName3");
+ Assert.assertNull(vertex);
+ }
+
+ @Test
+ public void test_07_getVertexTest() {
+ GraphVertex vertex = janusGraph.getVertex("qualifiedName2");
+ Assert.assertNotNull(vertex);
+ }
+
+ @Test
+ public void test_08_getVerticesByTypeTest() {
+ List vertices = janusGraph.getVerticesByType("type1");
+ Assert.assertNotNull(vertices);
+ Assert.assertEquals(vertices.size(), 2);
+ }
+
+ @Test
+ public void test_09_createEdgeTest() {
+ String edgeId =
+ janusGraph.createEdge(
+ "edgeQualifiedName1", "type1", "qualifiedName1", "qualifiedName2", null);
+ Assert.assertNotNull(edgeId);
+ }
+
+ @Test
+ public void test_10_createEdgeNotPreCheckTest() {
+ String edgeId =
+ janusGraph.createEdgeNotPreCheck(
+ "edgeQualifiedName2",
+ "type1",
+ janusGraph.getJanusGraphVertexId("qualifiedName1"),
+ janusGraph.getJanusGraphVertexId("qualifiedName2"),
+ null);
+ Assert.assertNotNull(edgeId);
+ }
+
+ @Test
+ public void test_11_graphLineageQueryTest() {
+ Map sourceVertexEdgeMap =
+ janusGraph.getSourceVertexEdgeMap("qualifiedName1");
+ Assert.assertEquals(0, sourceVertexEdgeMap.size());
+ sourceVertexEdgeMap = janusGraph.getSourceVertexEdgeMap("qualifiedName2");
+ Assert.assertEquals(2, sourceVertexEdgeMap.size());
+ Map targetVertexEdgeMap =
+ janusGraph.getTargetVertexEdgeMap("qualifiedName1");
+ Assert.assertEquals(2, targetVertexEdgeMap.size());
+ targetVertexEdgeMap = janusGraph.getTargetVertexEdgeMap("qualifiedName2");
+ Assert.assertEquals(0, targetVertexEdgeMap.size());
+ GraphLineage fullLineage = janusGraph.getFullLineage("qualifiedName1", -1, true);
+ Assert.assertEquals(2, fullLineage.getVertices().size());
+ Assert.assertEquals(2, fullLineage.getEdges().size());
+ fullLineage = janusGraph.getFullLineage("qualifiedName2", -1, true);
+ Assert.assertEquals(2, fullLineage.getVertices().size());
+ Assert.assertEquals(2, fullLineage.getEdges().size());
+ fullLineage = janusGraph.getFullLineage("qualifiedName1", 1, true);
+ Assert.assertEquals(2, fullLineage.getVertices().size());
+ Assert.assertEquals(2, fullLineage.getEdges().size());
+ fullLineage = janusGraph.getFullLineage("qualifiedName2", 1, true);
+ Assert.assertEquals(2, fullLineage.getVertices().size());
+ Assert.assertEquals(2, fullLineage.getEdges().size());
+ GraphLineage impactInfo = janusGraph.getImpact("qualifiedName1", 1, true);
+ Assert.assertEquals(2, impactInfo.getVertices().size());
+ Assert.assertEquals(2, impactInfo.getEdges().size());
+ GraphLineage lineageInfo = janusGraph.getLineage("qualifiedName2", 1, true);
+ Assert.assertEquals(2, lineageInfo.getVertices().size());
+ Assert.assertEquals(2, lineageInfo.getEdges().size());
+ }
+
+ @Test
+ public void test_12_getEdgeTest() {
+ GraphEdge graphEdge = janusGraph.getEdge("edgeQualifiedName2");
+ Assert.assertNotNull(graphEdge);
+ Assert.assertEquals(graphEdge.getType(), "type1");
+ }
+
+ @Test
+ public void test_13_getEdgesTest() {
+ List graphEdges = janusGraph.getEdges("type1", "qualifiedName1", "qualifiedName2");
+ Assert.assertNotNull(graphEdges);
+ Assert.assertEquals(graphEdges.size(), 2);
+ }
+
+ @Test
+ public void test_14_deleteSourceTargetVertexTest() {
+ boolean flag = janusGraph.hardDeleteVertices("qualifiedName2", null);
+ Assert.assertEquals(true, flag);
+ List graphEdges = janusGraph.getEdges("type1", null, null);
+ Assert.assertEquals(0, graphEdges.size());
+ String edgeId =
+ janusGraph.createEdge(
+ "edgeQualifiedName1", "type1", "qualifiedName1", "qualifiedName2", null);
+ Assert.assertNotNull(edgeId);
+ edgeId =
+ janusGraph.createEdgeNotPreCheck(
+ "edgeQualifiedName2",
+ "type1",
+ janusGraph.getJanusGraphVertexId("qualifiedName1"),
+ janusGraph.getJanusGraphVertexId("qualifiedName2"),
+ null);
+ Assert.assertNotNull(edgeId);
+ List vertices = janusGraph.getVerticesByType("type1");
+ Assert.assertNotNull(vertices);
+ Assert.assertEquals(vertices.size(), 2);
+ graphEdges = janusGraph.getEdges("type1", "qualifiedName1", "qualifiedName2");
+ Assert.assertNotNull(graphEdges);
+ Assert.assertEquals(graphEdges.size(), 2);
+ }
+
+ @Test
+ public void test_15_softDeleteEdgesTest() {
+ boolean flag = janusGraph.softDeleteEdges("edgeQualifiedName1", null, null, null);
+ Assert.assertEquals(flag, true);
+ GraphEdge graphEdge = janusGraph.getEdge("edgeQualifiedName1");
+ Assert.assertEquals(graphEdge.getDeleted(), true);
+ }
+
+ @Test
+ public void test_16_recoverDeletedEdgesTest() {
+ boolean flag = janusGraph.recoverDeletedEdges("edgeQualifiedName1", null, null, null);
+ Assert.assertEquals(flag, true);
+ GraphEdge graphEdge = janusGraph.getEdge("edgeQualifiedName1");
+ Assert.assertEquals(graphEdge.getDeleted(), false);
+ }
+
+ @Test
+ public void test_17_hardDeleteEdgesTest() {
+ boolean flag = janusGraph.hardDeleteEdges("edgeQualifiedName2", null, null, null);
+ Assert.assertEquals(flag, true);
+ GraphEdge edge = janusGraph.getEdge("edgeQualifiedName2");
+ Assert.assertNull(edge);
+ }
+
+ @Test
+ public void test_18_getSourceVertexEdgeMapTest() {
+ String edgeId =
+ janusGraph.createEdge(
+ "edgeQualifiedName2", "type1", "qualifiedName1", "qualifiedName2", null);
+ Assert.assertNotNull(edgeId);
+ Map graphEdgeVertexMap =
+ janusGraph.getSourceVertexEdgeMap("qualifiedName2");
+ Assert.assertNotNull(graphEdgeVertexMap);
+ Assert.assertEquals(graphEdgeVertexMap.size(), 2);
+ }
+
+ @Test
+ public void test_19_getTargetVertexEdgeMapTest() {
+ Map graphEdgeVertexMap =
+ janusGraph.getTargetVertexEdgeMap("qualifiedName1");
+ Assert.assertNotNull(graphEdgeVertexMap);
+ Assert.assertEquals(graphEdgeVertexMap.size(), 2);
+ }
+
+ @Test
+ public void test_20_updateVertexOldNewUniqTest() {
+ Long vertexId1 = janusGraph.createVertex("qualifiedName11", "type2", null);
+ Assert.assertNotNull(vertexId1);
+ Long vertexId2 = janusGraph.createVertex("qualifiedName22", "type2", null);
+ Assert.assertNotNull(vertexId2);
+ Long vertexId3 = janusGraph.createVertex("qualifiedName33", "type2", null);
+ Assert.assertNotNull(vertexId3);
+ String edgeId1 =
+ janusGraph.createEdge(
+ "edgeQualifiedName11", "type2", "qualifiedName11", "qualifiedName22", null);
+ Assert.assertNotNull(edgeId1);
+ String edgeId2 =
+ janusGraph.createEdge(
+ "edgeQualifiedName22", "type2", "qualifiedName22", "qualifiedName33", null);
+ Assert.assertNotNull(edgeId2);
+ janusGraph.updateVertex("qualifiedName22", "qualifiedName44", null, null);
+ GraphVertex graphVertex = janusGraph.getVertex("qualifiedName22");
+ Assert.assertNull(graphVertex);
+ graphVertex = janusGraph.getVertex("qualifiedName44");
+ Assert.assertNotNull(graphVertex);
+ GraphEdge graphEdge = janusGraph.getEdge("edgeQualifiedName11");
+ Assert.assertEquals("qualifiedName44", graphEdge.getTargetVertexUniq());
+ graphEdge = janusGraph.getEdge("edgeQualifiedName22");
+ Assert.assertEquals("qualifiedName44", graphEdge.getSourceVertexUniq());
+ janusGraph.hardDeleteVertices("qualifiedName11", null);
+ janusGraph.hardDeleteVertices("qualifiedName44", null);
+ janusGraph.hardDeleteVertices("qualifiedName33", null);
+ graphEdge = janusGraph.getEdge("edgeQualifiedName11");
+ Assert.assertNull(graphEdge);
+ graphEdge = janusGraph.getEdge("edgeQualifiedName22");
+ Assert.assertNull(graphEdge);
+ }
+
+ @Test
+ public void test_21_getImpact1Test() {
+ janusGraph.createVertex("qualifiedName3", "type1", null);
+ janusGraph.createVertex("qualifiedName4", "type1", null);
+ janusGraph.createVertex("qualifiedName5", "type1", null);
+ janusGraph.createEdge("edgeQualifiedName3", "type1", "qualifiedName2", "qualifiedName3", null);
+ janusGraph.createEdge("edgeQualifiedName4", "type1", "qualifiedName3", "qualifiedName4", null);
+ janusGraph.createEdge("edgeQualifiedName5", "type1", "qualifiedName4", "qualifiedName5", null);
+ janusGraph.createEdge("edgeQualifiedName6", "type1", "qualifiedName5", "qualifiedName1", null);
+ GraphLineage lineage = janusGraph.getImpact("qualifiedName2", -1, false);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 5);
+ Assert.assertEquals(lineage.getEdges().size(), 6);
+ }
+
+ @Test
+ public void test_22_getImpact2Test() {
+ janusGraph.softDeleteEdges("edgeQualifiedName4", null, null, null);
+ GraphLineage lineage = janusGraph.getImpact("qualifiedName2", -1, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 2);
+ Assert.assertEquals(lineage.getEdges().size(), 1);
+ janusGraph.recoverDeletedEdges("edgeQualifiedName4", null, null, null);
+ }
+
+ @Test
+ public void test_23_getImpact3Test() {
+ janusGraph.softDeleteVertices("qualifiedName4", null);
+ GraphLineage lineage = janusGraph.getImpact("qualifiedName2", -1, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 2);
+ Assert.assertEquals(lineage.getEdges().size(), 1);
+ janusGraph.recoverDeletedVertices("qualifiedName4", null);
+ }
+
+ @Test
+ public void test_24_getImpact4Test() {
+ GraphLineage lineage = janusGraph.getImpact("qualifiedName2", 3, false);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 4);
+ Assert.assertEquals(lineage.getEdges().size(), 3);
+ }
+
+ @Test
+ public void test_25_getImpact5Test() {
+ janusGraph.softDeleteEdges("edgeQualifiedName4", null, null, null);
+ GraphLineage lineage = janusGraph.getImpact("qualifiedName2", 3, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 2);
+ Assert.assertEquals(lineage.getEdges().size(), 1);
+ janusGraph.recoverDeletedEdges("edgeQualifiedName4", null, null, null);
+ }
+
+ @Test
+ public void test_26_getImpact6Test() {
+ janusGraph.softDeleteVertices("qualifiedName4", null);
+ GraphLineage lineage = janusGraph.getImpact("qualifiedName2", 3, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 2);
+ Assert.assertEquals(lineage.getEdges().size(), 1);
+ janusGraph.recoverDeletedVertices("qualifiedName4", null);
+ }
+
+ @Test
+ public void test_27_getImpact7Test() {
+ janusGraph.softDeleteVertices("qualifiedName2", null);
+ GraphLineage lineage = janusGraph.getImpact("qualifiedName2", -1, false);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 5);
+ Assert.assertEquals(lineage.getEdges().size(), 6);
+ }
+
+ @Test
+ public void test_28_getImpact8Test() {
+ GraphLineage lineage = janusGraph.getImpact("qualifiedName2", 3, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 0);
+ Assert.assertEquals(lineage.getEdges().size(), 0);
+ janusGraph.recoverDeletedVertices("qualifiedName2", null);
+ }
+
+ @Test
+ public void test_29_getLineage1Test() {
+ GraphLineage lineage = janusGraph.getLineage("qualifiedName2", -1, false);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 5);
+ Assert.assertEquals(lineage.getEdges().size(), 6);
+ }
+
+ @Test
+ public void test_30_getLineage2Test() {
+ janusGraph.softDeleteEdges("edgeQualifiedName5", null, null, null);
+ GraphLineage lineage = janusGraph.getLineage("qualifiedName2", -1, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 3);
+ Assert.assertEquals(lineage.getEdges().size(), 3);
+ janusGraph.recoverDeletedEdges("edgeQualifiedName5", null, null, null);
+ }
+
+ @Test
+ public void test_31_getLineage3Test() {
+ janusGraph.softDeleteVertices("qualifiedName5", null);
+ GraphLineage lineage = janusGraph.getLineage("qualifiedName2", -1, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 2);
+ Assert.assertEquals(lineage.getEdges().size(), 2);
+ janusGraph.recoverDeletedVertices("qualifiedName5", null);
+ }
+
+ @Test
+ public void test_32_getLineage4Test() {
+ GraphLineage lineage = janusGraph.getLineage("qualifiedName2", 3, false);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 4);
+ Assert.assertEquals(lineage.getEdges().size(), 4);
+ }
+
+ @Test
+ public void test_33_getLineage5Test() {
+ janusGraph.softDeleteEdges("edgeQualifiedName5", null, null, null);
+ GraphLineage lineage = janusGraph.getLineage("qualifiedName2", 3, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 3);
+ Assert.assertEquals(lineage.getEdges().size(), 3);
+ janusGraph.recoverDeletedEdges("edgeQualifiedName5", null, null, null);
+ }
+
+ @Test
+ public void test_34_getLineage6Test() {
+ janusGraph.softDeleteVertices("qualifiedName5", null);
+ GraphLineage lineage = janusGraph.getLineage("qualifiedName2", 3, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 2);
+ Assert.assertEquals(lineage.getEdges().size(), 2);
+ janusGraph.recoverDeletedVertices("qualifiedName5", null);
+ }
+
+ @Test
+ public void test_35_getLineage7Test() {
+ janusGraph.softDeleteVertices("qualifiedName2", null);
+ GraphLineage lineage = janusGraph.getLineage("qualifiedName2", -1, false);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 5);
+ Assert.assertEquals(lineage.getEdges().size(), 6);
+ }
+
+ @Test
+ public void test_36_getLineage8Test() {
+ GraphLineage lineage = janusGraph.getLineage("qualifiedName2", 3, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 0);
+ Assert.assertEquals(lineage.getEdges().size(), 0);
+ janusGraph.recoverDeletedVertices("qualifiedName2", null);
+ }
+
+ @Test
+ public void test_37_getFullLineage1Test() {
+ GraphLineage lineage = janusGraph.getFullLineage("qualifiedName2", -1, false);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 5);
+ Assert.assertEquals(lineage.getEdges().size(), 6);
+ }
+
+ @Test
+ public void test_38_getFullLineage2Test() {
+ janusGraph.softDeleteEdges("edgeQualifiedName5", null, null, null);
+ GraphLineage lineage = janusGraph.getFullLineage("qualifiedName2", -1, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 5);
+ Assert.assertEquals(lineage.getEdges().size(), 5);
+ janusGraph.recoverDeletedEdges("edgeQualifiedName5", null, null, null);
+ }
+
+ @Test
+ public void test_39_getFullLineage3Test() {
+ janusGraph.softDeleteVertices("qualifiedName5", null);
+ GraphLineage lineage = janusGraph.getFullLineage("qualifiedName2", -1, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 4);
+ Assert.assertEquals(lineage.getEdges().size(), 4);
+ janusGraph.recoverDeletedVertices("qualifiedName5", null);
+ }
+
+ @Test
+ public void test_40_getFullLineage4Test() {
+ GraphLineage lineage = janusGraph.getFullLineage("qualifiedName2", 2, false);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 5);
+ Assert.assertEquals(lineage.getEdges().size(), 5);
+ }
+
+ @Test
+ public void test_41_getFullLineage5Test() {
+ janusGraph.softDeleteEdges("edgeQualifiedName4", null, null, null);
+ GraphLineage lineage = janusGraph.getFullLineage("qualifiedName2", 2, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 4);
+ Assert.assertEquals(lineage.getEdges().size(), 4);
+ janusGraph.recoverDeletedEdges("edgeQualifiedName4", null, null, null);
+ }
+
+ @Test
+ public void test_42_getFullLineage6Test() {
+ janusGraph.softDeleteVertices("qualifiedName3", null);
+ GraphLineage lineage = janusGraph.getFullLineage("qualifiedName2", 2, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 3);
+ Assert.assertEquals(lineage.getEdges().size(), 3);
+ janusGraph.recoverDeletedVertices("qualifiedName3", null);
+ }
+
+ @Test
+ public void test_43_getFullLineage7Test() {
+ janusGraph.softDeleteVertices("qualifiedName2", null);
+ GraphLineage lineage = janusGraph.getFullLineage("qualifiedName2", -1, false);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 5);
+ Assert.assertEquals(lineage.getEdges().size(), 6);
+ }
+
+ @Test
+ public void test_44_getFullLineage8Test() {
+ GraphLineage lineage = janusGraph.getFullLineage("qualifiedName2", 3, true);
+ Assert.assertNotNull(lineage);
+ Assert.assertEquals(lineage.getVertices().size(), 0);
+ Assert.assertEquals(lineage.getEdges().size(), 0);
+ janusGraph.recoverDeletedVertices("qualifiedName2", null);
+ }
+
+ @Test
+ public void test_45_createVertexNotPreCheck2Test() {
+ Long vertexId = janusGraph.createVertexNotPreCheck("qualifiedName1", "type1", null);
+ Assert.assertNotNull(vertexId);
+ Assert.assertEquals(janusGraph.getVerticesByType("type1").size(), 6);
+ }
+
+ @Test
+ public void test_46_createEdge2Test() {
+ String edgeId =
+ janusGraph.createEdgeNotPreCheck(
+ "edgeQualifiedName1",
+ "type1",
+ janusGraph.getJanusGraphVertexId("qualifiedName1"),
+ janusGraph.getJanusGraphVertexId("qualifiedName2"),
+ null);
+ Assert.assertNotNull(edgeId);
+ List graphEdges = janusGraph.getEdges("type1", "qualifiedName1", "qualifiedName2");
+ Assert.assertNotNull(graphEdges);
+ Assert.assertEquals(graphEdges.size(), 3);
+ }
+
+ @Test
+ public void test_47_performance1Test() {
+ int startNum = 1;
+ int endNum = 50;
+ for (int i = startNum; i <= endNum; i++) {
+ String uniq = "performance_1_" + String.valueOf(i);
+ janusGraph.createVertex(uniq, "type1", null);
+ }
+ }
+
+ @Test
+ public void test_48_performance2Test() {
+ int startNum = 1;
+ int endNum = 50;
+ for (int i = startNum; i <= endNum; i++) {
+ String uniq = "performance_2_" + String.valueOf(i);
+ janusGraph.createVertexNotPreCheck(uniq, "type1", null);
+ }
+ }
+}
diff --git a/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/util/DateUtil.java b/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/util/DateUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..05c55d6bbea5ce6c694dfe26fab241cb9b26467b
--- /dev/null
+++ b/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/util/DateUtil.java
@@ -0,0 +1,56 @@
+package org.studiox.graph.janusgraph.common.util;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class DateUtil {
+
+ public static Long getCurrentTimestamp() {
+ return System.currentTimeMillis();
+ }
+
+ public static Date getCurrentDate() {
+ return new Date();
+ }
+
+ public static Date getDate(long timestamp) {
+ return new Date(timestamp);
+ }
+
+ public static long getTimestamp(Date date) {
+ return date.getTime();
+ }
+
+ public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
+
+ public static final String DEFAULT_DAY_FORMAT = "yyyy-MM-dd";
+
+ public static String formatDate(String format, Date date) {
+ if (StringUtils.isBlank(format) || null == date) {
+ return null;
+ }
+ SimpleDateFormat sdf = new SimpleDateFormat(format);
+ return sdf.format(date);
+ }
+
+ public static Date parseDate(String format, String dateStr) throws Exception {
+ if (StringUtils.isBlank(format) || StringUtils.isBlank(dateStr)) {
+ return null;
+ }
+ SimpleDateFormat sdf = new SimpleDateFormat(format);
+ try {
+ return sdf.parse(dateStr);
+ } catch (Throwable e) {
+ throw new Exception(
+ "parse date string='"
+ + dateStr
+ + "' by format='"
+ + format
+ + "' failed, caused by "
+ + e.getMessage(),
+ e);
+ }
+ }
+}
diff --git a/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/util/StringUtil.java b/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/util/StringUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..46e3646a1920bb562d7851e9476d0e68f6dc5d27
--- /dev/null
+++ b/graph-janusgraph/janusgraph-common/src/main/java/org/studiox/graph/janusgraph/common/util/StringUtil.java
@@ -0,0 +1,18 @@
+package org.studiox.graph.janusgraph.common.util;
+
+import org.apache.commons.lang.StringUtils;
+
+public class StringUtil {
+
+ public static boolean checkStringParamsBlank(String... params) {
+ if (null == params || params.length == 0) {
+ return true;
+ }
+ for (String param : params) {
+ if (StringUtils.isBlank(param)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/graph-janusgraph/janusgraph-latest/pom.xml b/graph-janusgraph/janusgraph-latest/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..54683913a59d833daab81023fce73fc309c2c06a
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/pom.xml
@@ -0,0 +1,224 @@
+
+
+ 4.0.0
+
+ org.studiox.graph
+ graph-janusgraph
+ 1.0.5-SNAPSHOT
+
+ org.studiox.graph.janusgraph
+ janusgraph-latest
+ 1.0.5-SNAPSHOT
+ jar
+
+
+
+ 1.0.0-SNAPSHOT
+ 1.3.1
+ 3.5.1
+
+
+
+ 2.5.14
+
+
+
+ junit
+ junit
+ test
+
+
+ org.studiox.graph.janusgraph
+ janusgraph-v0.2.0
+
+
+ org.janusgraph
+ *
+
+
+ org.apache.hbase
+ *
+
+
+
+
+ org.janusgraph
+ janusgraph-core
+ ${janusgraph.version}
+
+
+ org.janusgraph
+ janusgraph-inmemory
+ ${janusgraph.version}
+
+
+ org.janusgraph
+ janusgraph-hbase
+ ${janusgraph.version}
+
+
+ org.apache.hbase
+ hbase-client
+ ${hbase.version}
+
+
+ org.apache.hadoop
+ hadoop-mapreduce-client-core
+
+
+
+
+ org.janusgraph
+ janusgraph-server
+ ${janusgraph.version}
+
+
+ org.codehaus.groovy
+ groovy-cli-picocli
+ ${groovy.version}
+
+
+ org.codehaus.groovy
+ groovy
+
+
+
+
+ org.codehaus.groovy
+ groovy-console
+ ${groovy.version}
+
+
+ org.codehaus.groovy
+ groovy-templates
+ ${groovy.version}
+
+
+ org.codehaus.groovy
+ groovy-xml
+ ${groovy.version}
+
+
+ org.codehaus.groovy
+ groovy-swing
+ ${groovy.version}
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+ false
+
+
+
+ package
+
+ shade
+
+
+
+
+ *:*
+
+ properties.dtd
+ log4j.properties
+ digesterRules.xml
+ PropertyList-1.0.dtd
+ yarn-default.xml
+ core-default.xml
+ hbase-default.xml
+ mapred-default.xml
+ tp2-to-tp3-graphml.xslt
+
+
+
+
+
+ io.netty
+ graph.io.netty
+
+
+ org.jboss.netty
+ graph.org.jboss.netty
+
+
+ org.codehaus.groovy
+ graph.org.codehaus.groovy
+
+
+
+
+
+
+
+
+
+
+ pl.project13.maven
+ git-commit-id-plugin
+
+
+
+
diff --git a/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractGraphChannelizer.java b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractGraphChannelizer.java
new file mode 100644
index 0000000000000000000000000000000000000000..580dae81e4340d369fcc40bccf7a8b927ab3fdf9
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractGraphChannelizer.java
@@ -0,0 +1,408 @@
+package org.apache.tinkerpop.gremlin.server;
+
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.ssl.ClientAuth;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.ssl.SslProvider;
+import io.netty.handler.timeout.IdleStateHandler;
+import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
+import org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1;
+import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV2d0;
+import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor;
+import org.apache.tinkerpop.gremlin.server.auth.Authenticator;
+import org.apache.tinkerpop.gremlin.server.authz.Authorizer;
+import org.apache.tinkerpop.gremlin.server.handler.AbstractAuthenticationHandler;
+import org.apache.tinkerpop.gremlin.server.handler.GraphOpSelectorHandler;
+import org.apache.tinkerpop.gremlin.server.handler.OpExecutorHandler;
+import org.apache.tinkerpop.gremlin.server.util.GraphServerGremlinExecutor;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.javatuples.Pair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.stream.Stream;
+
+public abstract class AbstractGraphChannelizer extends ChannelInitializer
+ implements GraphChannelizer {
+ private static final Logger logger = LoggerFactory.getLogger(AbstractGraphChannelizer.class);
+
+ protected Settings settings;
+ protected GremlinExecutor gremlinExecutor;
+ protected Optional sslContext;
+ protected GraphManager graphManager;
+ protected ExecutorService gremlinExecutorService;
+ protected ScheduledExecutorService scheduledExecutorService;
+
+ public static final String PIPELINE_AUTHENTICATOR = "authenticator";
+ public static final String PIPELINE_AUTHORIZER = "authorizer";
+ public static final String PIPELINE_REQUEST_HANDLER = "request-handler";
+ public static final String PIPELINE_HTTP_RESPONSE_ENCODER = "http-response-encoder";
+ public static final String PIPELINE_HTTP_AGGREGATOR = "http-aggregator";
+ public static final String PIPELINE_WEBSOCKET_SERVER_COMPRESSION =
+ "web-socket-server-compression-handler";
+
+ protected static final String PIPELINE_SSL = "ssl";
+ protected static final String PIPELINE_OP_SELECTOR = "op-selector";
+ protected static final String PIPELINE_OP_EXECUTOR = "op-executor";
+ protected static final String PIPELINE_HTTP_REQUEST_DECODER = "http-request-decoder";
+
+ protected static final String GREMLIN_ENDPOINT = "/gremlin";
+
+ protected final Map> serializers = new HashMap<>();
+
+ private GraphOpSelectorHandler opSelectorHandler;
+ private OpExecutorHandler opExecutorHandler;
+
+ protected Authenticator authenticator;
+ protected Authorizer authorizer;
+
+ /**
+ * This method is called from within {@link #initChannel(SocketChannel)} just after the SSL
+ * handler is put in the pipeline. Modify the pipeline as needed here.
+ */
+ public abstract void configure(final ChannelPipeline pipeline);
+
+ /**
+ * This method is called after the pipeline is completely configured. It can be overridden to make
+ * any final changes to the pipeline before it goes into use.
+ */
+ public void finalize(final ChannelPipeline pipeline) {
+ // do nothing
+ }
+
+ public static final List getDefaultSerializers() {
+ return Arrays.asList(
+ new Settings.SerializerSettings(
+ GraphSONMessageSerializerV2d0.class.getName(), Collections.emptyMap()),
+ new Settings.SerializerSettings(
+ GraphBinaryMessageSerializerV1.class.getName(), Collections.emptyMap()),
+ new Settings.SerializerSettings(
+ GraphBinaryMessageSerializerV1.class.getName(),
+ new HashMap() {
+ {
+ put(GraphBinaryMessageSerializerV1.TOKEN_SERIALIZE_RESULT_TO_STRING, true);
+ }
+ }));
+ }
+
+ @Override
+ public void init(final GraphServerGremlinExecutor graphServerGremlinExecutor) {
+ settings = graphServerGremlinExecutor.getSettings();
+ gremlinExecutor = graphServerGremlinExecutor.getGremlinExecutor();
+ graphManager = graphServerGremlinExecutor.getGraphManager();
+ gremlinExecutorService = graphServerGremlinExecutor.getGremlinExecutorService();
+ scheduledExecutorService = graphServerGremlinExecutor.getScheduledExecutorService();
+
+ // instantiate and configure the serializers that gremlin server will use - could error out here
+ // and fail the server startup
+ configureSerializers();
+
+ // configure ssl if present
+ sslContext =
+ settings.optionalSsl().isPresent() && settings.ssl.enabled
+ ? Optional.ofNullable(createSSLContext(settings))
+ : Optional.empty();
+ if (sslContext.isPresent()) {
+ logger.info("SSL enabled");
+ }
+
+ authenticator = createAuthenticator(settings.authentication);
+ authorizer = createAuthorizer(settings.authorization);
+
+ // these handlers don't share any state and can thus be initialized once per pipeline
+ opSelectorHandler =
+ new GraphOpSelectorHandler(
+ settings, graphManager, gremlinExecutor, scheduledExecutorService, this);
+ opExecutorHandler =
+ new OpExecutorHandler(settings, graphManager, gremlinExecutor, scheduledExecutorService);
+ }
+
+ @Override
+ public void initChannel(final SocketChannel ch) throws Exception {
+ final ChannelPipeline pipeline = ch.pipeline();
+
+ sslContext.ifPresent(
+ sslContext -> pipeline.addLast(PIPELINE_SSL, sslContext.newHandler(ch.alloc())));
+
+ // checks for no activity on a channel and triggers an event that is consumed by the
+ // OpSelectorHandler
+ // and either closes the connection or sends a ping to see if the client is still alive
+ if (supportsIdleMonitor()) {
+ final int idleConnectionTimeout = (int) (settings.idleConnectionTimeout / 1000);
+ final int keepAliveInterval = (int) (settings.keepAliveInterval / 1000);
+ pipeline.addLast(new IdleStateHandler(idleConnectionTimeout, keepAliveInterval, 0));
+ }
+
+ // the implementation provides the method by which Gremlin Server will process requests. the
+ // end of the
+ // pipeline must decode to an incoming RequestMessage instances and encode to a outgoing
+ // ResponseMessage
+ // instance
+ configure(pipeline);
+
+ pipeline.addLast(PIPELINE_OP_SELECTOR, opSelectorHandler);
+ pipeline.addLast(PIPELINE_OP_EXECUTOR, opExecutorHandler);
+
+ finalize(pipeline);
+ }
+
+ protected AbstractAuthenticationHandler createAuthenticationHandler(final Settings settings) {
+ try {
+ final Class> clazz = Class.forName(settings.authentication.authenticationHandler);
+ AbstractAuthenticationHandler aah;
+ try {
+ // the three arg constructor is the new form as a handler may need the authorizer in some
+ // cases
+ final Class>[] threeArgForm =
+ new Class[] {Authenticator.class, Authorizer.class, Settings.class};
+ final Constructor> twoArgConstructor = clazz.getDeclaredConstructor(threeArgForm);
+ return (AbstractAuthenticationHandler)
+ twoArgConstructor.newInstance(authenticator, authorizer, settings);
+ } catch (Exception threeArgEx) {
+ try {
+ // the two arg constructor is the "old form" that existed prior to Authorizers. should
+ // probably
+ // deprecate this form
+ final Class>[] twoArgForm = new Class[] {Authenticator.class, Settings.class};
+ final Constructor> twoArgConstructor = clazz.getDeclaredConstructor(twoArgForm);
+
+ if (authorizer != null) {
+ logger.warn(
+ "There is an authorizer configured but the {} does not have a constructor of ({}, {}, {}) so it cannot be added",
+ clazz.getName(),
+ Authenticator.class.getSimpleName(),
+ Authorizer.class.getSimpleName(),
+ Settings.class.getSimpleName());
+ }
+
+ return (AbstractAuthenticationHandler)
+ twoArgConstructor.newInstance(authenticator, settings);
+ } catch (Exception twoArgEx) {
+ throw twoArgEx;
+ }
+ }
+ } catch (Exception ex) {
+ logger.warn(ex.getMessage());
+ throw new IllegalStateException(
+ String.format(
+ "Could not create/configure AuthenticationHandler %s",
+ settings.authentication.authenticationHandler),
+ ex);
+ }
+ }
+
+ private Authenticator createAuthenticator(final Settings.AuthenticationSettings config) {
+ final String authenticatorClass = config.authenticator;
+ try {
+ final Class> clazz = Class.forName(authenticatorClass);
+ final Authenticator authenticator = (Authenticator) clazz.newInstance();
+ authenticator.setup(config.config);
+ return authenticator;
+ } catch (Exception ex) {
+ logger.warn(ex.getMessage());
+ throw new IllegalStateException(
+ String.format("Could not create/configure Authenticator %s", authenticator), ex);
+ }
+ }
+
+ private Authorizer createAuthorizer(final Settings.AuthorizationSettings config) {
+ final String authorizerClass = config.authorizer;
+ if (null == authorizerClass) {
+ return null;
+ }
+ try {
+ final Class> clazz = Class.forName(authorizerClass);
+ final Authorizer authorizer = (Authorizer) clazz.newInstance();
+ authorizer.setup(config.config);
+ return authorizer;
+ } catch (Exception ex) {
+ logger.warn(ex.getMessage());
+ throw new IllegalStateException(
+ String.format("Could not create/configure Authorizer %s", authorizer), ex);
+ }
+ }
+
+ private void configureSerializers() {
+ // grab some sensible defaults if no serializers are present in the config
+ final List serializerSettings =
+ (null == this.settings.serializers || this.settings.serializers.isEmpty())
+ ? getDefaultSerializers()
+ : settings.serializers;
+
+ serializerSettings.stream()
+ .map(
+ config -> {
+ try {
+ final Class clazz = Class.forName(config.className);
+ if (!MessageSerializer.class.isAssignableFrom(clazz)) {
+ logger.warn(
+ "The {} serialization class does not implement {} - it will not be available.",
+ config.className,
+ MessageSerializer.class.getCanonicalName());
+ return Optional.empty();
+ }
+
+ if (clazz.getAnnotation(Deprecated.class) != null)
+ logger.warn("The {} serialization class is deprecated.", config.className);
+
+ final MessageSerializer> serializer = (MessageSerializer) clazz.newInstance();
+ final Map graphsDefinedAtStartup = new HashMap<>();
+ for (String graphName : settings.graphs.keySet()) {
+ graphsDefinedAtStartup.put(graphName, graphManager.getGraph(graphName));
+ }
+
+ if (config.config != null)
+ serializer.configure(config.config, graphsDefinedAtStartup);
+
+ return Optional.ofNullable(serializer);
+ } catch (ClassNotFoundException cnfe) {
+ logger.warn(
+ "Could not find configured serializer class - {} - it will not be available",
+ config.className);
+ return Optional.empty();
+ } catch (Exception ex) {
+ logger.warn(
+ "Could not instantiate configured serializer class - {} - it will not be available. {}",
+ config.className,
+ ex.getMessage());
+ return Optional.empty();
+ }
+ })
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .flatMap(
+ serializer ->
+ Stream.of(serializer.mimeTypesSupported())
+ .map(mimeType -> Pair.with(mimeType, serializer)))
+ .forEach(
+ pair -> {
+ final String mimeType = pair.getValue0();
+ final MessageSerializer> serializer = pair.getValue1();
+ if (serializers.containsKey(mimeType))
+ logger.info(
+ "{} already has {} configured - it will not be replaced by {}, change order of serialization configuration if this is not desired.",
+ mimeType,
+ serializers.get(mimeType).getClass().getName(),
+ serializer.getClass().getName());
+ else {
+ logger.info(
+ "Configured {} with {}", mimeType, pair.getValue1().getClass().getName());
+ serializers.put(mimeType, serializer);
+ }
+ });
+
+ if (serializers.size() == 0) {
+ logger.error("No serializers were successfully configured - server will not start.");
+ throw new RuntimeException("Serialization configuration error.");
+ }
+ }
+
+ private SslContext createSSLContext(final Settings settings) {
+ final Settings.SslSettings sslSettings = settings.ssl;
+
+ if (sslSettings.getSslContext().isPresent()) {
+ logger.info("Using the SslContext override");
+ return sslSettings.getSslContext().get();
+ }
+
+ final SslProvider provider = SslProvider.JDK;
+
+ final SslContextBuilder builder;
+
+ // Build JSSE SSLContext
+ try {
+ final KeyManagerFactory kmf =
+ KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+
+ // Load private key and signed cert
+ if (null != sslSettings.keyStore) {
+ final String keyStoreType =
+ null == sslSettings.keyStoreType ? KeyStore.getDefaultType() : sslSettings.keyStoreType;
+ final KeyStore keystore = KeyStore.getInstance(keyStoreType);
+ final char[] password =
+ null == sslSettings.keyStorePassword
+ ? null
+ : sslSettings.keyStorePassword.toCharArray();
+ try (final InputStream in = new FileInputStream(sslSettings.keyStore)) {
+ keystore.load(in, password);
+ }
+ kmf.init(keystore, password);
+ } else {
+ throw new IllegalStateException("keyStore must be configured when SSL is enabled.");
+ }
+
+ builder = SslContextBuilder.forServer(kmf);
+
+ // Load custom truststore for client auth certs
+ if (null != sslSettings.trustStore) {
+ final String trustStoreType =
+ null != sslSettings.trustStoreType
+ ? sslSettings.trustStoreType
+ : sslSettings.keyStoreType != null
+ ? sslSettings.keyStoreType
+ : KeyStore.getDefaultType();
+
+ final KeyStore truststore = KeyStore.getInstance(trustStoreType);
+ final char[] password =
+ null == sslSettings.trustStorePassword
+ ? null
+ : sslSettings.trustStorePassword.toCharArray();
+ try (final InputStream in = new FileInputStream(sslSettings.trustStore)) {
+ truststore.load(in, password);
+ }
+ final TrustManagerFactory tmf =
+ TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(truststore);
+ builder.trustManager(tmf);
+ }
+
+ } catch (UnrecoverableKeyException
+ | NoSuchAlgorithmException
+ | KeyStoreException
+ | CertificateException
+ | IOException e) {
+ logger.error(e.getMessage());
+ throw new RuntimeException("There was an error enabling SSL.", e);
+ }
+
+ if (null != sslSettings.sslCipherSuites && !sslSettings.sslCipherSuites.isEmpty()) {
+ builder.ciphers(sslSettings.sslCipherSuites);
+ }
+
+ if (null != sslSettings.sslEnabledProtocols && !sslSettings.sslEnabledProtocols.isEmpty()) {
+ builder.protocols(sslSettings.sslEnabledProtocols.toArray(new String[] {}));
+ }
+
+ if (null != sslSettings.needClientAuth && ClientAuth.OPTIONAL == sslSettings.needClientAuth) {
+ logger.warn("needClientAuth = OPTIONAL is not a secure configuration. Setting to REQUIRE.");
+ sslSettings.needClientAuth = ClientAuth.REQUIRE;
+ }
+
+ builder.clientAuth(sslSettings.needClientAuth).sslProvider(provider);
+
+ try {
+ return builder.build();
+ } catch (SSLException ssle) {
+ logger.error(ssle.getMessage());
+ throw new RuntimeException("There was an error enabling SSL.", ssle);
+ }
+ }
+}
diff --git a/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/GraphChannelizer.java b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/GraphChannelizer.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec8174de20ff9fe2531e64cfde2878c7ed94bbdd
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/GraphChannelizer.java
@@ -0,0 +1,17 @@
+package org.apache.tinkerpop.gremlin.server;
+
+import io.netty.channel.ChannelHandler;
+import org.apache.tinkerpop.gremlin.server.util.GraphServerGremlinExecutor;
+
+public interface GraphChannelizer extends ChannelHandler {
+
+ public void init(final GraphServerGremlinExecutor graphServerGremlinExecutor);
+
+ public default Object createIdleDetectionMessage() {
+ return null;
+ }
+
+ public default boolean supportsIdleMonitor() {
+ return false;
+ }
+}
diff --git a/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/GraphGremlinServer.java b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/GraphGremlinServer.java
new file mode 100644
index 0000000000000000000000000000000000000000..bea2dad7e9e84a36b894bf26c6c3f29055ad51cb
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/GraphGremlinServer.java
@@ -0,0 +1,459 @@
+package org.apache.tinkerpop.gremlin.server;
+
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.buffer.PooledByteBufAllocator;
+import io.netty.channel.*;
+import io.netty.channel.epoll.EpollEventLoopGroup;
+import io.netty.channel.epoll.EpollServerSocketChannel;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.util.concurrent.GenericFutureListener;
+import io.netty.util.internal.logging.InternalLoggerFactory;
+import io.netty.util.internal.logging.Slf4JLoggerFactory;
+import org.apache.commons.lang3.SystemUtils;
+import org.apache.tinkerpop.gremlin.server.op.OpLoader;
+import org.apache.tinkerpop.gremlin.server.util.GraphServerGremlinExecutor;
+import org.apache.tinkerpop.gremlin.server.util.LifeCycleHook;
+import org.apache.tinkerpop.gremlin.server.util.MetricManager;
+import org.apache.tinkerpop.gremlin.server.util.ThreadFactoryUtil;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.janusgraph.core.JanusGraph;
+import org.janusgraph.graphdb.grpc.JanusGraphContextHandler;
+import org.janusgraph.graphdb.grpc.JanusGraphManagerServiceImpl;
+import org.janusgraph.graphdb.grpc.schema.SchemaManagerImpl;
+import org.janusgraph.graphdb.management.JanusGraphManager;
+import org.janusgraph.graphdb.server.JanusGraphSettings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.studiox.graph.common.exception.GraphException;
+import org.studiox.graph.janusgraph.latest.JanusGraphLatest;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.UndeclaredThrowableException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.concurrent.*;
+
+public class GraphGremlinServer {
+
+ static {
+ // hook slf4j up to netty internal logging
+ InternalLoggerFactory.setDefaultFactory(Slf4JLoggerFactory.INSTANCE);
+ }
+
+ private static final String SERVER_THREAD_PREFIX = "gremlin-server-";
+
+ private static final Logger logger = LoggerFactory.getLogger(GraphGremlinServer.class);
+
+ private final Settings settings;
+
+ private Channel ch;
+
+ private CompletableFuture serverStopped = null;
+ private CompletableFuture serverStarted = null;
+
+ private final EventLoopGroup bossGroup;
+ private final EventLoopGroup workerGroup;
+ private final ExecutorService gremlinExecutorService;
+
+ private final GraphServerGremlinExecutor graphServerGremlinExecutor;
+
+ private final boolean isEpollEnabled;
+
+ private GraphChannelizer graphChannelizer;
+
+ public GraphGremlinServer(final Settings settings) {
+ this(settings, null, null);
+ }
+
+ public GraphGremlinServer(final Settings settings, Graph graph) {
+ this(settings, null, graph);
+ }
+
+ public GraphGremlinServer(
+ final Settings settings, final ExecutorService gremlinExecutorService, Graph graph) {
+ this.settings = settings;
+
+ provideDefaultForGremlinPoolSize(settings);
+ this.isEpollEnabled = settings.useEpollEventLoop && SystemUtils.IS_OS_LINUX;
+ if (settings.useEpollEventLoop && !SystemUtils.IS_OS_LINUX) {
+ logger.warn("cannot use epoll in non-linux env, falling back to NIO");
+ }
+
+ Runtime.getRuntime()
+ .addShutdownHook(new Thread(() -> this.stop().join(), SERVER_THREAD_PREFIX + "shutdown"));
+
+ final ThreadFactory threadFactoryBoss = ThreadFactoryUtil.create("boss-%d");
+
+ // if linux os use epoll else fallback to nio based eventloop
+ // epoll helps in reducing GC and has better performance
+ // http://netty.io/wiki/native-transports.html
+ if (isEpollEnabled) {
+ bossGroup = new EpollEventLoopGroup(settings.threadPoolBoss, threadFactoryBoss);
+ } else {
+ bossGroup = new NioEventLoopGroup(settings.threadPoolBoss, threadFactoryBoss);
+ }
+
+ final ThreadFactory threadFactoryWorker = ThreadFactoryUtil.create("worker-%d");
+ if (isEpollEnabled) {
+ workerGroup = new EpollEventLoopGroup(settings.threadPoolWorker, threadFactoryWorker);
+ } else {
+ workerGroup = new NioEventLoopGroup(settings.threadPoolWorker, threadFactoryWorker);
+ }
+
+ // use the ExecutorService returned from ServerGremlinExecutor as it might be initialized there
+ graphServerGremlinExecutor =
+ new GraphServerGremlinExecutor(settings, gremlinExecutorService, workerGroup, graph);
+ this.gremlinExecutorService = graphServerGremlinExecutor.getGremlinExecutorService();
+
+ // initialize the OpLoader with configurations being passed to each OpProcessor implementation
+ // loaded
+ OpLoader.init(settings);
+ }
+
+ public void start() {
+ Server grpcServer = createGrpcServer();
+
+ CompletableFuture grpcServerFuture =
+ CompletableFuture.runAsync(
+ () -> {
+ try {
+ grpcServer.start();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ });
+
+ CompletableFuture gremlinServerFuture =
+ startGremlinServer().thenAcceptAsync(GraphGremlinServer::configure);
+
+ CompletableFuture serverStarted =
+ CompletableFuture.allOf(gremlinServerFuture, grpcServerFuture);
+ }
+
+ public synchronized CompletableFuture startGremlinServer() {
+ if (serverStarted != null) {
+ // server already started - don't get it rolling again
+ return serverStarted;
+ }
+
+ serverStarted = new CompletableFuture<>();
+ final CompletableFuture serverReadyFuture = serverStarted;
+ try {
+ final ServerBootstrap b = new ServerBootstrap();
+
+ // when high value is reached then the channel becomes non-writable and stays like that until
+ // the
+ // low value is so that there is time to recover
+ b.childOption(
+ ChannelOption.WRITE_BUFFER_WATER_MARK,
+ new WriteBufferWaterMark(
+ settings.writeBufferLowWaterMark, settings.writeBufferHighWaterMark));
+ b.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
+
+ // fire off any lifecycle scripts that were provided by the user. hooks get initialized during
+ // ServerGremlinExecutor initialization
+ graphServerGremlinExecutor
+ .getHooks()
+ .forEach(
+ hook -> {
+ logger.info("Executing start up {}", LifeCycleHook.class.getSimpleName());
+ try {
+ hook.onStartUp(new LifeCycleHook.Context(logger));
+ } catch (UnsupportedOperationException uoe) {
+ // if the user doesn't implement onStartUp the scriptengine will throw
+ // this exception. it can safely be ignored.
+ }
+ });
+
+ graphChannelizer = createGraphChannelizer(settings);
+ graphChannelizer.init(graphServerGremlinExecutor);
+ b.group(bossGroup, workerGroup).childHandler(graphChannelizer);
+ if (isEpollEnabled) {
+ b.channel(EpollServerSocketChannel.class);
+ } else {
+ b.channel(NioServerSocketChannel.class);
+ }
+
+ // bind to host/port and wait for channel to be ready
+ b.bind(settings.host, settings.port)
+ .addListener(
+ (ChannelFutureListener)
+ channelFuture -> {
+ if (channelFuture.isSuccess()) {
+ ch = channelFuture.channel();
+ logger.info(
+ "Gremlin Server configured with worker thread pool of {}, gremlin pool of {} and boss thread pool of {}.",
+ settings.threadPoolWorker,
+ settings.gremlinPool,
+ settings.threadPoolBoss);
+ logger.info("Channel started at port {}.", settings.port);
+ serverReadyFuture.complete(graphServerGremlinExecutor);
+ } else {
+ serverReadyFuture.completeExceptionally(
+ new IOException(
+ String.format(
+ "Could not bind to %s and %s - perhaps something else is bound to that address.",
+ settings.host, settings.port)));
+ }
+ });
+ } catch (Exception ex) {
+ logger.error("Gremlin Server Error", ex);
+ serverReadyFuture.completeExceptionally(ex);
+ }
+
+ return serverStarted;
+ }
+
+ private static GraphChannelizer createGraphChannelizer(final Settings settings) {
+ try {
+ final Class clazz = Class.forName(settings.channelizer);
+ final Object o = clazz.newInstance();
+
+ final GraphChannelizer c = (GraphChannelizer) o;
+ if (c.supportsIdleMonitor()) {
+ logger.info(
+ "idleConnectionTimeout was set to {} which resolves to {} seconds when configuring this value - this feature will be {}",
+ settings.idleConnectionTimeout,
+ settings.idleConnectionTimeout / 1000,
+ settings.idleConnectionTimeout < 1000 ? "disabled" : "enabled");
+ logger.info(
+ "keepAliveInterval was set to {} which resolves to {} seconds when configuring this value - this feature will be {}",
+ settings.keepAliveInterval,
+ settings.keepAliveInterval / 1000,
+ settings.keepAliveInterval < 1000 ? "disabled" : "enabled");
+ }
+
+ return c;
+ } catch (ClassNotFoundException cnfe) {
+ logger.error(
+ "Could not find {} implementation defined by the 'graphChannelizer' setting as: {}",
+ GraphChannelizer.class.getName(),
+ settings.channelizer);
+ throw new RuntimeException(cnfe);
+ } catch (Exception ex) {
+ logger.error(
+ "Class defined by the 'graphChannelizer' setting as: {} could not be properly instantiated as a {}",
+ settings.channelizer,
+ GraphChannelizer.class.getName());
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public synchronized CompletableFuture stop() {
+ if (serverStopped != null) {
+ // shutdown has started so don't fire it off again
+ return serverStopped;
+ }
+
+ serverStopped = new CompletableFuture<>();
+ final CountDownLatch servicesLeftToShutdown = new CountDownLatch(3);
+
+ // release resources in the OpProcessors (e.g. kill sessions)
+ OpLoader.getProcessors()
+ .forEach(
+ (key, value) -> {
+ logger.info("Shutting down OpProcessor[{}]", key);
+ try {
+ value.close();
+ } catch (Exception ex) {
+ logger.warn(
+ "Shutdown will continue but, there was an error encountered while closing "
+ + key,
+ ex);
+ }
+ });
+
+ // it's possible that a channel might not be initialized in the first place if bind() fails
+ // because
+ // of port conflict. in that case, there's no need to wait for the channel to close.
+ if (null == ch) {
+ servicesLeftToShutdown.countDown();
+ } else {
+ ch.close().addListener(f -> servicesLeftToShutdown.countDown());
+ }
+
+ logger.info("Shutting down thread pools.");
+
+ try {
+ if (gremlinExecutorService != null) {
+ gremlinExecutorService.shutdown();
+ }
+ } finally {
+ logger.debug("Shutdown Gremlin thread pool.");
+ }
+
+ try {
+ workerGroup
+ .shutdownGracefully()
+ .addListener((GenericFutureListener) f -> servicesLeftToShutdown.countDown());
+ } finally {
+ logger.debug("Shutdown Worker thread pool.");
+ }
+ try {
+ bossGroup
+ .shutdownGracefully()
+ .addListener((GenericFutureListener) f -> servicesLeftToShutdown.countDown());
+ } finally {
+ logger.debug("Shutdown Boss thread pool.");
+ }
+
+ // channel is shutdown as are the thread pools - time to kill graphs as nothing else should be
+ // acting on them
+ new Thread(
+ () -> {
+ if (graphServerGremlinExecutor != null) {
+ graphServerGremlinExecutor
+ .getHooks()
+ .forEach(
+ hook -> {
+ logger.info("Executing shutdown {}", LifeCycleHook.class.getSimpleName());
+ try {
+ hook.onShutDown(new LifeCycleHook.Context(logger));
+ } catch (UnsupportedOperationException
+ | UndeclaredThrowableException uoe) {
+ // if the user doesn't implement onShutDown the scriptengine will throw
+ // this exception. it can safely be ignored.
+ }
+ });
+ }
+
+ try {
+ if (gremlinExecutorService != null) {
+ if (!gremlinExecutorService.awaitTermination(30000, TimeUnit.MILLISECONDS)) {
+ logger.warn(
+ "Gremlin thread pool did not fully terminate - continuing with shutdown process");
+ }
+ }
+ } catch (InterruptedException ie) {
+ logger.warn(
+ "Timeout waiting for Gremlin thread pool to shutdown - continuing with shutdown process.");
+ }
+
+ try {
+ servicesLeftToShutdown.await(30000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException ie) {
+ logger.warn(
+ "Timeout waiting for boss/worker thread pools to shutdown - continuing with shutdown process.");
+ }
+
+ if (graphServerGremlinExecutor != null) {
+ graphServerGremlinExecutor
+ .getGraphManager()
+ .getGraphNames()
+ .forEach(
+ gName -> {
+ logger.debug("Closing Graph instance [{}]", gName);
+ try {
+ graphServerGremlinExecutor.getGraphManager().getGraph(gName).close();
+ } catch (Exception ex) {
+ logger.warn(
+ String.format("Exception while closing Graph instance [%s]", gName),
+ ex);
+ } finally {
+ logger.info("Closed Graph instance [{}]", gName);
+ }
+ });
+ }
+
+ // kills reporter threads. this is a last bit of cleanup that can be done. typically,
+ // the jvm is headed
+ // for shutdown which would obviously kill the reporters, but when it isn't they just
+ // keep reporting.
+ // removing them all will silent them up and release the appropriate resources.
+ MetricManager.INSTANCE.removeAllReporters();
+
+ // removing all the metrics should allow Gremlin Server to clean up the metrics
+ // instance so that it can be
+ // started again in the same JVM without those metrics initialized which generates a
+ // warning and won't
+ // reset to start values
+ MetricManager.INSTANCE.removeAllMetrics();
+
+ logger.info("Gremlin Server - shutdown complete");
+ serverStopped.complete(null);
+ },
+ SERVER_THREAD_PREFIX + "stop")
+ .start();
+
+ return serverStopped;
+ }
+
+ public GraphServerGremlinExecutor getGraphServerGremlinExecutor() {
+ return graphServerGremlinExecutor;
+ }
+
+ private static void provideDefaultForGremlinPoolSize(final Settings settings) {
+ if (settings.gremlinPool == 0) {
+ settings.gremlinPool = Runtime.getRuntime().availableProcessors();
+ }
+ }
+
+ private Server createGrpcServer() {
+ JanusGraphSettings janusGraphSettings = (JanusGraphSettings) settings;
+ GraphManager graphManager = getGraphServerGremlinExecutor().getGraphManager();
+ JanusGraphContextHandler janusGraphContextHandler = new JanusGraphContextHandler(graphManager);
+ return ServerBuilder.forPort(janusGraphSettings.getGrpcServer().getPort())
+ .addService(new JanusGraphManagerServiceImpl(janusGraphContextHandler))
+ .addService(new SchemaManagerImpl(janusGraphContextHandler))
+ .build();
+ }
+
+ private static void configure(GraphServerGremlinExecutor graphServerGremlinExecutor) {
+ GraphManager graphManager = graphServerGremlinExecutor.getGraphManager();
+ ((JanusGraphManager) graphManager)
+ .configureGremlinExecutor(graphServerGremlinExecutor.getGremlinExecutor());
+ }
+
+ public static JanusGraphSettings createJanusGraphSettings() {
+ JanusGraphSettings janusGraphSettings = null;
+ InputStream inputStream = null;
+ try {
+ inputStream =
+ Thread.currentThread().getContextClassLoader().getResourceAsStream("gremlin-server.yaml");
+ janusGraphSettings = JanusGraphSettings.read(inputStream);
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ } finally {
+ if (null != inputStream) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ janusGraphSettings
+ .scriptEngines
+ .get("gremlin-groovy")
+ .plugins
+ .put(
+ "org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin",
+ Collections.singletonMap(
+ "files",
+ new ArrayList<>(
+ Arrays.asList(
+ Thread.currentThread()
+ .getContextClassLoader()
+ .getResource("graph.groovy")
+ .getFile()))));
+
+ return janusGraphSettings;
+ }
+
+ public static void main(String[] args) throws GraphException {
+ JanusGraphLatest janusGraphLatest = new JanusGraphLatest(logger);
+ janusGraphLatest.open();
+ janusGraphLatest.createVertex("uniq1", "type1", null);
+ JanusGraph janusGraph = janusGraphLatest.getJanusGraph();
+
+ JanusGraphSettings janusGraphSettings = GraphGremlinServer.createJanusGraphSettings();
+ GraphGremlinServer graphGremlinServer = new GraphGremlinServer(janusGraphSettings, janusGraph);
+ graphGremlinServer.start();
+ }
+}
diff --git a/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/channel/GraphHttpChannelizer.java b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/channel/GraphHttpChannelizer.java
new file mode 100644
index 0000000000000000000000000000000000000000..043ea2a1c729f95c6f564c18c85fdf3a33441cf2
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/channel/GraphHttpChannelizer.java
@@ -0,0 +1,86 @@
+package org.apache.tinkerpop.gremlin.server.channel;
+
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.ChannelPipeline;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpServerCodec;
+import io.netty.handler.logging.LogLevel;
+import io.netty.handler.logging.LoggingHandler;
+import org.apache.tinkerpop.gremlin.server.AbstractGraphChannelizer;
+import org.apache.tinkerpop.gremlin.server.Settings;
+import org.apache.tinkerpop.gremlin.server.auth.AllowAllAuthenticator;
+import org.apache.tinkerpop.gremlin.server.handler.AbstractAuthenticationHandler;
+import org.apache.tinkerpop.gremlin.server.handler.HttpBasicAuthenticationHandler;
+import org.apache.tinkerpop.gremlin.server.handler.HttpBasicAuthorizationHandler;
+import org.apache.tinkerpop.gremlin.server.handler.HttpGremlinEndpointHandler;
+import org.apache.tinkerpop.gremlin.server.util.GraphServerGremlinExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GraphHttpChannelizer extends AbstractGraphChannelizer {
+ private static final Logger logger = LoggerFactory.getLogger(GraphHttpChannelizer.class);
+
+ private HttpGremlinEndpointHandler httpGremlinEndpointHandler;
+
+ @Override
+ public void init(final GraphServerGremlinExecutor graphServerGremlinExecutor) {
+ super.init(graphServerGremlinExecutor);
+ httpGremlinEndpointHandler =
+ new HttpGremlinEndpointHandler(serializers, gremlinExecutor, graphManager, settings);
+ }
+
+ @Override
+ public void configure(final ChannelPipeline pipeline) {
+ if (logger.isDebugEnabled()) {
+ pipeline.addLast(new LoggingHandler("log-io", LogLevel.DEBUG));
+ }
+
+ pipeline.addLast("http-server", new HttpServerCodec());
+
+ if (logger.isDebugEnabled()) {
+ pipeline.addLast(new LoggingHandler("http-io", LogLevel.DEBUG));
+ }
+
+ final HttpObjectAggregator aggregator = new HttpObjectAggregator(settings.maxContentLength);
+ aggregator.setMaxCumulationBufferComponents(settings.maxAccumulationBufferComponents);
+ pipeline.addLast(PIPELINE_HTTP_AGGREGATOR, aggregator);
+
+ if (authenticator != null) {
+ // Cannot add the same handler instance multiple times unless
+ // it is marked as @Sharable, indicating a race condition will
+ // not occur. It may not be a safe assumption that the handler
+ // is sharable so create a new handler each time.
+ final AbstractAuthenticationHandler authenticationHandler =
+ authenticator.getClass() == AllowAllAuthenticator.class
+ ? null
+ : instantiateAuthenticationHandler(settings);
+ if (authenticationHandler != null) {
+ pipeline.addLast(PIPELINE_AUTHENTICATOR, authenticationHandler);
+ }
+ }
+
+ if (authorizer != null) {
+ final ChannelInboundHandlerAdapter authorizationHandler =
+ new HttpBasicAuthorizationHandler(authorizer);
+ pipeline.addLast(PIPELINE_AUTHORIZER, authorizationHandler);
+ }
+
+ pipeline.addLast("http-gremlin-handler", httpGremlinEndpointHandler);
+ }
+
+ private AbstractAuthenticationHandler instantiateAuthenticationHandler(final Settings settings) {
+ final String authHandlerClass = settings.authentication.authenticationHandler;
+ if (authHandlerClass == null) {
+ // Keep things backwards compatible
+ return new HttpBasicAuthenticationHandler(authenticator, settings);
+ } else {
+ return createAuthenticationHandler(settings);
+ }
+ }
+
+ @Override
+ public void finalize(final ChannelPipeline pipeline) {
+ pipeline.remove(PIPELINE_OP_SELECTOR);
+ pipeline.remove(PIPELINE_OP_EXECUTOR);
+ }
+}
diff --git a/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/channel/GraphWebSocketChannelizer.java b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/channel/GraphWebSocketChannelizer.java
new file mode 100644
index 0000000000000000000000000000000000000000..0691892021fee8440d4390e93dd1c61c0c51019e
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/channel/GraphWebSocketChannelizer.java
@@ -0,0 +1,143 @@
+package org.apache.tinkerpop.gremlin.server.channel;
+
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.ChannelPipeline;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketDecoderConfig;
+import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
+import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
+import io.netty.handler.logging.LogLevel;
+import io.netty.handler.logging.LoggingHandler;
+import org.apache.tinkerpop.gremlin.server.AbstractGraphChannelizer;
+import org.apache.tinkerpop.gremlin.server.Settings;
+import org.apache.tinkerpop.gremlin.server.auth.AllowAllAuthenticator;
+import org.apache.tinkerpop.gremlin.server.handler.*;
+import org.apache.tinkerpop.gremlin.server.util.GraphServerGremlinExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GraphWebSocketChannelizer extends AbstractGraphChannelizer {
+ private static final Logger logger = LoggerFactory.getLogger(GraphWebSocketChannelizer.class);
+
+ private GremlinResponseFrameEncoder gremlinResponseFrameEncoder;
+ private WsGremlinTextRequestDecoder wsGremlinTextRequestDecoder;
+ private WsGremlinBinaryRequestDecoder wsGremlinBinaryRequestDecoder;
+ private WsGremlinResponseFrameEncoder wsGremlinResponseFrameEncoder;
+ private WsGremlinCloseRequestDecoder wsGremlinCloseRequestDecoder;
+ private AbstractAuthenticationHandler authenticationHandler;
+ private ChannelInboundHandlerAdapter authorizationHandler;
+
+ @Override
+ public void init(final GraphServerGremlinExecutor graphServerGremlinExecutor) {
+ super.init(graphServerGremlinExecutor);
+
+ gremlinResponseFrameEncoder = new GremlinResponseFrameEncoder();
+ wsGremlinTextRequestDecoder = new WsGremlinTextRequestDecoder(serializers);
+ wsGremlinBinaryRequestDecoder = new WsGremlinBinaryRequestDecoder(serializers);
+ wsGremlinCloseRequestDecoder = new WsGremlinCloseRequestDecoder(serializers);
+ wsGremlinResponseFrameEncoder = new WsGremlinResponseFrameEncoder();
+
+ // configure authentication - null means don't bother to add authentication to the pipeline
+ authenticationHandler =
+ authenticator.getClass() == AllowAllAuthenticator.class
+ ? null
+ : instantiateAuthenticationHandler(settings);
+ if (authorizer != null) {
+ authorizationHandler = new WebSocketAuthorizationHandler(authorizer);
+ }
+ }
+
+ @Override
+ public void configure(final ChannelPipeline pipeline) {
+
+ if (logger.isDebugEnabled()) {
+ pipeline.addLast(new LoggingHandler("log-encoder-aggregator", LogLevel.DEBUG));
+ }
+
+ pipeline.addLast(PIPELINE_HTTP_RESPONSE_ENCODER, new HttpResponseEncoder());
+
+ logger.debug(
+ "HttpRequestDecoder settings - maxInitialLineLength={}, maxHeaderSize={}, maxChunkSize={}",
+ settings.maxInitialLineLength,
+ settings.maxHeaderSize,
+ settings.maxChunkSize);
+ pipeline.addLast(
+ PIPELINE_HTTP_REQUEST_DECODER,
+ new HttpRequestDecoder(
+ settings.maxInitialLineLength, settings.maxHeaderSize, settings.maxChunkSize));
+
+ if (logger.isDebugEnabled()) {
+ pipeline.addLast(new LoggingHandler("log-decoder-aggregator", LogLevel.DEBUG));
+ }
+
+ logger.debug(
+ "HttpObjectAggregator settings - maxContentLength={}, maxAccumulationBufferComponents={}",
+ settings.maxContentLength,
+ settings.maxAccumulationBufferComponents);
+ final HttpObjectAggregator aggregator = new HttpObjectAggregator(settings.maxContentLength);
+ aggregator.setMaxCumulationBufferComponents(settings.maxAccumulationBufferComponents);
+ pipeline.addLast(PIPELINE_HTTP_AGGREGATOR, aggregator);
+ // Add compression extension for WebSocket defined in https://tools.ietf.org/html/rfc7692
+ pipeline.addLast(
+ PIPELINE_WEBSOCKET_SERVER_COMPRESSION, new WebSocketServerCompressionHandler());
+
+ // setting closeOnProtocolViolation to false prevents causing all the other requests using the
+ // same channel
+ // to fail when a single request causes a protocol violation.
+ final WebSocketDecoderConfig wsDecoderConfig =
+ WebSocketDecoderConfig.newBuilder()
+ .closeOnProtocolViolation(false)
+ .allowExtensions(true)
+ .maxFramePayloadLength(settings.maxContentLength)
+ .build();
+ pipeline.addLast(
+ PIPELINE_REQUEST_HANDLER,
+ new WebSocketServerProtocolHandler(
+ GREMLIN_ENDPOINT, null, false, false, 10000L, wsDecoderConfig));
+
+ if (logger.isDebugEnabled()) {
+ pipeline.addLast(new LoggingHandler("log-aggregator-encoder", LogLevel.DEBUG));
+ }
+
+ pipeline.addLast("ws-frame-encoder", wsGremlinResponseFrameEncoder);
+ pipeline.addLast("response-frame-encoder", gremlinResponseFrameEncoder);
+ pipeline.addLast("request-text-decoder", wsGremlinTextRequestDecoder);
+ pipeline.addLast("request-binary-decoder", wsGremlinBinaryRequestDecoder);
+ pipeline.addLast("request-close-decoder", wsGremlinCloseRequestDecoder);
+
+ if (logger.isDebugEnabled()) {
+ pipeline.addLast(new LoggingHandler("log-aggregator-encoder", LogLevel.DEBUG));
+ }
+
+ if (authenticationHandler != null) {
+ pipeline.addLast(PIPELINE_AUTHENTICATOR, authenticationHandler);
+ }
+
+ if (authorizationHandler != null) {
+ pipeline.addLast(PIPELINE_AUTHORIZER, authorizationHandler);
+ }
+ }
+
+ @Override
+ public boolean supportsIdleMonitor() {
+ return true;
+ }
+
+ @Override
+ public Object createIdleDetectionMessage() {
+ return new PingWebSocketFrame();
+ }
+
+ private AbstractAuthenticationHandler instantiateAuthenticationHandler(final Settings settings) {
+ final String authenticationHandler = settings.authentication.authenticationHandler;
+ if (authenticationHandler == null) {
+ // Keep things backwards compatible
+ return new SaslAuthenticationHandler(authenticator, settings);
+ } else {
+ return createAuthenticationHandler(settings);
+ }
+ }
+}
diff --git a/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/channel/GraphWsAndHttpChannelizer.java b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/channel/GraphWsAndHttpChannelizer.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed1f2bc5758479f70cedc96b6d76ea3ee4cdd0b0
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/channel/GraphWsAndHttpChannelizer.java
@@ -0,0 +1,55 @@
+/*
+ * 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.tinkerpop.gremlin.server.channel;
+
+import io.netty.channel.ChannelPipeline;
+import org.apache.tinkerpop.gremlin.server.AbstractGraphChannelizer;
+import org.apache.tinkerpop.gremlin.server.handler.GraphWsAndHttpChannelizerHandler;
+import org.apache.tinkerpop.gremlin.server.handler.HttpGremlinEndpointHandler;
+import org.apache.tinkerpop.gremlin.server.util.GraphServerGremlinExecutor;
+
+public class GraphWsAndHttpChannelizer extends AbstractGraphChannelizer {
+
+ private GraphWsAndHttpChannelizerHandler handler;
+
+ @Override
+ public void init(final GraphServerGremlinExecutor graphServerGremlinExecutor) {
+ super.init(graphServerGremlinExecutor);
+ handler = new GraphWsAndHttpChannelizerHandler();
+ handler.init(
+ graphServerGremlinExecutor,
+ new HttpGremlinEndpointHandler(serializers, gremlinExecutor, graphManager, settings));
+ }
+
+ @Override
+ public void configure(final ChannelPipeline pipeline) {
+ handler.configure(pipeline);
+ pipeline.addAfter(PIPELINE_HTTP_REQUEST_DECODER, "WsAndHttpChannelizerHandler", handler);
+ }
+
+ @Override
+ public boolean supportsIdleMonitor() {
+ return true;
+ }
+
+ @Override
+ public Object createIdleDetectionMessage() {
+ return handler.getGraphWebSocketChannelizer().createIdleDetectionMessage();
+ }
+}
diff --git a/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GraphOpSelectorHandler.java b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GraphOpSelectorHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..e4ded4a02afa2088435ea5ecb06bcc915f98ea8e
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GraphOpSelectorHandler.java
@@ -0,0 +1,111 @@
+package org.apache.tinkerpop.gremlin.server.handler;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToMessageDecoder;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
+import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor;
+import org.apache.tinkerpop.gremlin.server.*;
+import org.apache.tinkerpop.gremlin.server.op.OpLoader;
+import org.apache.tinkerpop.gremlin.server.op.OpProcessorException;
+import org.javatuples.Pair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.ScheduledExecutorService;
+
+@ChannelHandler.Sharable
+public class GraphOpSelectorHandler extends MessageToMessageDecoder {
+ private static final Logger logger = LoggerFactory.getLogger(GraphOpSelectorHandler.class);
+
+ private final Settings settings;
+ private final GraphManager graphManager;
+
+ private final GremlinExecutor gremlinExecutor;
+ private final ScheduledExecutorService scheduledExecutorService;
+ private final GraphChannelizer graphChannelizer;
+
+ public GraphOpSelectorHandler(
+ final Settings settings,
+ final GraphManager graphManager,
+ final GremlinExecutor gremlinExecutor,
+ final ScheduledExecutorService scheduledExecutorService,
+ final GraphChannelizer graphChannelizer) {
+ this.settings = settings;
+ this.graphManager = graphManager;
+ this.gremlinExecutor = gremlinExecutor;
+ this.scheduledExecutorService = scheduledExecutorService;
+ this.graphChannelizer = graphChannelizer;
+ }
+
+ @Override
+ protected void decode(
+ final ChannelHandlerContext ctx, final RequestMessage msg, final List objects)
+ throws Exception {
+ final Context gremlinServerContext =
+ new Context(
+ msg, ctx, settings, graphManager, gremlinExecutor, this.scheduledExecutorService);
+ try {
+ // choose a processor to do the work based on the request message.
+ final Optional processor = OpLoader.getProcessor(msg.getProcessor());
+
+ if (processor.isPresent())
+ // the processor is known so use it to evaluate the message
+ objects.add(Pair.with(msg, processor.get().select(gremlinServerContext)));
+ else {
+ // invalid op processor selected so write back an error by way of OpProcessorException.
+ final String errorMessage =
+ String.format("Invalid OpProcessor requested [%s]", msg.getProcessor());
+ throw new OpProcessorException(
+ errorMessage,
+ ResponseMessage.build(msg)
+ .code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS)
+ .statusMessage(errorMessage)
+ .create());
+ }
+ } catch (OpProcessorException ope) {
+ logger.warn(ope.getMessage(), ope);
+ gremlinServerContext.writeAndFlush(ope.getResponseMessage());
+ }
+ }
+
+ @Override
+ public void userEventTriggered(final ChannelHandlerContext ctx, final Object evt)
+ throws Exception {
+ // only need to handle this event if the idle monitor is on
+ if (!graphChannelizer.supportsIdleMonitor()) {
+ return;
+ }
+
+ if (evt instanceof IdleStateEvent) {
+ final IdleStateEvent e = (IdleStateEvent) evt;
+
+ // if no requests (reader) then close, if no writes from server to client then ping. clients
+ // should
+ // periodically ping the server, but coming from this direction allows the server to kill
+ // channels that
+ // have dead clients on the other end
+ if (e.state() == IdleState.READER_IDLE) {
+ logger.info(
+ "Closing channel - client is disconnected after idle period of "
+ + settings.idleConnectionTimeout
+ + " "
+ + ctx.channel().id().asShortText());
+ ctx.close();
+ } else if (e.state() == IdleState.WRITER_IDLE && settings.keepAliveInterval > 0) {
+ logger.info(
+ "Checking channel - sending ping to client after idle period of "
+ + settings.keepAliveInterval
+ + " "
+ + ctx.channel().id().asShortText());
+ ctx.writeAndFlush(graphChannelizer.createIdleDetectionMessage());
+ }
+ }
+ }
+}
diff --git a/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GraphWsAndHttpChannelizerHandler.java b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GraphWsAndHttpChannelizerHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..f809c0d546a209fac2d5ccd003ec2cd57c8c3f6d
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/handler/GraphWsAndHttpChannelizerHandler.java
@@ -0,0 +1,80 @@
+package org.apache.tinkerpop.gremlin.server.handler;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.ChannelPipeline;
+import io.netty.handler.codec.http.HttpMessage;
+import org.apache.tinkerpop.gremlin.server.GraphChannelizer;
+import org.apache.tinkerpop.gremlin.server.channel.GraphWebSocketChannelizer;
+import org.apache.tinkerpop.gremlin.server.util.GraphServerGremlinExecutor;
+
+import static org.apache.tinkerpop.gremlin.server.AbstractChannelizer.PIPELINE_HTTP_AGGREGATOR;
+import static org.apache.tinkerpop.gremlin.server.channel.WebSocketChannelizer.PIPELINE_AUTHENTICATOR;
+import static org.apache.tinkerpop.gremlin.server.channel.WebSocketChannelizer.PIPELINE_REQUEST_HANDLER;
+
+@ChannelHandler.Sharable
+public class GraphWsAndHttpChannelizerHandler extends ChannelInboundHandlerAdapter {
+
+ private final GraphWebSocketChannelizer graphWebSocketChannelizer =
+ new GraphWebSocketChannelizer();
+ private HttpGremlinEndpointHandler httpGremlinEndpointHandler;
+
+ public void init(
+ final GraphServerGremlinExecutor graphServerGremlinExecutor,
+ final HttpGremlinEndpointHandler httpGremlinEndpointHandler) {
+ // WebSocketChannelizer has everything needed for the http endpoint to work
+ graphWebSocketChannelizer.init(graphServerGremlinExecutor);
+ this.httpGremlinEndpointHandler = httpGremlinEndpointHandler;
+ }
+
+ public GraphChannelizer getGraphWebSocketChannelizer() {
+ return graphWebSocketChannelizer;
+ }
+
+ public void configure(final ChannelPipeline pipeline) {
+ graphWebSocketChannelizer.configure(pipeline);
+ }
+
+ @Override
+ public void channelRead(final ChannelHandlerContext ctx, final Object obj) {
+ final ChannelPipeline pipeline = ctx.pipeline();
+ if (obj instanceof HttpMessage && !WebSocketHandlerUtil.isWebSocket((HttpMessage) obj)) {
+ // if the message is for HTTP and not websockets then this handler injects the endpoint
+ // handler in front
+ // of the HTTP Aggregator to intercept the HttpMessage. Therefore the pipeline looks like this
+ // at start:
+ //
+ // IdleStateHandler -> HttpResponseEncoder -> HttpRequestDecoder ->
+ // WsAndHttpChannelizerHandler -> HttpObjectAggregator ->
+ // WebSocketServerCompressionHandler -> WebSocketServerProtocolHandshakeHandler -> (more
+ // websockets)
+ //
+ // and shifts to (setting aside the authentication condition):
+ //
+ // IdleStateHandler -> HttpResponseEncoder -> HttpRequestDecoder ->
+ // WsAndHttpChannelizerHandler -> HttpObjectAggregator ->
+ // HttpGremlinEndpointHandler ->
+ // WebSocketServerCompressionHandler - WebSocketServerProtocolHandshakeHandler -> (more
+ // websockets)
+ if (null != pipeline.get(PIPELINE_AUTHENTICATOR)) {
+ pipeline.remove(PIPELINE_REQUEST_HANDLER);
+ final ChannelHandler authenticator = pipeline.get(PIPELINE_AUTHENTICATOR);
+ pipeline.remove(PIPELINE_AUTHENTICATOR);
+ pipeline.addAfter(PIPELINE_HTTP_AGGREGATOR, PIPELINE_AUTHENTICATOR, authenticator);
+ pipeline.addAfter(
+ PIPELINE_AUTHENTICATOR, PIPELINE_REQUEST_HANDLER, this.httpGremlinEndpointHandler);
+ } else {
+ pipeline.remove(PIPELINE_REQUEST_HANDLER);
+ pipeline.addAfter(
+ PIPELINE_HTTP_AGGREGATOR, PIPELINE_REQUEST_HANDLER, this.httpGremlinEndpointHandler);
+ }
+ }
+ ctx.fireChannelRead(obj);
+ }
+
+ @Override
+ public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
+ ctx.close();
+ }
+}
diff --git a/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/util/GraphServerGremlinExecutor.java b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/util/GraphServerGremlinExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d10cfdb01163da889d22d9c557c487669deb2aa
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/main/java/org/apache/tinkerpop/gremlin/server/util/GraphServerGremlinExecutor.java
@@ -0,0 +1,226 @@
+package org.apache.tinkerpop.gremlin.server.util;
+
+import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor;
+import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngine;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
+import org.apache.tinkerpop.gremlin.server.GraphManager;
+import org.apache.tinkerpop.gremlin.server.Settings;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.script.SimpleBindings;
+import java.lang.reflect.Constructor;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.*;
+import java.util.stream.Collectors;
+
+import static org.studiox.graph.common.GraphConstant.JanusGraphConfigConstant.CONFIG_PREFIX;
+
+public class GraphServerGremlinExecutor {
+ private static final Logger logger = LoggerFactory.getLogger(GraphServerGremlinExecutor.class);
+
+ private final GraphManager graphManager;
+ private final Settings settings;
+ private final List hooks;
+
+ private final ScheduledExecutorService scheduledExecutorService;
+ private final ExecutorService gremlinExecutorService;
+ private final GremlinExecutor gremlinExecutor;
+
+ private final Map hostOptions = new ConcurrentHashMap<>();
+
+ public GraphServerGremlinExecutor(
+ final Settings settings,
+ final ExecutorService gremlinExecutorService,
+ final ScheduledExecutorService scheduledExecutorService,
+ final Graph graph) {
+ this.settings = settings;
+
+ try {
+ final Class> clazz = Class.forName(settings.graphManager);
+ final Constructor c = clazz.getConstructor(Settings.class);
+ graphManager = (GraphManager) c.newInstance(settings);
+ } catch (ClassNotFoundException e) {
+ logger.error(
+ "Could not find GraphManager implementation "
+ + "defined by the 'graphManager' setting as: {}",
+ settings.graphManager);
+ throw new RuntimeException(e);
+ } catch (Exception e) {
+ logger.error(
+ "Could not invoke constructor on class {} (defined by "
+ + "the 'graphManager' setting) with one argument of "
+ + "class Settings",
+ settings.graphManager);
+ throw new RuntimeException(e);
+ }
+
+ if (null != graphManager && null != graph) {
+ graphManager.putGraph(CONFIG_PREFIX, graph);
+ }
+
+ if (null == gremlinExecutorService) {
+ final ThreadFactory threadFactoryGremlin = ThreadFactoryUtil.create("exec-%d");
+ final BlockingQueue queue = new ArrayBlockingQueue<>(settings.maxWorkQueueSize);
+ this.gremlinExecutorService =
+ new ThreadPoolExecutor(
+ settings.gremlinPool,
+ settings.gremlinPool,
+ 0L,
+ TimeUnit.MILLISECONDS,
+ queue,
+ threadFactoryGremlin,
+ new ThreadPoolExecutor.AbortPolicy());
+ } else {
+ this.gremlinExecutorService = gremlinExecutorService;
+ }
+
+ if (null == scheduledExecutorService) {
+ final ThreadFactory threadFactoryGremlin = ThreadFactoryUtil.create("worker-%d");
+ this.scheduledExecutorService =
+ Executors.newScheduledThreadPool(settings.threadPoolWorker, threadFactoryGremlin);
+ } else {
+ this.scheduledExecutorService = scheduledExecutorService;
+ }
+
+ logger.info("Initialized Gremlin thread pool. Threads in pool named with pattern gremlin-*");
+
+ final GremlinExecutor.Builder gremlinExecutorBuilder =
+ GremlinExecutor.build()
+ .evaluationTimeout(settings.getEvaluationTimeout())
+ .afterFailure((b, e) -> this.graphManager.rollbackAll())
+ .beforeEval(b -> this.graphManager.rollbackAll())
+ .afterTimeout(b -> this.graphManager.rollbackAll())
+ .globalBindings(this.graphManager.getAsBindings())
+ .executorService(this.gremlinExecutorService)
+ .scheduledExecutorService(this.scheduledExecutorService);
+
+ settings.scriptEngines.forEach(
+ (k, v) -> {
+ // use plugins if they are present
+ if (!v.plugins.isEmpty()) {
+ // make sure that server related classes are available at init - new approach. the
+ // LifeCycleHook stuff
+ // will be added explicitly via configuration using GremlinServerGremlinModule in the
+ // yaml
+ gremlinExecutorBuilder.addPlugins(k, v.plugins);
+ }
+ });
+
+ gremlinExecutor = gremlinExecutorBuilder.create();
+
+ logger.info("Initialized GremlinExecutor and preparing GremlinScriptEngines instances.");
+
+ // force each scriptengine to process something so that the init scripts will fire (this is
+ // necessary if
+ // the GremlinExecutor is using the GremlinScriptEngineManager. this is a bit of hack, but it at
+ // least allows
+ // the global bindings to become available after the init scripts are run
+ // (DefaultGremlinScriptEngineManager
+ // runs the init scripts when the GremlinScriptEngine is created.
+ settings
+ .scriptEngines
+ .keySet()
+ .forEach(
+ engineName -> {
+ try {
+ // use no timeout on the engine initialization - perhaps this can be a configuration
+ // later
+ final GremlinExecutor.LifeCycle lifeCycle =
+ GremlinExecutor.LifeCycle.build().evaluationTimeoutOverride(0L).create();
+ gremlinExecutor
+ .eval("1+1", engineName, new SimpleBindings(Collections.emptyMap()), lifeCycle)
+ .join();
+ registerMetrics(engineName);
+ logger.info(
+ "Initialized {} GremlinScriptEngine and registered metrics", engineName);
+ } catch (Exception ex) {
+ logger.warn(
+ String.format(
+ "Could not initialize %s GremlinScriptEngine as init script could not be evaluated",
+ engineName),
+ ex);
+ }
+ });
+
+ // script engine init may have altered the graph bindings or maybe even created new ones - need
+ // to
+ // re-apply those references back
+ gremlinExecutor.getScriptEngineManager().getBindings().entrySet().stream()
+ .filter(kv -> kv.getValue() instanceof Graph)
+ .forEach(kv -> this.graphManager.putGraph(kv.getKey(), (Graph) kv.getValue()));
+
+ // script engine init may have constructed the TraversalSource bindings - store them in Graphs
+ // object
+ gremlinExecutor.getScriptEngineManager().getBindings().entrySet().stream()
+ .filter(kv -> kv.getValue() instanceof TraversalSource)
+ .forEach(
+ kv -> {
+ logger.info(
+ "A {} is now bound to [{}] with {}",
+ kv.getValue().getClass().getSimpleName(),
+ kv.getKey(),
+ kv.getValue());
+ this.graphManager.putTraversalSource(kv.getKey(), (TraversalSource) kv.getValue());
+ });
+
+ // determine if the initialization scripts introduced LifeCycleHook objects - if so we need to
+ // gather them
+ // up for execution
+ hooks =
+ gremlinExecutor.getScriptEngineManager().getBindings().entrySet().stream()
+ .filter(kv -> kv.getValue() instanceof LifeCycleHook)
+ .map(kv -> (LifeCycleHook) kv.getValue())
+ .collect(Collectors.toList());
+ }
+
+ private void registerMetrics(final String engineName) {
+ final GremlinScriptEngine engine =
+ gremlinExecutor.getScriptEngineManager().getEngineByName(engineName);
+ MetricManager.INSTANCE.registerGremlinScriptEngineMetrics(
+ engine, engineName, "sessionless", "class-cache");
+ }
+
+ public void addHostOption(final String key, final Object value) {
+ hostOptions.put(key, value);
+ }
+
+ public Map getHostOptions() {
+ return Collections.unmodifiableMap(hostOptions);
+ }
+
+ public Object removeHostOption(final String key) {
+ return hostOptions.remove(key);
+ }
+
+ public void clearHostOptions() {
+ hostOptions.clear();
+ }
+
+ public ScheduledExecutorService getScheduledExecutorService() {
+ return scheduledExecutorService;
+ }
+
+ public GremlinExecutor getGremlinExecutor() {
+ return gremlinExecutor;
+ }
+
+ public ExecutorService getGremlinExecutorService() {
+ return gremlinExecutorService;
+ }
+
+ public GraphManager getGraphManager() {
+ return graphManager;
+ }
+
+ public Settings getSettings() {
+ return settings;
+ }
+
+ public List getHooks() {
+ return hooks;
+ }
+}
diff --git a/graph-janusgraph/janusgraph-latest/src/main/java/org/studiox/graph/janusgraph/latest/JanusGraphLatest.java b/graph-janusgraph/janusgraph-latest/src/main/java/org/studiox/graph/janusgraph/latest/JanusGraphLatest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c1172b66a017dd36bcf14dc6f17a8da10cf1e3f
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/main/java/org/studiox/graph/janusgraph/latest/JanusGraphLatest.java
@@ -0,0 +1,17 @@
+package org.studiox.graph.janusgraph.latest;
+
+import org.apache.commons.configuration.Configuration;
+import org.slf4j.Logger;
+import org.studiox.graph.common.exception.GraphException;
+import org.studiox.graph.janusgraph.v020.JanusGraphV020;
+
+public class JanusGraphLatest extends JanusGraphV020 {
+
+ public JanusGraphLatest(Logger logger) throws GraphException {
+ super(logger);
+ }
+
+ public JanusGraphLatest(Configuration config, String hbaseTableName, Logger logger) {
+ super(config, hbaseTableName, logger);
+ }
+}
diff --git a/graph-janusgraph/janusgraph-latest/src/main/resources/graph.groovy b/graph-janusgraph/janusgraph-latest/src/main/resources/graph.groovy
new file mode 100644
index 0000000000000000000000000000000000000000..386298659e0a33a0c392004bcfe70f011363b239
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/main/resources/graph.groovy
@@ -0,0 +1,17 @@
+
+// an init script that returns a Map allows explicit setting of global bindings.
+def globals = [:]
+
+// defines a sample LifeCycleHook that prints some output to the Gremlin Server console.
+// note that the name of the key in the "global" map is unimportant.
+globals << [hook : [
+ onStartUp: { ctx ->
+ ctx.logger.info("Executed once at startup of Gremlin Server.")
+ },
+ onShutDown: { ctx ->
+ ctx.logger.info("Executed once at shutdown of Gremlin Server.")
+ }
+] as LifeCycleHook]
+
+// define the default TraversalSource to bind queries to - this one will be named "g".
+globals << [g : graph.traversal()]
diff --git a/graph-janusgraph/janusgraph-latest/src/main/resources/gremlin-server.yaml b/graph-janusgraph/janusgraph-latest/src/main/resources/gremlin-server.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d74187b958a0729a805fdcd3d2041ff5661344ec
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/main/resources/gremlin-server.yaml
@@ -0,0 +1,69 @@
+host: 0.0.0.0
+
+port: 8082
+
+useEpollEventLoop: false
+
+gremlinPool: 1
+
+evaluationTimeout: 60000
+
+channelizer: org.apache.tinkerpop.gremlin.server.channel.GraphHttpChannelizer
+
+graphs: {
+}
+
+scriptEngines: {
+ gremlin-groovy: {
+ plugins:
+ {
+ org.janusgraph.graphdb.tinkerpop.plugin.JanusGraphGremlinPlugin: { },
+ org.apache.tinkerpop.gremlin.server.jsr223.GremlinServerGremlinPlugin: { },
+ org.apache.tinkerpop.gremlin.tinkergraph.jsr223.TinkerGraphGremlinPlugin: { },
+ org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: { classImports: [ java.lang.Math ], methodImports: [ java.lang.Math#* ] }
+ #,org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: { files: [ /xxx/xxx/graph.groovy ] }
+ }
+ }
+}
+
+# JanusGraph sets default serializers. You need to uncomment the following lines, if you require any custom serializers.
+#
+# serializers:
+# - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
+# - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}
+# - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
+# - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }}
+# - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
+# # Older serialization versions for backwards compatibility:
+# - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
+# - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0, config: {ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
+# - { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}
+# - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV2d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
+# - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistryV1d0] }}
+# - { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistryV1d0] }}
+
+processors:
+ - {
+ className: org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor,
+ config: {
+ sessionTimeout: 28800000
+ }
+ }
+ - {
+ className: org.apache.tinkerpop.gremlin.server.op.traversal.TraversalOpProcessor,
+ config: {
+ cacheExpirationTime: 600000,
+ cacheMaxSize: 1000
+ }
+ }
+
+resultIterationBatchSize: 64
+maxInitialLineLength: 4096
+maxHeaderSize: 8192
+maxChunkSize: 8192
+maxContentLength: 65536
+maxAccumulationBufferComponents: 1024
+writeBufferHighWaterMark: 65536
+writeBufferLowWaterMark: 32768
+strictTransactionManagement: false
+sessionLifetimeTimeout: 600000
diff --git a/graph-janusgraph/janusgraph-latest/src/test/java/org/studiox/graph/janusgraph/latest/GraphGremlinServerTest.java b/graph-janusgraph/janusgraph-latest/src/test/java/org/studiox/graph/janusgraph/latest/GraphGremlinServerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..134aef4db05f5dccf2a4fea80cf850c0507cdd95
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/test/java/org/studiox/graph/janusgraph/latest/GraphGremlinServerTest.java
@@ -0,0 +1,28 @@
+package org.studiox.graph.janusgraph.latest;
+
+import org.apache.tinkerpop.gremlin.server.GraphGremlinServer;
+import org.janusgraph.core.JanusGraph;
+import org.janusgraph.graphdb.server.JanusGraphSettings;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.studiox.graph.common.exception.GraphException;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class GraphGremlinServerTest {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(GraphGremlinServerTest.class);
+
+ @Test
+ public void test() throws GraphException {
+ JanusGraphLatest janusGraphLatest = new JanusGraphLatest(LOGGER);
+ janusGraphLatest.open();
+ JanusGraph janusGraph = janusGraphLatest.getJanusGraph();
+
+ JanusGraphSettings janusGraphSettings = GraphGremlinServer.createJanusGraphSettings();
+ GraphGremlinServer graphGremlinServer = new GraphGremlinServer(janusGraphSettings, janusGraph);
+ graphGremlinServer.start();
+ }
+}
diff --git a/graph-janusgraph/janusgraph-latest/src/test/java/org/studiox/graph/janusgraph/latest/JanusGraphLatestTest.java b/graph-janusgraph/janusgraph-latest/src/test/java/org/studiox/graph/janusgraph/latest/JanusGraphLatestTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..661155705170071598a04918e0851cda45aece71
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/test/java/org/studiox/graph/janusgraph/latest/JanusGraphLatestTest.java
@@ -0,0 +1,14 @@
+package org.studiox.graph.janusgraph.latest;
+
+import org.junit.BeforeClass;
+import org.slf4j.LoggerFactory;
+import org.studiox.graph.common.exception.GraphException;
+import org.studiox.graph.janusgraph.common.test.JanusGraphTest;
+
+public class JanusGraphLatestTest extends JanusGraphTest {
+
+ @BeforeClass
+ public static void init() throws GraphException {
+ init(new JanusGraphLatest(LoggerFactory.getLogger(JanusGraphLatestTest.class)));
+ }
+}
diff --git a/graph-janusgraph/janusgraph-latest/src/test/resources/graph.properties b/graph-janusgraph/janusgraph-latest/src/test/resources/graph.properties
new file mode 100755
index 0000000000000000000000000000000000000000..028881eac35990e8878e4f2500384c658aaa54f8
--- /dev/null
+++ b/graph-janusgraph/janusgraph-latest/src/test/resources/graph.properties
@@ -0,0 +1,27 @@
+###################################################################
+graph.schema.default=none
+graph.storage.batch-loading=true
+###################################################################
+graph.cache.db-cache=false
+graph.ids.block-size=20000000
+graph.ids.renew-timeout=3600000
+graph.storage.buffer-size=20240
+###################################################################
+graph.gremlin.graph=org.janusgraph.core.JanusGraphFactory
+###################################################################
+graph.storage.backend=inmemory
+###################################################################
+#graph.storage.backend=hbase
+#graph.storage.hostname=localhost
+#graph.storage.hbase.table=graph_table_1
+#graph.storage.hbase.ext.zookeeper.znode.parent=/hbase1
+###################################################################
+#graph.storage.hbase.region-count=9
+#graph.storage.hbase.regions-per-server=3
+#graph.storage.hbase.ext.hbase.rpc.timeout=300000
+#graph.storage.hbase.ext.hbase.client.operation.timeout=300000
+#graph.storage.hbase.ext.hbase.client.scanner.timeout.period=300000
+###################################################################
+#graph.index.search.backend=elasticsearch
+#graph.index.search.hostname=localhost:9200
+###################################################################
diff --git a/graph-janusgraph/janusgraph-v0.2.0/pom.xml b/graph-janusgraph/janusgraph-v0.2.0/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3c0c847189e688c479271d5965d33319388abc52
--- /dev/null
+++ b/graph-janusgraph/janusgraph-v0.2.0/pom.xml
@@ -0,0 +1,54 @@
+
+
+ 4.0.0
+
+ org.studiox.graph
+ graph-janusgraph
+ 1.0.5-SNAPSHOT
+
+ org.studiox.graph.janusgraph
+ janusgraph-v0.2.0
+ 1.0.5-SNAPSHOT
+ jar
+
+ 0.2.0
+ 3.2.6
+ 1.3.1
+
+
+
+ junit
+ junit
+ test
+
+
+ org.studiox.graph.janusgraph
+ janusgraph-common
+
+
+ org.janusgraph
+ janusgraph-core
+ ${janusgraph.version}
+
+
+ org.janusgraph
+ janusgraph-hbase
+ ${janusgraph.version}
+
+
+ org.apache.hbase
+ hbase-client
+ ${hbase.version}
+
+
+
+
+
+ pl.project13.maven
+ git-commit-id-plugin
+
+
+
+
diff --git a/graph-janusgraph/janusgraph-v0.2.0/src/main/java/org/studiox/graph/janusgraph/v020/JanusGraphV020.java b/graph-janusgraph/janusgraph-v0.2.0/src/main/java/org/studiox/graph/janusgraph/v020/JanusGraphV020.java
new file mode 100644
index 0000000000000000000000000000000000000000..9f3d22ebd133557f7064e3409d0b0d6c5e314dce
--- /dev/null
+++ b/graph-janusgraph/janusgraph-v0.2.0/src/main/java/org/studiox/graph/janusgraph/v020/JanusGraphV020.java
@@ -0,0 +1,1211 @@
+package org.studiox.graph.janusgraph.v020;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.lang.StringUtils;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.janusgraph.core.*;
+import org.janusgraph.core.schema.*;
+import org.janusgraph.graphdb.database.management.ManagementSystem;
+import org.slf4j.Logger;
+import org.studiox.graph.common.GraphEdge;
+import org.studiox.graph.common.GraphLineage;
+import org.studiox.graph.common.GraphVertex;
+import org.studiox.graph.common.exception.GraphException;
+import org.studiox.graph.janusgraph.common.AbstractJanusGraph;
+import org.studiox.graph.janusgraph.common.util.DateUtil;
+import org.studiox.graph.janusgraph.common.util.StringUtil;
+
+import java.util.*;
+import java.util.concurrent.ExecutionException;
+
+import static org.studiox.graph.common.GraphConstant.JanusGraphLabelPropertyKeyIndexConstant.*;
+
+public class JanusGraphV020 extends AbstractJanusGraph {
+
+ private Logger logger;
+
+ private JanusGraphFactory.Builder builder;
+
+ public JanusGraphV020(Logger logger) throws GraphException {
+ this.logger = logger;
+ builder = JanusGraphFactory.build();
+ buildGraphConfig();
+ }
+
+ public JanusGraphV020(Configuration config, String hbaseTableName, Logger logger) {
+ this.logger = logger;
+ builder = JanusGraphFactory.build();
+ buildGraphConfig(config, hbaseTableName);
+ }
+
+ @Override
+ public void setBuilderConfig(String key, Object value) {
+ builder.set(key, value);
+ }
+
+ private JanusGraph janusGraph;
+
+ public JanusGraph getJanusGraph() {
+ return janusGraph;
+ }
+
+ private JanusGraphManagement mgmt;
+
+ @Override
+ public boolean mgmtNotContainsVertexLabel(String vertexLabelName) {
+ return !mgmt.containsVertexLabel(vertexLabelName);
+ }
+
+ @Override
+ public void mgmtMakeVertexLabel(String vertexLabelName) {
+ mgmt.makeVertexLabel(vertexLabelName).make();
+ }
+
+ @Override
+ public boolean mgmtNotContainsEdgeLabel(String edgeLabelName) {
+ return !mgmt.containsEdgeLabel(edgeLabelName);
+ }
+
+ @Override
+ public void mgmtMakeEdgeLabel(String edgeLabelName) {
+ mgmt.makeEdgeLabel(edgeLabelName).multiplicity(Multiplicity.MULTI).make();
+ }
+
+ @Override
+ public boolean mgmtNotContainsPropertyKey(String propertyKeyName) {
+ return !mgmt.containsPropertyKey(propertyKeyName);
+ }
+
+ @Override
+ public void mgmtMakePropertyKey(String propertyKeyName, Class> zlass) {
+ mgmt.makePropertyKey(propertyKeyName).dataType(zlass).cardinality(Cardinality.SINGLE).make();
+ }
+
+ @Override
+ public boolean mgmtNotContainsGraphIndex(String indexName) {
+ return !mgmt.containsGraphIndex(indexName);
+ }
+
+ @Override
+ public void mgmtBuildVertexIndexOnlyWithOneKeyUnique(
+ String indexName, String propertyKeyName, String labelName) {
+ PropertyKey propertyKey = mgmt.getPropertyKey(propertyKeyName);
+ VertexLabel vertexLabel = mgmt.getVertexLabel(labelName);
+ JanusGraphIndex janusGraphIndex =
+ mgmt.buildIndex(indexName, Vertex.class)
+ .addKey(propertyKey)
+ .indexOnly(vertexLabel)
+ .unique()
+ .buildCompositeIndex();
+ mgmt.setConsistency(janusGraphIndex, ConsistencyModifier.LOCK);
+ }
+
+ @Override
+ public void mgmtBuildVertexIndexWithOneKey(String indexName, String propertyKeyName) {
+ PropertyKey propertyKey = mgmt.getPropertyKey(propertyKeyName);
+ mgmt.buildIndex(indexName, Vertex.class).addKey(propertyKey).buildCompositeIndex();
+ }
+
+ @Override
+ public void mgmtBuildEdgeIndexWithOneKey(String indexName, String propertyKeyName) {
+ PropertyKey propertyKey = mgmt.getPropertyKey(propertyKeyName);
+ mgmt.buildIndex(indexName, Edge.class).addKey(propertyKey).buildCompositeIndex();
+ }
+
+ @Override
+ public void mgmtBuildEdgeIndexWithTwoKey(
+ String indexName, String firstPropertyKeyName, String secondPropertyKeyName) {
+ PropertyKey firstPropertyKey = mgmt.getPropertyKey(firstPropertyKeyName);
+ PropertyKey secondPropertyKey = mgmt.getPropertyKey(secondPropertyKeyName);
+ mgmt.buildIndex(indexName, Edge.class)
+ .addKey(firstPropertyKey)
+ .addKey(secondPropertyKey)
+ .buildCompositeIndex();
+ }
+
+ @Override
+ public void mgmtBuildEdgeIndexWithThreeKey(
+ String indexName,
+ String firstPropertyKeyName,
+ String secondPropertyKeyName,
+ String thirdPropertyKeyName) {
+ PropertyKey firstPropertyKey = mgmt.getPropertyKey(firstPropertyKeyName);
+ PropertyKey secondPropertyKey = mgmt.getPropertyKey(secondPropertyKeyName);
+ PropertyKey thirdPropertyKey = mgmt.getPropertyKey(thirdPropertyKeyName);
+ mgmt.buildIndex(indexName, Edge.class)
+ .addKey(firstPropertyKey)
+ .addKey(secondPropertyKey)
+ .addKey(thirdPropertyKey)
+ .buildCompositeIndex();
+ }
+
+ @Override
+ public boolean mgmtNotContainsRelationIndex(String edgeLabelName, String relationIndexName) {
+ EdgeLabel edgeLabel = mgmt.getEdgeLabel(edgeLabelName);
+ return !mgmt.containsRelationIndex(edgeLabel, relationIndexName);
+ }
+
+ @Override
+ public void mgmtBuildRelationIndexWithOneKey(
+ String edgeLabelName, String relationIndexName, String propertyKeyName) {
+ EdgeLabel edgeLabel = mgmt.getEdgeLabel(edgeLabelName);
+ PropertyKey propertyKey = mgmt.getPropertyKey(propertyKeyName);
+ mgmt.buildEdgeIndex(edgeLabel, relationIndexName, Direction.BOTH, propertyKey);
+ }
+
+ @Override
+ public void mgmtBuildRelationIndexWithTwoKey(
+ String edgeLabelName,
+ String relationIndexName,
+ String firstPropertyKeyName,
+ String secondPropertyKeyName) {
+ EdgeLabel edgeLabel = mgmt.getEdgeLabel(edgeLabelName);
+ PropertyKey firstPropertyKey = mgmt.getPropertyKey(firstPropertyKeyName);
+ PropertyKey secondPropertyKey = mgmt.getPropertyKey(secondPropertyKeyName);
+ mgmt.buildEdgeIndex(
+ edgeLabel, relationIndexName, Direction.BOTH, firstPropertyKey, secondPropertyKey);
+ }
+
+ @Override
+ public void mgmtBuildRelationIndexWithThreeKey(
+ String edgeLabelName,
+ String relationIndexName,
+ String firstPropertyKeyName,
+ String secondPropertyKeyName,
+ String thirdPropertyKeyName) {
+ EdgeLabel edgeLabel = mgmt.getEdgeLabel(edgeLabelName);
+ PropertyKey firstPropertyKey = mgmt.getPropertyKey(firstPropertyKeyName);
+ PropertyKey secondPropertyKey = mgmt.getPropertyKey(secondPropertyKeyName);
+ PropertyKey thirdPropertyKey = mgmt.getPropertyKey(thirdPropertyKeyName);
+ mgmt.buildEdgeIndex(
+ edgeLabel,
+ relationIndexName,
+ Direction.BOTH,
+ firstPropertyKey,
+ secondPropertyKey,
+ thirdPropertyKey);
+ }
+
+ @Override
+ public void updateGraphIndexWithReindex(String indexName)
+ throws ExecutionException, InterruptedException {
+ mgmt.updateIndex(mgmt.getGraphIndex(indexName), SchemaAction.REINDEX).get();
+ }
+
+ @Override
+ public void updateRelationIndexWithReindex(String edgeLabelName, String relationIndexName)
+ throws ExecutionException, InterruptedException {
+ EdgeLabel edgeLabel = mgmt.getEdgeLabel(edgeLabelName);
+ mgmt.updateIndex(mgmt.getRelationIndex(edgeLabel, relationIndexName), SchemaAction.REINDEX)
+ .get();
+ }
+
+ @Override
+ public void awaitGraphIndexStatusWithEnabled(String indexName) throws InterruptedException {
+ ManagementSystem.awaitGraphIndexStatus(janusGraph, indexName)
+ .status(SchemaStatus.ENABLED)
+ .call();
+ }
+
+ @Override
+ public void awaitRelationIndexStatusWithEnabled(String edgeLabelName, String relationIndexName)
+ throws InterruptedException {
+ ManagementSystem.awaitRelationIndexStatus(janusGraph, relationIndexName, edgeLabelName)
+ .status(SchemaStatus.ENABLED)
+ .call();
+ }
+
+ @Override
+ public void mgmtCommit() {
+ mgmt.commit();
+ }
+
+ @Override
+ public void mgmtRollback() {
+ mgmt.rollback();
+ }
+
+ @Override
+ public void open() throws GraphException {
+ logger.info("## JanusGraph start to create instance...");
+ janusGraph = builder.open();
+ mgmt = janusGraph.openManagement();
+ super.open();
+ logger.info("## JanusGraph create instance finish.");
+ }
+
+ @Override
+ public void close() {
+ if (null != janusGraph && janusGraph.isOpen()) {
+ logger.info("## JanusGraph start to close...");
+ try {
+ janusGraph.close();
+ } catch (Throwable t) {
+ logger.info("## JanusGraph instance close failed, caused by {}", t.getMessage(), t);
+ return;
+ }
+ logger.info("## JanusGraph instance closed.");
+ }
+ }
+
+ private Long createJanusGraphVertex(String uniq, String type, Long createTime) {
+ if (StringUtils.isBlank(uniq)) {
+ return null;
+ }
+ try {
+ JanusGraphVertex vertex = janusGraph.addVertex(LABEL_VERTEX);
+ vertex.property(VERTEX_PROPERTY_UNIQ, uniq);
+ if (StringUtils.isNotBlank(type)) {
+ vertex.property(VERTEX_PROPERTY_TYPE, type);
+ }
+ vertex.property(VERTEX_PROPERTY_DELETED, false);
+ if (null != createTime) {
+ vertex.property(VERTEX_PROPERTY_CREATE_TIME, createTime);
+ } else {
+ vertex.property(VERTEX_PROPERTY_CREATE_TIME, DateUtil.getCurrentTimestamp());
+ }
+ janusGraph.tx().commit();
+ return (Long) vertex.id();
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ janusGraph.tx().rollback();
+ return null;
+ }
+ }
+
+ private boolean updateJanusGraphVertex(
+ List vertices, String uniq, String type, Long createTime) {
+ if (null == vertices || vertices.isEmpty()) {
+ return false;
+ }
+ for (Vertex vertex : vertices) {
+ try {
+ boolean skip = true;
+ if (StringUtils.isNotBlank(uniq)) {
+ if (vertex.property(VERTEX_PROPERTY_UNIQ).isPresent()) {
+ if (!vertex.value(VERTEX_PROPERTY_UNIQ).toString().equals(uniq)) {
+ vertex.property(VERTEX_PROPERTY_UNIQ, uniq);
+ skip = false;
+ }
+ } else {
+ vertex.property(VERTEX_PROPERTY_UNIQ, uniq);
+ skip = false;
+ }
+ }
+ if (StringUtils.isNotBlank(type)) {
+ if (vertex.property(VERTEX_PROPERTY_TYPE).isPresent()) {
+ if (!vertex.value(VERTEX_PROPERTY_TYPE).toString().equals(type)) {
+ vertex.property(VERTEX_PROPERTY_TYPE, type);
+ skip = false;
+ }
+ } else {
+ vertex.property(VERTEX_PROPERTY_TYPE, type);
+ skip = false;
+ }
+ }
+ if (null != createTime) {
+ if (vertex.property(VERTEX_PROPERTY_CREATE_TIME).isPresent()) {
+ if (Long.parseLong(vertex.value(VERTEX_PROPERTY_CREATE_TIME).toString())
+ != createTime) {
+ vertex.property(VERTEX_PROPERTY_CREATE_TIME, createTime);
+ skip = false;
+ }
+ } else {
+ vertex.property(VERTEX_PROPERTY_CREATE_TIME, createTime);
+ skip = false;
+ }
+ }
+ if (!skip) {
+ janusGraph.tx().commit();
+ }
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ janusGraph.tx().rollback();
+ }
+ }
+ return true;
+ }
+
+ private Vertex getJanusGraphVertexById(Long vertexId) {
+ if (null == vertexId || vertexId <= 0) {
+ return null;
+ }
+ return janusGraph.traversal().V(vertexId).next();
+ }
+
+ private List getJanusGraphVerticesByUniq(String uniq) {
+ if (StringUtils.isBlank(uniq)) {
+ return Collections.emptyList();
+ }
+ return janusGraph.traversal().V().has(VERTEX_PROPERTY_UNIQ, uniq).toList();
+ }
+
+ private List getJanusGraphVerticesByType(String type) {
+ if (StringUtils.isBlank(type)) {
+ return janusGraph.traversal().V().toList();
+ }
+ return janusGraph.traversal().V().has(VERTEX_PROPERTY_TYPE, type).toList();
+ }
+
+ @Override
+ public Long createVertex(String uniq, String type, Long createTime) {
+ List vertices = getJanusGraphVerticesByUniq(uniq);
+ if (null != vertices && !vertices.isEmpty()) {
+ return null;
+ }
+ return createJanusGraphVertex(uniq, type, createTime);
+ }
+
+ @Override
+ public Long createVertexNotPreCheck(String uniq, String type, Long createTime) {
+ return createJanusGraphVertex(uniq, type, createTime);
+ }
+
+ @Override
+ public boolean updateVertex(String uniq, String type, Long createTime) {
+ List vertices = getJanusGraphVerticesByUniq(uniq);
+ if (null != vertices && !vertices.isEmpty()) {
+ return updateJanusGraphVertex(vertices, null, type, createTime);
+ }
+ vertices = getJanusGraphVerticesByType(type);
+ return updateJanusGraphVertex(vertices, null, type, createTime);
+ }
+
+ private boolean updateEdgeSourceTargetVertexUniq(String uniq) {
+ if (StringUtils.isBlank(uniq)) {
+ return false;
+ }
+ List inEdges =
+ janusGraph.traversal().V().has(VERTEX_PROPERTY_UNIQ, uniq).inE(LABEL_EDGE).toList();
+ if (null != inEdges) {
+ for (Edge edge : inEdges) {
+ try {
+ boolean skip = true;
+ if (edge.property(EDGE_PROPERTY_TARGET_VERTEX_UNIQ).isPresent()) {
+ if (!edge.value(EDGE_PROPERTY_TARGET_VERTEX_UNIQ).toString().equals(uniq)) {
+ edge.property(EDGE_PROPERTY_TARGET_VERTEX_UNIQ, uniq);
+ skip = false;
+ }
+ } else {
+ edge.property(EDGE_PROPERTY_TARGET_VERTEX_UNIQ, uniq);
+ skip = false;
+ }
+ if (!skip) {
+ janusGraph.tx().commit();
+ }
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ janusGraph.tx().rollback();
+ }
+ }
+ }
+ List outEdges =
+ janusGraph.traversal().V().has(VERTEX_PROPERTY_UNIQ, uniq).outE(LABEL_EDGE).toList();
+ if (null != outEdges) {
+ for (Edge edge : outEdges) {
+ try {
+ boolean skip = true;
+ if (edge.property(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ).isPresent()) {
+ if (!edge.value(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ).toString().equals(uniq)) {
+ edge.property(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ, uniq);
+ skip = false;
+ }
+ } else {
+ edge.property(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ, uniq);
+ skip = false;
+ }
+ if (!skip) {
+ janusGraph.tx().commit();
+ }
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ janusGraph.tx().rollback();
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean updateVertex(String oldUniq, String newUniq, String type, Long createTime) {
+ if (StringUtils.isBlank(oldUniq) || StringUtils.isBlank(newUniq)) {
+ return false;
+ }
+ List vertices = getJanusGraphVerticesByUniq(newUniq);
+ if (null != vertices && !vertices.isEmpty()) {
+ return false;
+ }
+ vertices = getJanusGraphVerticesByUniq(oldUniq);
+ if (null == vertices || vertices.isEmpty()) {
+ return false;
+ }
+ boolean updateVertexFlag = updateJanusGraphVertex(vertices, newUniq, type, createTime);
+ boolean updateEdgeFlag = false;
+ if (updateVertexFlag) {
+ updateEdgeFlag = updateEdgeSourceTargetVertexUniq(newUniq);
+ }
+ return updateVertexFlag & updateEdgeFlag;
+ }
+
+ private void updateJanusGraphVertexDeletedStatus(List vertices, boolean deleted) {
+ if (null == vertices || vertices.isEmpty()) {
+ return;
+ }
+ for (Vertex vertex : vertices) {
+ try {
+ boolean skip = true;
+ if (vertex.property(VERTEX_PROPERTY_DELETED).isPresent()) {
+ boolean current = Boolean.parseBoolean(vertex.value(VERTEX_PROPERTY_DELETED).toString());
+ if (current != deleted) {
+ vertex.property(VERTEX_PROPERTY_DELETED, deleted);
+ skip = false;
+ }
+ } else {
+ vertex.property(VERTEX_PROPERTY_DELETED, deleted);
+ skip = false;
+ }
+ if (!skip) {
+ janusGraph.tx().commit();
+ }
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ janusGraph.tx().rollback();
+ }
+ }
+ }
+
+ private boolean updateJanusGraphVertexDeletedStatus(String uniq, String type, boolean deleted) {
+ if (StringUtils.isNotBlank(uniq)) {
+ List vertices = getJanusGraphVerticesByUniq(uniq);
+ if (null != vertices && !vertices.isEmpty()) {
+ updateJanusGraphVertexDeletedStatus(vertices, deleted);
+ }
+ } else {
+ List vertices = getJanusGraphVerticesByType(type);
+ updateJanusGraphVertexDeletedStatus(vertices, deleted);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean softDeleteVertices(String uniq, String type) {
+ return updateJanusGraphVertexDeletedStatus(uniq, type, true);
+ }
+
+ @Override
+ public boolean recoverDeletedVertices(String uniq, String type) {
+ return updateJanusGraphVertexDeletedStatus(uniq, type, false);
+ }
+
+ @Override
+ public boolean hardDeleteVertices(String uniq, String type) {
+ if (StringUtils.isNotBlank(uniq)) {
+ try {
+ janusGraph.traversal().V().has(VERTEX_PROPERTY_UNIQ, uniq).drop().iterate();
+ janusGraph.tx().commit();
+ return true;
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ janusGraph.tx().rollback();
+ return false;
+ }
+ }
+ if (StringUtils.isNotBlank(type)) {
+ try {
+ janusGraph.traversal().V().has(VERTEX_PROPERTY_TYPE, type).drop().iterate();
+ janusGraph.tx().commit();
+ return true;
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ janusGraph.tx().rollback();
+ return false;
+ }
+ }
+ try {
+ janusGraph.traversal().V().drop().iterate();
+ janusGraph.tx().commit();
+ return true;
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ janusGraph.tx().rollback();
+ return false;
+ }
+ }
+
+ private Edge getJanusGraphEdgeById(String edgeId) {
+ if (StringUtils.isBlank(edgeId)) {
+ return null;
+ }
+ return janusGraph.traversal().E(edgeId).next();
+ }
+
+ private GraphTraversal getJanusGraphEdgeTraversal(
+ String uniq, String type, String sourceVertexUniq, String targetVertexUniq) {
+ if (StringUtils.isNotBlank(uniq)) {
+ return janusGraph.traversal().E().has(EDGE_PROPERTY_UNIQ, uniq);
+ }
+ if (StringUtils.isNotBlank(type)) {
+ if (StringUtils.isNotBlank(sourceVertexUniq) && StringUtils.isNotBlank(targetVertexUniq)) {
+ return janusGraph
+ .traversal()
+ .E()
+ .has(EDGE_PROPERTY_TYPE, type)
+ .has(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ, sourceVertexUniq)
+ .has(EDGE_PROPERTY_TARGET_VERTEX_UNIQ, targetVertexUniq);
+ } else if (StringUtils.isNotBlank(sourceVertexUniq)
+ && StringUtils.isBlank(targetVertexUniq)) {
+ return janusGraph
+ .traversal()
+ .E()
+ .has(EDGE_PROPERTY_TYPE, type)
+ .has(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ, sourceVertexUniq);
+ } else if (StringUtils.isBlank(sourceVertexUniq)
+ && StringUtils.isNotBlank(targetVertexUniq)) {
+ return janusGraph
+ .traversal()
+ .E()
+ .has(EDGE_PROPERTY_TYPE, type)
+ .has(EDGE_PROPERTY_TARGET_VERTEX_UNIQ, targetVertexUniq);
+ } else {
+ return janusGraph.traversal().E().has(EDGE_PROPERTY_TYPE, type);
+ }
+ }
+ if (StringUtils.isNotBlank(sourceVertexUniq) && StringUtils.isNotBlank(targetVertexUniq)) {
+ return janusGraph
+ .traversal()
+ .E()
+ .has(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ, sourceVertexUniq)
+ .has(EDGE_PROPERTY_TARGET_VERTEX_UNIQ, targetVertexUniq);
+ } else if (StringUtils.isNotBlank(sourceVertexUniq) && StringUtils.isBlank(targetVertexUniq)) {
+ return janusGraph.traversal().E().has(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ, sourceVertexUniq);
+ } else if (StringUtils.isBlank(sourceVertexUniq) && StringUtils.isNotBlank(targetVertexUniq)) {
+ return janusGraph.traversal().E().has(EDGE_PROPERTY_TARGET_VERTEX_UNIQ, targetVertexUniq);
+ }
+ return janusGraph.traversal().E();
+ }
+
+ private List getJanusGraphEdges(
+ String uniq, String type, String sourceVertexUniq, String targetVertexUniq) {
+ GraphTraversal janusGraphEdgeTraversal =
+ getJanusGraphEdgeTraversal(uniq, type, sourceVertexUniq, targetVertexUniq);
+ if (null != janusGraphEdgeTraversal) {
+ return janusGraphEdgeTraversal.toList();
+ }
+ return Collections.emptyList();
+ }
+
+ private String createJanusGraphEdge(
+ String uniq, String type, Vertex sourceVertex, Vertex targetVertex, Long createTime) {
+ if (StringUtils.isBlank(uniq)) {
+ return null;
+ }
+ if (null == sourceVertex || null == targetVertex) {
+ return null;
+ }
+ try {
+ Edge edge = sourceVertex.addEdge(LABEL_EDGE, targetVertex);
+ edge.property(EDGE_PROPERTY_UNIQ, uniq);
+ if (StringUtils.isNotBlank(type)) {
+ edge.property(EDGE_PROPERTY_TYPE, type);
+ }
+ edge.property(EDGE_PROPERTY_DELETED, false);
+ if (sourceVertex.property(VERTEX_PROPERTY_UNIQ).isPresent()) {
+ edge.property(
+ EDGE_PROPERTY_SOURCE_VERTEX_UNIQ, sourceVertex.value(VERTEX_PROPERTY_UNIQ).toString());
+ }
+ if (targetVertex.property(VERTEX_PROPERTY_UNIQ).isPresent()) {
+ edge.property(
+ EDGE_PROPERTY_TARGET_VERTEX_UNIQ, targetVertex.value(VERTEX_PROPERTY_UNIQ).toString());
+ }
+ if (null != createTime) {
+ edge.property(EDGE_PROPERTY_CREATE_TIME, createTime);
+ } else {
+ edge.property(EDGE_PROPERTY_CREATE_TIME, DateUtil.getCurrentTimestamp());
+ }
+ janusGraph.tx().commit();
+ return edge.id().toString();
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ janusGraph.tx().rollback();
+ return null;
+ }
+ }
+
+ @Override
+ public String createEdge(
+ String uniq, String type, String sourceVertexUniq, String targetVertexUniq, Long createTime) {
+ if (StringUtil.checkStringParamsBlank(uniq, sourceVertexUniq, targetVertexUniq)) {
+ return null;
+ }
+ List edges = getJanusGraphEdges(uniq, null, null, null);
+ if (null != edges && !edges.isEmpty()) {
+ return null;
+ }
+ List sourceVertices = getJanusGraphVerticesByUniq(sourceVertexUniq);
+ if (null == sourceVertices || sourceVertices.isEmpty()) {
+ Long vertexId = createVertex(sourceVertexUniq, type, createTime);
+ if (null != vertexId) {
+ sourceVertices = new ArrayList<>();
+ sourceVertices.add(getJanusGraphVertexById(vertexId));
+ } else {
+ logger.warn(
+ "Create edge uniq='{}',type='{}',sourceVertexUniq='{}',targetVertexUniq='{}' failed when create source vertex.",
+ uniq,
+ type,
+ sourceVertexUniq,
+ targetVertexUniq);
+ return null;
+ }
+ }
+ List targetVertices = getJanusGraphVerticesByUniq(targetVertexUniq);
+ if (null == targetVertices || targetVertices.isEmpty()) {
+ Long vertexId = createVertex(targetVertexUniq, type, createTime);
+ if (null != vertexId) {
+ targetVertices = new ArrayList<>();
+ targetVertices.add(getJanusGraphVertexById(vertexId));
+ } else {
+ logger.warn(
+ "Create edge uniq='{}',type='{}',sourceVertexUniq='{}',targetVertexUniq='{}' failed when create target vertex.",
+ uniq,
+ type,
+ sourceVertexUniq,
+ targetVertexUniq);
+ return null;
+ }
+ }
+ if (sourceVertices.size() > 1) {
+ logger.warn(
+ "## CreateEdge method query '{}' vertices by sourceVertexUniq='{}'.",
+ sourceVertices.size(),
+ sourceVertexUniq);
+ }
+ if (targetVertices.size() > 1) {
+ logger.warn(
+ "## CreateEdge method query '{}' vertices by targetVertexUniq='{}'.",
+ targetVertices.size(),
+ targetVertexUniq);
+ }
+ return createJanusGraphEdge(
+ uniq, type, sourceVertices.get(0), targetVertices.get(0), createTime);
+ }
+
+ @Override
+ public String createEdgeNotPreCheck(
+ String uniq, String type, Long sourceVertexId, Long targetVertexId, Long createTime) {
+ if (StringUtils.isBlank(uniq)) {
+ return null;
+ }
+ Vertex sourceVertex = getJanusGraphVertexById(sourceVertexId);
+ if (null == sourceVertex) {
+ return null;
+ }
+ Vertex targetVertex = getJanusGraphVertexById(targetVertexId);
+ if (null == targetVertex) {
+ return null;
+ }
+ return createJanusGraphEdge(uniq, type, sourceVertex, targetVertex, createTime);
+ }
+
+ private boolean setJanusGraphEdgesDeletedStatus(List edges, boolean deleted) {
+ if (null == edges || edges.isEmpty()) {
+ return false;
+ }
+ for (Edge edge : edges) {
+ try {
+ boolean skip = true;
+ if (edge.property(EDGE_PROPERTY_DELETED).isPresent()) {
+ boolean current = Boolean.parseBoolean(edge.value(EDGE_PROPERTY_DELETED).toString());
+ if (current != deleted) {
+ edge.property(EDGE_PROPERTY_DELETED, deleted);
+ skip = false;
+ }
+ } else {
+ edge.property(EDGE_PROPERTY_DELETED, deleted);
+ skip = false;
+ }
+ if (!skip) {
+ janusGraph.tx().commit();
+ }
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ janusGraph.tx().rollback();
+ }
+ }
+ return true;
+ }
+
+ private boolean deleteJanusGraphEdges(
+ String uniq, String type, String sourceVertexUniq, String targetVertexUniq, boolean deleted) {
+ List edges = getJanusGraphEdges(uniq, type, sourceVertexUniq, targetVertexUniq);
+ if (null == edges || edges.isEmpty()) {
+ return false;
+ }
+ if (edges.size() > 1) {
+ logger.warn(
+ "## DeleteJanusGraphEdges method query '{}' edges by uniq={},type='{}',sourceVertexUniq={},targetVertexUniq={}.",
+ edges.size(),
+ uniq,
+ type,
+ sourceVertexUniq,
+ targetVertexUniq);
+ }
+ return setJanusGraphEdgesDeletedStatus(edges, deleted);
+ }
+
+ @Override
+ public boolean softDeleteEdges(
+ String uniq, String type, String sourceVertexUniq, String targetVertexUniq) {
+ return deleteJanusGraphEdges(uniq, type, sourceVertexUniq, targetVertexUniq, true);
+ }
+
+ @Override
+ public boolean recoverDeletedEdges(
+ String uniq, String type, String sourceVertexUniq, String targetVertexUniq) {
+ return deleteJanusGraphEdges(uniq, type, sourceVertexUniq, targetVertexUniq, false);
+ }
+
+ private boolean hardDeleteJanusGraphEdges(
+ String uniq, String type, String sourceVertexUniq, String targetVertexUniq) {
+ GraphTraversal janusGraphEdgeTraversal =
+ getJanusGraphEdgeTraversal(uniq, type, sourceVertexUniq, targetVertexUniq);
+ if (null == janusGraphEdgeTraversal) {
+ return false;
+ }
+ try {
+ janusGraphEdgeTraversal.drop().iterate();
+ janusGraph.tx().commit();
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ janusGraph.tx().rollback();
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean hardDeleteEdges(
+ String uniq, String type, String sourceVertexUniq, String targetVertexUniq) {
+ return hardDeleteJanusGraphEdges(uniq, type, sourceVertexUniq, targetVertexUniq);
+ }
+
+ private GraphVertex transferToGraphVertex(Vertex v) {
+ if (null == v) {
+ return null;
+ }
+ // org.studiox.graph.janusgraph.common.JanusGraphVertex graphVertex =
+ // new org.studiox.graph.janusgraph.common.JanusGraphVertex();
+ GraphVertex graphVertex = new GraphVertex();
+ try {
+ // graphVertex.setId(Long.parseLong(v.id().toString()));
+ if (v.property(VERTEX_PROPERTY_UNIQ).isPresent()) {
+ graphVertex.setUniq(v.value(VERTEX_PROPERTY_UNIQ).toString());
+ }
+ if (v.property(VERTEX_PROPERTY_TYPE).isPresent()) {
+ graphVertex.setType(v.value(VERTEX_PROPERTY_TYPE).toString());
+ }
+ if (v.property(VERTEX_PROPERTY_DELETED).isPresent()) {
+ graphVertex.setDeleted(Boolean.valueOf(v.value(VERTEX_PROPERTY_DELETED).toString()));
+ }
+ if (v.property(VERTEX_PROPERTY_CREATE_TIME).isPresent()) {
+ graphVertex.setCreateTime(Long.parseLong(v.value(VERTEX_PROPERTY_CREATE_TIME).toString()));
+ }
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ }
+ return graphVertex;
+ }
+
+ @Override
+ public Long getJanusGraphVertexId(String uniq) {
+ List vertices = getJanusGraphVerticesByUniq(uniq);
+ if (null == vertices || vertices.isEmpty()) {
+ return null;
+ }
+ if (vertices.size() > 1) {
+ logger.warn("## GetVertex method query '{}' vertices by uniq='{}'.", vertices.size(), uniq);
+ }
+ return Long.parseLong(vertices.get(0).id().toString());
+ }
+
+ @Override
+ public GraphVertex getVertex(String uniq) {
+ List vertices = getJanusGraphVerticesByUniq(uniq);
+ if (null == vertices || vertices.isEmpty()) {
+ return null;
+ }
+ if (vertices.size() > 1) {
+ logger.warn("## GetVertex method query '{}' vertices by uniq='{}'.", vertices.size(), uniq);
+ }
+ return transferToGraphVertex(vertices.get(0));
+ }
+
+ @Override
+ public List getVerticesByType(String type) {
+ List vertices = getJanusGraphVerticesByType(type);
+ if (null == vertices || vertices.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List result = new ArrayList<>();
+ for (Vertex v : vertices) {
+ GraphVertex vertex = transferToGraphVertex(v);
+ if (null == vertex) {
+ continue;
+ }
+ result.add(vertex);
+ }
+ return result;
+ }
+
+ private GraphEdge transferToGraphEdge(Edge e) {
+ if (null == e) {
+ return null;
+ }
+ // org.studiox.graph.janusgraph.common.JanusGraphEdge graphEdge =
+ // new org.studiox.graph.janusgraph.common.JanusGraphEdge();
+ GraphEdge graphEdge = new GraphEdge();
+ try {
+ // graphEdge.setId(((RelationIdentifier) e.id()).toString());
+ // graphEdge.setSourceVertexId(Long.parseLong(e.outVertex().id().toString()));
+ // graphEdge.setTargetVertexId(Long.parseLong(e.inVertex().id().toString()));
+ if (e.property(EDGE_PROPERTY_UNIQ).isPresent()) {
+ graphEdge.setUniq(e.value(EDGE_PROPERTY_UNIQ).toString());
+ }
+ if (e.property(EDGE_PROPERTY_TYPE).isPresent()) {
+ graphEdge.setType(e.value(EDGE_PROPERTY_TYPE).toString());
+ }
+ if (e.property(EDGE_PROPERTY_DELETED).isPresent()) {
+ graphEdge.setDeleted(Boolean.valueOf(e.value(EDGE_PROPERTY_DELETED).toString()));
+ }
+ if (e.property(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ).isPresent()) {
+ graphEdge.setSourceVertexUniq(e.value(EDGE_PROPERTY_SOURCE_VERTEX_UNIQ).toString());
+ }
+ if (e.property(EDGE_PROPERTY_TARGET_VERTEX_UNIQ).isPresent()) {
+ graphEdge.setTargetVertexUniq(e.value(EDGE_PROPERTY_TARGET_VERTEX_UNIQ).toString());
+ }
+ if (e.property(EDGE_PROPERTY_CREATE_TIME).isPresent()) {
+ graphEdge.setCreateTime(Long.parseLong(e.value(EDGE_PROPERTY_CREATE_TIME).toString()));
+ }
+ } catch (Throwable t) {
+ logger.error(t.getMessage(), t);
+ }
+ return graphEdge;
+ }
+
+ private List transferToGraphEdges(List edges) {
+ if (null == edges || edges.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List result = new ArrayList<>();
+ for (Edge e : edges) {
+ GraphEdge edge = transferToGraphEdge(e);
+ if (null == e) {
+ continue;
+ }
+ result.add(edge);
+ }
+ return result;
+ }
+
+ @Override
+ public GraphEdge getEdge(String uniq) {
+ List edges = getJanusGraphEdges(uniq, null, null, null);
+ if (null == edges || edges.isEmpty()) {
+ return null;
+ }
+ return transferToGraphEdge(edges.get(0));
+ }
+
+ @Override
+ public List getEdges(String type, String sourceVertexUniq, String targetVertexUniq) {
+ List edges = getJanusGraphEdges(null, type, sourceVertexUniq, targetVertexUniq);
+ return transferToGraphEdges(edges);
+ }
+
+ @Override
+ public Map getSourceVertexEdgeMap(String vertexUniq) {
+ if (StringUtils.isBlank(vertexUniq)) {
+ return Collections.emptyMap();
+ }
+ List edges =
+ janusGraph.traversal().V().has(VERTEX_PROPERTY_UNIQ, vertexUniq).inE(LABEL_EDGE).toList();
+ if (null == edges || edges.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ Map result = new HashMap<>(edges.size());
+ for (Edge e : edges) {
+ GraphEdge graphEdge = transferToGraphEdge(e);
+ GraphVertex graphVertex = transferToGraphVertex(e.inVertex());
+ result.put(graphEdge, graphVertex);
+ }
+ return result;
+ }
+
+ @Override
+ public Map getTargetVertexEdgeMap(String vertexUniq) {
+ if (StringUtils.isBlank(vertexUniq)) {
+ return Collections.emptyMap();
+ }
+ List edges =
+ janusGraph.traversal().V().has(VERTEX_PROPERTY_UNIQ, vertexUniq).outE(LABEL_EDGE).toList();
+ if (null == edges || edges.size() == 0) {
+ return Collections.emptyMap();
+ }
+ Map result = new HashMap<>(edges.size());
+ for (Edge e : edges) {
+ GraphEdge graphEdge = transferToGraphEdge(e);
+ GraphVertex graphVertex = transferToGraphVertex(e.outVertex());
+ result.put(graphEdge, graphVertex);
+ }
+ return result;
+ }
+
+ private GraphLineage transferToGraphLineage(String vertexUniq, Graph graph) {
+ if (StringUtils.isBlank(vertexUniq) || null == graph) {
+ return null;
+ }
+ GraphVertex currentVertex = getVertex(vertexUniq);
+ GraphLineage graphLineage = new GraphLineage();
+ graphLineage.setCurrent(currentVertex);
+ graphLineage.setVertices(new ArrayList<>());
+ graphLineage.setEdges(new ArrayList<>());
+ Iterator vertexIterator = graph.vertices();
+ while (vertexIterator.hasNext()) {
+ Vertex v = vertexIterator.next();
+ graphLineage.getVertices().add(transferToGraphVertex(v));
+ }
+ Iterator edgeIterator = graph.edges();
+ while (edgeIterator.hasNext()) {
+ Edge e = edgeIterator.next();
+ graphLineage.getEdges().add(transferToGraphEdge(e));
+ }
+ return graphLineage;
+ }
+
+ @Override
+ public GraphLineage getImpact(String vertexUniq, Integer depth, boolean skipDeleted) {
+ if (StringUtils.isBlank(vertexUniq)) {
+ return null;
+ }
+ GraphTraversal graphTraversal =
+ janusGraph.traversal().V().has(VERTEX_PROPERTY_UNIQ, vertexUniq);
+ if (skipDeleted) {
+ graphTraversal = graphTraversal.has(VERTEX_PROPERTY_DELETED, false);
+ }
+ Graph graph;
+ if (depth <= 0) {
+ if (!skipDeleted) {
+ graph =
+ (Graph)
+ graphTraversal
+ .until(__.outE(LABEL_EDGE).count().is(0))
+ .repeat(__.outE(LABEL_EDGE).subgraph("subGraph").inV().simplePath())
+ .cap("subGraph")
+ .next();
+ } else {
+ graph =
+ (Graph)
+ graphTraversal
+ .until(
+ __.outE(LABEL_EDGE)
+ .or(
+ __.has(EDGE_PROPERTY_DELETED, true),
+ __.inV().has(VERTEX_PROPERTY_DELETED, true),
+ __.count().is(0)))
+ .repeat(__.outE(LABEL_EDGE).subgraph("subGraph").inV().simplePath())
+ .cap("subGraph")
+ .next();
+ }
+ } else {
+ if (!skipDeleted) {
+ graph =
+ (Graph)
+ graphTraversal
+ .repeat(__.outE(LABEL_EDGE).subgraph("subGraph").inV().simplePath())
+ .times(depth)
+ .cap("subGraph")
+ .next();
+ } else {
+ graph =
+ (Graph)
+ graphTraversal
+ .repeat(
+ __.outE(LABEL_EDGE)
+ .and(
+ __.has(EDGE_PROPERTY_DELETED, false),
+ __.inV().has(VERTEX_PROPERTY_DELETED, false))
+ .subgraph("subGraph")
+ .inV()
+ .simplePath())
+ .times(depth)
+ .cap("subGraph")
+ .next();
+ }
+ }
+ return transferToGraphLineage(vertexUniq, graph);
+ }
+
+ @Override
+ public GraphLineage getLineage(String vertexUniq, Integer depth, boolean skipDeleted) {
+ if (StringUtils.isBlank(vertexUniq)) {
+ return null;
+ }
+ GraphTraversal graphTraversal =
+ janusGraph.traversal().V().has(VERTEX_PROPERTY_UNIQ, vertexUniq);
+ if (skipDeleted) {
+ graphTraversal = graphTraversal.has(VERTEX_PROPERTY_DELETED, false);
+ }
+ Graph graph;
+ if (depth <= 0) {
+ if (!skipDeleted) {
+ graph =
+ (Graph)
+ graphTraversal
+ .until(__.inE(LABEL_EDGE).count().is(0))
+ .repeat(__.inE(LABEL_EDGE).subgraph("subGraph").outV().simplePath())
+ .cap("subGraph")
+ .next();
+ } else {
+ graph =
+ (Graph)
+ graphTraversal
+ .until(
+ __.inE(LABEL_EDGE)
+ .or(
+ __.has(EDGE_PROPERTY_DELETED, true),
+ __.outV().has(VERTEX_PROPERTY_DELETED, true),
+ __.count().is(0)))
+ .repeat(__.inE(LABEL_EDGE).subgraph("subGraph").outV().simplePath())
+ .cap("subGraph")
+ .next();
+ }
+ } else {
+ if (!skipDeleted) {
+ graph =
+ (Graph)
+ graphTraversal
+ .repeat(__.inE(LABEL_EDGE).subgraph("subGraph").outV().simplePath())
+ .times(depth)
+ .cap("subGraph")
+ .next();
+ } else {
+ graph =
+ (Graph)
+ graphTraversal
+ .repeat(
+ __.inE(LABEL_EDGE)
+ .and(
+ __.has(EDGE_PROPERTY_DELETED, false),
+ __.outV().has(VERTEX_PROPERTY_DELETED, false))
+ .subgraph("subGraph")
+ .outV()
+ .simplePath())
+ .times(depth)
+ .cap("subGraph")
+ .next();
+ }
+ }
+ return transferToGraphLineage(vertexUniq, graph);
+ }
+
+ @Override
+ public GraphLineage getFullLineage(String vertexUniq, Integer depth, boolean skipDeleted) {
+ if (StringUtils.isBlank(vertexUniq)) {
+ return null;
+ }
+ GraphTraversal graphTraversal =
+ janusGraph.traversal().V().has(VERTEX_PROPERTY_UNIQ, vertexUniq);
+ if (skipDeleted) {
+ graphTraversal = graphTraversal.has(VERTEX_PROPERTY_DELETED, false);
+ }
+ Graph graph;
+ if (depth <= 0) {
+ if (!skipDeleted) {
+ graph =
+ (Graph)
+ graphTraversal
+ .union(
+ __.until(__.outE(LABEL_EDGE).count().is(0))
+ .repeat(
+ (Traversal)
+ __.outE(LABEL_EDGE).subgraph("subGraph").inV().simplePath()),
+ __.until(__.inE(LABEL_EDGE).count().is(0))
+ .repeat(
+ (Traversal)
+ __.inE(LABEL_EDGE).subgraph("subGraph").outV().simplePath()))
+ .cap("subGraph")
+ .next();
+ } else {
+ graph =
+ (Graph)
+ graphTraversal
+ .union(
+ __.until(
+ __.outE(LABEL_EDGE)
+ .or(
+ __.has(EDGE_PROPERTY_DELETED, true),
+ __.inV().has(VERTEX_PROPERTY_DELETED, true),
+ __.count().is(0)))
+ .repeat(
+ (Traversal)
+ __.outE(LABEL_EDGE).subgraph("subGraph").inV().simplePath()),
+ __.until(
+ __.inE(LABEL_EDGE)
+ .or(
+ __.has(EDGE_PROPERTY_DELETED, true),
+ __.outV().has(VERTEX_PROPERTY_DELETED, true),
+ __.count().is(0)))
+ .repeat(
+ (Traversal)
+ __.inE(LABEL_EDGE).subgraph("subGraph").outV().simplePath()))
+ .cap("subGraph")
+ .next();
+ }
+ } else {
+ if (!skipDeleted) {
+ graph =
+ (Graph)
+ graphTraversal
+ .union(
+ __.repeat(__.outE(LABEL_EDGE).subgraph("subGraph").inV().simplePath())
+ .times(depth),
+ __.repeat(__.inE(LABEL_EDGE).subgraph("subGraph").outV().simplePath())
+ .times(depth))
+ .cap("subGraph")
+ .next();
+
+ } else {
+ graph =
+ (Graph)
+ graphTraversal
+ .union(
+ __.repeat(
+ __.outE(LABEL_EDGE)
+ .and(
+ __.has(EDGE_PROPERTY_DELETED, false),
+ __.inV().has(VERTEX_PROPERTY_DELETED, false))
+ .subgraph("subGraph")
+ .inV()
+ .simplePath())
+ .times(depth),
+ __.repeat(
+ __.inE(LABEL_EDGE)
+ .and(
+ __.has(EDGE_PROPERTY_DELETED, false),
+ __.outV().has(VERTEX_PROPERTY_DELETED, false))
+ .subgraph("subGraph")
+ .outV()
+ .simplePath())
+ .times(depth))
+ .cap("subGraph")
+ .next();
+ }
+ }
+ return transferToGraphLineage(vertexUniq, graph);
+ }
+}
diff --git a/graph-janusgraph/janusgraph-v0.2.0/src/test/java/org/studiox/graph/janusgraph/v020/JanusGraphV020Test.java b/graph-janusgraph/janusgraph-v0.2.0/src/test/java/org/studiox/graph/janusgraph/v020/JanusGraphV020Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..4d45a93c303ddbd18ed4f02451bc056caacdccf7
--- /dev/null
+++ b/graph-janusgraph/janusgraph-v0.2.0/src/test/java/org/studiox/graph/janusgraph/v020/JanusGraphV020Test.java
@@ -0,0 +1,14 @@
+package org.studiox.graph.janusgraph.v020;
+
+import org.junit.BeforeClass;
+import org.slf4j.LoggerFactory;
+import org.studiox.graph.common.exception.GraphException;
+import org.studiox.graph.janusgraph.common.test.JanusGraphTest;
+
+public class JanusGraphV020Test extends JanusGraphTest {
+
+ @BeforeClass
+ public static void init() throws GraphException {
+ init(new JanusGraphV020(LoggerFactory.getLogger(JanusGraphV020Test.class)));
+ }
+}
diff --git a/graph-janusgraph/janusgraph-v0.2.0/src/test/resources/graph.properties b/graph-janusgraph/janusgraph-v0.2.0/src/test/resources/graph.properties
new file mode 100755
index 0000000000000000000000000000000000000000..028881eac35990e8878e4f2500384c658aaa54f8
--- /dev/null
+++ b/graph-janusgraph/janusgraph-v0.2.0/src/test/resources/graph.properties
@@ -0,0 +1,27 @@
+###################################################################
+graph.schema.default=none
+graph.storage.batch-loading=true
+###################################################################
+graph.cache.db-cache=false
+graph.ids.block-size=20000000
+graph.ids.renew-timeout=3600000
+graph.storage.buffer-size=20240
+###################################################################
+graph.gremlin.graph=org.janusgraph.core.JanusGraphFactory
+###################################################################
+graph.storage.backend=inmemory
+###################################################################
+#graph.storage.backend=hbase
+#graph.storage.hostname=localhost
+#graph.storage.hbase.table=graph_table_1
+#graph.storage.hbase.ext.zookeeper.znode.parent=/hbase1
+###################################################################
+#graph.storage.hbase.region-count=9
+#graph.storage.hbase.regions-per-server=3
+#graph.storage.hbase.ext.hbase.rpc.timeout=300000
+#graph.storage.hbase.ext.hbase.client.operation.timeout=300000
+#graph.storage.hbase.ext.hbase.client.scanner.timeout.period=300000
+###################################################################
+#graph.index.search.backend=elasticsearch
+#graph.index.search.hostname=localhost:9200
+###################################################################
diff --git a/graph-janusgraph/pom.xml b/graph-janusgraph/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0f4f371c59ab943c36914699be9dc22f631baa10
--- /dev/null
+++ b/graph-janusgraph/pom.xml
@@ -0,0 +1,20 @@
+
+
+ 4.0.0
+
+ org.studiox
+ graph
+ 1.0.5-SNAPSHOT
+
+ org.studiox.graph
+ graph-janusgraph
+ 1.0.5-SNAPSHOT
+ pom
+
+ janusgraph-common
+ janusgraph-v0.2.0
+ janusgraph-latest
+
+
diff --git a/graph-nebulagraph/pom.xml b/graph-nebulagraph/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..19d9431efda6efc188774d9db0feef1c71d8931c
--- /dev/null
+++ b/graph-nebulagraph/pom.xml
@@ -0,0 +1,16 @@
+
+
+ 4.0.0
+
+ org.studiox
+ graph
+ 1.0.5-SNAPSHOT
+
+ org.studiox.graph
+ graph-nebulagraph
+ 1.0.5-SNAPSHOT
+ pom
+
+
diff --git a/graph-neo4j/pom.xml b/graph-neo4j/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3e54be8d09d6fca620d2c8294bfd2647e2897ef6
--- /dev/null
+++ b/graph-neo4j/pom.xml
@@ -0,0 +1,16 @@
+
+
+ 4.0.0
+
+ org.studiox
+ graph
+ 1.0.5-SNAPSHOT
+
+ org.studiox.graph
+ graph-neo4j
+ 1.0.5-SNAPSHOT
+ pom
+
+
diff --git a/graph-persistence/persistence-model/pom.xml b/graph-persistence/persistence-model/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..15222b886d3a592c22bb8ccdaecc04c35383553f
--- /dev/null
+++ b/graph-persistence/persistence-model/pom.xml
@@ -0,0 +1,17 @@
+
+
+ 4.0.0
+
+ org.studiox.graph
+ graph-persistence
+ 1.0.5-SNAPSHOT
+
+ org.studiox.graph.persistence
+ persistence-model
+ 1.0.5-SNAPSHOT
+ jar
+
+
+
diff --git a/graph-persistence/persistence-model/src/main/java/org/studiox/graph/persistence/model/AbstractGraphDO.java b/graph-persistence/persistence-model/src/main/java/org/studiox/graph/persistence/model/AbstractGraphDO.java
new file mode 100644
index 0000000000000000000000000000000000000000..43df431691333ec79479a84bf58cf789e6dba454
--- /dev/null
+++ b/graph-persistence/persistence-model/src/main/java/org/studiox/graph/persistence/model/AbstractGraphDO.java
@@ -0,0 +1,67 @@
+package org.studiox.graph.persistence.model;
+
+import java.io.Serializable;
+import java.sql.Timestamp;
+
+public abstract class AbstractGraphDO implements Serializable {
+
+ protected Long id;
+
+ protected String type;
+
+ protected String owner;
+
+ protected Boolean deleted;
+
+ protected Timestamp createTime;
+
+ protected Timestamp updateTime;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getOwner() {
+ return owner;
+ }
+
+ public void setOwner(String owner) {
+ this.owner = owner;
+ }
+
+ public Boolean getDeleted() {
+ return deleted;
+ }
+
+ public void setDeleted(Boolean deleted) {
+ this.deleted = deleted;
+ }
+
+ public Timestamp getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(Timestamp createTime) {
+ this.createTime = createTime;
+ }
+
+ public Timestamp getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(Timestamp updateTime) {
+ this.updateTime = updateTime;
+ }
+}
diff --git a/graph-persistence/persistence-model/src/main/java/org/studiox/graph/persistence/model/GraphEdgeDO.java b/graph-persistence/persistence-model/src/main/java/org/studiox/graph/persistence/model/GraphEdgeDO.java
new file mode 100644
index 0000000000000000000000000000000000000000..d8496fe189c6698ac3631936caed3c106d7ba5a6
--- /dev/null
+++ b/graph-persistence/persistence-model/src/main/java/org/studiox/graph/persistence/model/GraphEdgeDO.java
@@ -0,0 +1,136 @@
+package org.studiox.graph.persistence.model;
+
+import java.io.Serializable;
+
+public class GraphEdgeDO extends AbstractGraphDO implements Serializable {
+
+ private String content;
+
+ private String contentMd5;
+
+ private String sourceVertexUniq;
+
+ private String targetVertexUniq;
+
+ private String janusEdgeId;
+
+ private Long neo4jEdgeId;
+
+ private String nebulaEdgeId;
+
+ private Long sourceJanusVertexId;
+
+ private Long targetJanusVertexId;
+
+ private Long sourceNeo4jVertexId;
+
+ private Long targetNeo4jVertexId;
+
+ private Long sourceNebulaVertexId;
+
+ private Long targetNebulaVertexId;
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getContentMd5() {
+ return contentMd5;
+ }
+
+ public void setContentMd5(String contentMd5) {
+ this.contentMd5 = contentMd5;
+ }
+
+ public String getSourceVertexUniq() {
+ return sourceVertexUniq;
+ }
+
+ public void setSourceVertexUniq(String sourceVertexUniq) {
+ this.sourceVertexUniq = sourceVertexUniq;
+ }
+
+ public String getTargetVertexUniq() {
+ return targetVertexUniq;
+ }
+
+ public void setTargetVertexUniq(String targetVertexUniq) {
+ this.targetVertexUniq = targetVertexUniq;
+ }
+
+ public String getJanusEdgeId() {
+ return janusEdgeId;
+ }
+
+ public void setJanusEdgeId(String janusEdgeId) {
+ this.janusEdgeId = janusEdgeId;
+ }
+
+ public Long getNeo4jEdgeId() {
+ return neo4jEdgeId;
+ }
+
+ public void setNeo4jEdgeId(Long neo4jEdgeId) {
+ this.neo4jEdgeId = neo4jEdgeId;
+ }
+
+ public String getNebulaEdgeId() {
+ return nebulaEdgeId;
+ }
+
+ public void setNebulaEdgeId(String nebulaEdgeId) {
+ this.nebulaEdgeId = nebulaEdgeId;
+ }
+
+ public Long getSourceJanusVertexId() {
+ return sourceJanusVertexId;
+ }
+
+ public void setSourceJanusVertexId(Long sourceJanusVertexId) {
+ this.sourceJanusVertexId = sourceJanusVertexId;
+ }
+
+ public Long getTargetJanusVertexId() {
+ return targetJanusVertexId;
+ }
+
+ public void setTargetJanusVertexId(Long targetJanusVertexId) {
+ this.targetJanusVertexId = targetJanusVertexId;
+ }
+
+ public Long getSourceNeo4jVertexId() {
+ return sourceNeo4jVertexId;
+ }
+
+ public void setSourceNeo4jVertexId(Long sourceNeo4jVertexId) {
+ this.sourceNeo4jVertexId = sourceNeo4jVertexId;
+ }
+
+ public Long getTargetNeo4jVertexId() {
+ return targetNeo4jVertexId;
+ }
+
+ public void setTargetNeo4jVertexId(Long targetNeo4jVertexId) {
+ this.targetNeo4jVertexId = targetNeo4jVertexId;
+ }
+
+ public Long getSourceNebulaVertexId() {
+ return sourceNebulaVertexId;
+ }
+
+ public void setSourceNebulaVertexId(Long sourceNebulaVertexId) {
+ this.sourceNebulaVertexId = sourceNebulaVertexId;
+ }
+
+ public Long getTargetNebulaVertexId() {
+ return targetNebulaVertexId;
+ }
+
+ public void setTargetNebulaVertexId(Long targetNebulaVertexId) {
+ this.targetNebulaVertexId = targetNebulaVertexId;
+ }
+}
diff --git a/graph-persistence/persistence-model/src/main/java/org/studiox/graph/persistence/model/GraphVertexDO.java b/graph-persistence/persistence-model/src/main/java/org/studiox/graph/persistence/model/GraphVertexDO.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ab9f2e842d9038c37dee00030a133eabd588a1f
--- /dev/null
+++ b/graph-persistence/persistence-model/src/main/java/org/studiox/graph/persistence/model/GraphVertexDO.java
@@ -0,0 +1,56 @@
+package org.studiox.graph.persistence.model;
+
+import java.io.Serializable;
+
+public class GraphVertexDO extends AbstractGraphDO implements Serializable {
+
+ private String uniq;
+
+ private Long janusVertexId;
+
+ private Long neo4jVertexId;
+
+ private Long nebulaVertexId;
+
+ protected Boolean temp;
+
+ public String getUniq() {
+ return uniq;
+ }
+
+ public void setUniq(String uniq) {
+ this.uniq = uniq;
+ }
+
+ public Long getJanusVertexId() {
+ return janusVertexId;
+ }
+
+ public void setJanusVertexId(Long janusVertexId) {
+ this.janusVertexId = janusVertexId;
+ }
+
+ public Long getNeo4jVertexId() {
+ return neo4jVertexId;
+ }
+
+ public void setNeo4jVertexId(Long neo4jVertexId) {
+ this.neo4jVertexId = neo4jVertexId;
+ }
+
+ public Long getNebulaVertexId() {
+ return nebulaVertexId;
+ }
+
+ public void setNebulaVertexId(Long nebulaVertexId) {
+ this.nebulaVertexId = nebulaVertexId;
+ }
+
+ public Boolean getTemp() {
+ return temp;
+ }
+
+ public void setTemp(Boolean temp) {
+ this.temp = temp;
+ }
+}
diff --git a/graph-persistence/persistence-mybatis-plus/pom.xml b/graph-persistence/persistence-mybatis-plus/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..902181a596ebe946641d7ec90b84dc54fda71eb6
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-plus/pom.xml
@@ -0,0 +1,52 @@
+
+
+ 4.0.0
+
+ org.studiox.graph
+ graph-persistence
+ 1.0.5-SNAPSHOT
+
+ org.studiox.graph.persistence
+ persistence-mybatis-plus
+ 1.0.5-SNAPSHOT
+ jar
+
+
+ junit
+ junit
+ test
+
+
+ com.h2database
+ h2
+ test
+
+
+ mysql
+ mysql-connector-java
+ test
+
+
+ org.studiox.graph.persistence
+ persistence-model
+
+
+ com.baomidou
+ mybatis-plus
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+
+
+
+
+
+ pl.project13.maven
+ git-commit-id-plugin
+
+
+
+
diff --git a/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/dao/GraphEdgeDao.java b/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/dao/GraphEdgeDao.java
new file mode 100644
index 0000000000000000000000000000000000000000..3aca336b7398f30fa410a0de6fb49b22fcc3cd38
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/dao/GraphEdgeDao.java
@@ -0,0 +1,5 @@
+package org.studiox.graph.persistence.mybatis.plus.dao;
+
+import org.studiox.graph.persistence.mybatis.plus.model.GraphEdgeDO;
+
+public interface GraphEdgeDao extends MybatisPlusDao {}
diff --git a/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/dao/GraphVertexDao.java b/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/dao/GraphVertexDao.java
new file mode 100644
index 0000000000000000000000000000000000000000..42548075475c2a15c882138e38aa154b03917ce7
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/dao/GraphVertexDao.java
@@ -0,0 +1,5 @@
+package org.studiox.graph.persistence.mybatis.plus.dao;
+
+import org.studiox.graph.persistence.mybatis.plus.model.GraphVertexDO;
+
+public interface GraphVertexDao extends MybatisPlusDao {}
diff --git a/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/dao/MybatisPlusDao.java b/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/dao/MybatisPlusDao.java
new file mode 100644
index 0000000000000000000000000000000000000000..af605755f16a42432295922d6e76e9a87a0ec547
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/dao/MybatisPlusDao.java
@@ -0,0 +1,5 @@
+package org.studiox.graph.persistence.mybatis.plus.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+public interface MybatisPlusDao extends BaseMapper {}
diff --git a/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/model/GraphEdgeDO.java b/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/model/GraphEdgeDO.java
new file mode 100644
index 0000000000000000000000000000000000000000..e56de5f04098cc5996ccd33dc0173c9219c4a2c3
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/model/GraphEdgeDO.java
@@ -0,0 +1,22 @@
+package org.studiox.graph.persistence.mybatis.plus.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+@TableName("graph_edge")
+public class GraphEdgeDO extends org.studiox.graph.persistence.model.GraphEdgeDO {
+
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @Override
+ public Long getId() {
+ return id;
+ }
+
+ @Override
+ public void setId(Long id) {
+ this.id = id;
+ }
+}
diff --git a/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/model/GraphVertexDO.java b/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/model/GraphVertexDO.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f4914bd179c2a2fa70941ff295ee31c8a7f467b
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-plus/src/main/java/org/studiox/graph/persistence/mybatis/plus/model/GraphVertexDO.java
@@ -0,0 +1,22 @@
+package org.studiox.graph.persistence.mybatis.plus.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+@TableName("graph_vertex")
+public class GraphVertexDO extends org.studiox.graph.persistence.model.GraphVertexDO {
+
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @Override
+ public Long getId() {
+ return id;
+ }
+
+ @Override
+ public void setId(Long id) {
+ this.id = id;
+ }
+}
diff --git a/graph-persistence/persistence-mybatis-plus/src/test/java/org/studiox/graph/persistence/mybatis/plus/test/MybatisPlusTest.java b/graph-persistence/persistence-mybatis-plus/src/test/java/org/studiox/graph/persistence/mybatis/plus/test/MybatisPlusTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ceba2cf732622deb73c40a2587d2d2d3385eac1
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-plus/src/test/java/org/studiox/graph/persistence/mybatis/plus/test/MybatisPlusTest.java
@@ -0,0 +1,138 @@
+package org.studiox.graph.persistence.mybatis.plus.test;
+
+import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
+import org.apache.ibatis.io.Resources;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.junit.*;
+import org.junit.runners.MethodSorters;
+import org.studiox.graph.persistence.mybatis.plus.dao.GraphEdgeDao;
+import org.studiox.graph.persistence.mybatis.plus.dao.GraphVertexDao;
+import org.studiox.graph.persistence.mybatis.plus.model.GraphEdgeDO;
+import org.studiox.graph.persistence.mybatis.plus.model.GraphVertexDO;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class MybatisPlusTest {
+
+ private static SqlSession session = null;
+
+ private static GraphVertexDao graphVertexDao;
+
+ private static GraphEdgeDao graphEdgeDao;
+
+ @BeforeClass
+ public static void init() {
+ InputStream inputStream = null;
+ try {
+ inputStream = Resources.getResourceAsStream("mybatis-config.xml");
+ SqlSessionFactory factory = new MybatisSqlSessionFactoryBuilder().build(inputStream);
+ session = factory.openSession();
+ graphVertexDao = session.getMapper(GraphVertexDao.class);
+ graphEdgeDao = session.getMapper(GraphEdgeDao.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (null != inputStream) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ @AfterClass
+ public static void clean() {
+ if (null != session) {
+ session.commit();
+ session.close();
+ }
+ }
+
+ @Test
+ public void test1() {
+ List graphVertexDOs = graphVertexDao.selectList(null);
+ if (null != graphVertexDOs && graphVertexDOs.size() > 0) {
+ for (GraphVertexDO graphVertexDO : graphVertexDOs) {
+ graphVertexDao.deleteById(graphVertexDO.getId());
+ }
+ }
+ session.commit();
+ }
+
+ @Test
+ public void test2() {
+ GraphVertexDO graphVertexDO1 = new GraphVertexDO();
+ graphVertexDO1.setUniq("uniq1");
+ graphVertexDO1.setType("type1");
+ graphVertexDO1.setOwner("owner1");
+ graphVertexDO1.setJanusVertexId(1L);
+ graphVertexDO1.setTemp(true);
+ graphVertexDO1.setDeleted(false);
+ graphVertexDao.insert(graphVertexDO1);
+
+ session.commit();
+
+ long count = graphVertexDao.selectCount(null);
+ Assert.assertEquals(1L, count);
+
+ List graphVertexDOs = graphVertexDao.selectList(null);
+ GraphVertexDO graphVertexDO2 = graphVertexDOs.get(0);
+ Long id = graphVertexDO2.getId();
+ graphVertexDO2.setUniq("uniq2");
+ graphVertexDao.updateById(graphVertexDO2);
+
+ session.commit();
+
+ GraphVertexDO graphVertexDO3 = graphVertexDao.selectById(id);
+ Assert.assertEquals("uniq2", graphVertexDO3.getUniq());
+ Assert.assertEquals(true, graphVertexDO3.getTemp());
+ Assert.assertEquals(false, graphVertexDO3.getDeleted());
+ }
+
+ @Test
+ public void test3() {
+ List graphEdgeDOs = graphEdgeDao.selectList(null);
+ if (null != graphEdgeDOs && graphEdgeDOs.size() > 0) {
+ for (GraphEdgeDO graphEdgeDO : graphEdgeDOs) {
+ graphEdgeDao.deleteById(graphEdgeDO.getId());
+ }
+ }
+ session.commit();
+ }
+
+ @Test
+ public void test4() {
+ GraphEdgeDO graphEdgeDO1 = new GraphEdgeDO();
+ graphEdgeDO1.setContent("select * from sys.version");
+ graphEdgeDO1.setType("typq1");
+ graphEdgeDO1.setOwner("owner1");
+ graphEdgeDO1.setSourceVertexUniq("uniq1");
+ graphEdgeDO1.setTargetVertexUniq("uniq2");
+ graphEdgeDO1.setJanusEdgeId("edge1");
+ graphEdgeDO1.setSourceJanusVertexId(1L);
+ graphEdgeDO1.setTargetJanusVertexId(1L);
+ graphEdgeDao.insert(graphEdgeDO1);
+
+ session.commit();
+
+ long count = graphEdgeDao.selectCount(null);
+ Assert.assertEquals(1, count);
+
+ List graphEdgeDOs = graphEdgeDao.selectList(null);
+ GraphEdgeDO graphEdgeDO2 = graphEdgeDOs.get(0);
+ Long id = graphEdgeDO2.getId();
+ graphEdgeDO2.setContent("select 1 from sys.version");
+ graphEdgeDao.updateById(graphEdgeDO2);
+
+ session.commit();
+
+ GraphEdgeDO graphEdgeDO3 = graphEdgeDao.selectById(id);
+ Assert.assertEquals("select 1 from sys.version", graphEdgeDO3.getContent());
+ }
+}
diff --git a/graph-persistence/persistence-mybatis-plus/src/test/resources/jdbc.properties b/graph-persistence/persistence-mybatis-plus/src/test/resources/jdbc.properties
new file mode 100644
index 0000000000000000000000000000000000000000..189dc13ead46c8f3eaa740157b8a9834d4f1ca2d
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-plus/src/test/resources/jdbc.properties
@@ -0,0 +1,13 @@
+# H2 Database
+#####################################
+jdbc.driver=org.h2.Driver
+jdbc.url=jdbc:h2:mem:test;MODE=MYSQL;DATABASE_TO_LOWER=FALSE;CASE_INSENSITIVE_IDENTIFIERS=TRUE;INIT=RUNSCRIPT FROM 'classpath:/mysql_ddl.sql'
+jdbc.username=root
+jdbc.password=123456
+#####################################
+# MySQL Database
+#jdbc.driver=com.mysql.jdbc.Driver
+#jdbc.url=jdbc:mysql://localhost:13306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
+#jdbc.username=root
+#jdbc.password=123456
+#####################################
diff --git a/graph-persistence/persistence-mybatis-plus/src/test/resources/mybatis-config.xml b/graph-persistence/persistence-mybatis-plus/src/test/resources/mybatis-config.xml
new file mode 100644
index 0000000000000000000000000000000000000000..60d1bee15f69280afa4e520d212807e67e35c7d8
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-plus/src/test/resources/mybatis-config.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/graph-persistence/persistence-mybatis-plus/src/test/resources/mysql_ddl.sql b/graph-persistence/persistence-mybatis-plus/src/test/resources/mysql_ddl.sql
new file mode 100644
index 0000000000000000000000000000000000000000..48cc95eeb62d757e9fe145bcf22fb758fd4eb86c
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-plus/src/test/resources/mysql_ddl.sql
@@ -0,0 +1,53 @@
+create table if not exists `graph_vertex` (
+ `id` bigint(20) unsigned not null auto_increment comment '主键',
+ `uniq` varchar(255) not null default '' comment '顶点的唯一标识',
+ `type` varchar(20) not null default '' comment '顶点的类型',
+ `owner` varchar(50) not null default '' comment '所有者',
+ `janus_vertex_id` bigint(20) not null default 0 comment '顶点存储 JanusGraph Vertex Id',
+ `neo4j_vertex_id` bigint(20) not null default 0 comment '顶点存储 Neo4j Vertex Id',
+ `nebula_vertex_id` bigint(20) not null default 0 comment '顶点存储 NebulaGraph Vertex Id',
+ `temp` tinyint(1) not null default 0 comment '是否临时点(0:否 1:是),只存在数据库,不存在图中',
+ `deleted` tinyint(1) not null default 0 comment '是否删除(0:否 1:是)',
+ `create_time` timestamp not null default current_timestamp comment '顶点的创建时间',
+ `update_time` timestamp not null default current_timestamp comment '顶点的修改时间',
+ primary key (`id`),
+ unique key (`uniq`),
+ index (`janus_vertex_id`),
+ index (`neo4j_vertex_id`),
+ index (`nebula_vertex_id`)
+) engine=innodb auto_increment=1 default charset=utf8 comment='图中顶点集合';
+
+create table if not exists `graph_edge` (
+ `id` bigint(20) unsigned not null auto_increment comment '主键',
+ `content` mediumtext not null comment '边的记录内容',
+ `content_md5` char(32) not null default '' comment '边的记录内容MD5值',
+ `type` varchar(20) not null default '' comment '边的类型',
+ `owner` varchar(50) not null default '' comment '所有者',
+ `source_vertex_uniq` varchar(255) not null default '' comment '边的输入顶点的唯一标识',
+ `target_vertex_uniq` varchar(255) not null default '' comment '边的输出顶点的唯一标识',
+ `janus_edge_id` varchar(50) not null default '' comment '边存储 JanusGraph Edge Id',
+ `neo4j_edge_id` bigint(20) not null default 0 comment '边存储 Neo4j Edge Id',
+ `nebula_edge_id` varchar(50) not null default '' comment '边存储 NebulaGraph Edge Id',
+ `source_janus_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 JanusGraph Vertex Id',
+ `target_janus_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 JanusGraph Vertex Id',
+ `source_neo4j_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 Neo4j Vertex Id',
+ `target_neo4j_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 Neo4j Vertex Id',
+ `source_nebula_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 NebulaGraph Vertex Id',
+ `target_nebula_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 NebulaGraph Vertex Id',
+ `deleted` tinyint(1) not null default 0 comment '是否删除(0:否 1:是)',
+ `create_time` timestamp not null default current_timestamp comment '边的创建时间',
+ `update_time` timestamp not null default current_timestamp comment '边的修改时间',
+ primary key (`id`),
+ index (`content_md5`),
+ index (`source_vertex_uniq`),
+ index (`target_vertex_uniq`),
+ index (`janus_edge_id`),
+ index (`neo4j_edge_id`),
+ index (`nebula_edge_id`),
+ index (`source_janus_vertex_id`),
+ index (`target_janus_vertex_id`),
+ index (`source_neo4j_vertex_id`),
+ index (`target_neo4j_vertex_id`),
+ index (`source_nebula_vertex_id`),
+ index (`target_nebula_vertex_id`)
+) engine=innodb auto_increment=1 default charset=utf8 comment='图中边集合';
diff --git a/graph-persistence/persistence-mybatis-tk/pom.xml b/graph-persistence/persistence-mybatis-tk/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7debc36bcd1f36a6ec7be04fb327cbe6f03b64a7
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/pom.xml
@@ -0,0 +1,52 @@
+
+
+ 4.0.0
+
+ org.studiox.graph
+ graph-persistence
+ 1.0.5-SNAPSHOT
+
+ org.studiox.graph.persistence
+ persistence-mybatis-tk
+ 1.0.5-SNAPSHOT
+ jar
+
+ 2.4.11
+ 5.3.10
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ ch.vorburger.mariaDB4j
+ mariaDB4j
+ test
+
+
+ mysql
+ mysql-connector-java
+ test
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+
+
+ tk.mybatis
+ mapper-spring-boot-starter
+
+
+
+
+
+ pl.project13.maven
+ git-commit-id-plugin
+
+
+
+
diff --git a/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/TkMybatisSpring.java b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/TkMybatisSpring.java
new file mode 100644
index 0000000000000000000000000000000000000000..dff0130388018ee126b0c8a31e976086832b4e85
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/TkMybatisSpring.java
@@ -0,0 +1,22 @@
+package org.studiox.graph.persistence.mybatis.tk;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+import tk.mybatis.spring.annotation.MapperScan;
+
+@SpringBootApplication
+@MapperScan(basePackages = {"org.studiox.graph.persistence.mybatis.tk.mapper"})
+@ComponentScan(
+ basePackages = {
+ "org.studiox.graph.persistence.mybatis.tk.base",
+ "org.studiox.graph.persistence.mybatis.tk.domain",
+ "org.studiox.graph.persistence.mybatis.tk.dao",
+ "org.studiox.graph.persistence.mybatis.tk.service"
+ })
+public class TkMybatisSpring {
+
+ public static void main(String[] args) {
+ SpringApplication.run(TkMybatisSpring.class, args);
+ }
+}
diff --git a/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/base/BaseGraphDO.java b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/base/BaseGraphDO.java
new file mode 100644
index 0000000000000000000000000000000000000000..c568bebec44323d37261a4c2accec64bb1e20bac
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/base/BaseGraphDO.java
@@ -0,0 +1,97 @@
+package org.studiox.graph.persistence.mybatis.tk.base;
+
+import tk.mybatis.mapper.annotation.KeySql;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+import java.sql.Timestamp;
+import java.util.Objects;
+
+public abstract class BaseGraphDO {
+
+ @Id
+ @Column(name = "id")
+ @KeySql(useGeneratedKeys = true)
+ private Long id;
+
+ @Column(name = "type")
+ private String type;
+
+ @Column(name = "owner")
+ private String owner;
+
+ @Column(name = "deleted")
+ private Boolean deleted;
+
+ @Column(name = "create_time")
+ private Timestamp createTime;
+
+ @Column(name = "update_time")
+ private Timestamp updateTime;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getOwner() {
+ return owner;
+ }
+
+ public void setOwner(String owner) {
+ this.owner = owner;
+ }
+
+ public Boolean getDeleted() {
+ return deleted;
+ }
+
+ public void setDeleted(Boolean deleted) {
+ this.deleted = deleted;
+ }
+
+ public Timestamp getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(Timestamp createTime) {
+ this.createTime = createTime;
+ }
+
+ public Timestamp getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(Timestamp updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ BaseGraphDO that = (BaseGraphDO) o;
+ return Objects.equals(id, that.id)
+ && Objects.equals(type, that.type)
+ && Objects.equals(owner, that.owner)
+ && Objects.equals(deleted, that.deleted)
+ && Objects.equals(createTime, that.createTime)
+ && Objects.equals(updateTime, that.updateTime);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, type, owner, deleted, createTime, updateTime);
+ }
+}
diff --git a/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/base/BaseGraphDao.java b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/base/BaseGraphDao.java
new file mode 100644
index 0000000000000000000000000000000000000000..e0c44a3353303872f209cf4f92a441eb4527c0fa
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/base/BaseGraphDao.java
@@ -0,0 +1,64 @@
+package org.studiox.graph.persistence.mybatis.tk.base;
+
+import java.util.List;
+
+public abstract class BaseGraphDao {
+
+ protected BaseGraphMapper mapper;
+
+ public List select(T obj) {
+ return mapper.select(obj);
+ }
+
+ public T selectOne(T obj) {
+ return mapper.selectOne(obj);
+ }
+
+ public T selectByPrimaryKey(Long id) {
+ return mapper.selectByPrimaryKey(id);
+ }
+
+ public List selectAll() {
+ return mapper.selectAll();
+ }
+
+ public int selectCount(T obj) {
+ return mapper.selectCount(obj);
+ }
+
+ public boolean existsWithPrimaryKey(Long id) {
+ return mapper.existsWithPrimaryKey(id);
+ }
+
+ public int insert(T obj) {
+ return mapper.insert(obj);
+ }
+
+ public int insertSelective(T obj) {
+ return mapper.insertSelective(obj);
+ }
+
+ public int insertUseGeneratedKeys(T obj) {
+ return mapper.insertUseGeneratedKeys(obj);
+ }
+
+ public int insertList(List objs) {
+ return mapper.insertList(objs);
+ }
+
+ public int updateByPrimaryKey(T obj) {
+ return mapper.updateByPrimaryKey(obj);
+ }
+
+ public int updateByPrimaryKeySelective(T obj) {
+ return mapper.updateByPrimaryKeySelective(obj);
+ }
+
+ public int delete(T obj) {
+ return mapper.delete(obj);
+ }
+
+ public int deleteByPrimaryKey(Long id) {
+ return mapper.deleteByPrimaryKey(id);
+ }
+}
diff --git a/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/base/BaseGraphMapper.java b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/base/BaseGraphMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc5d89f41c2b0a2e59dd4cbcf5da5d2adb2f8732
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/base/BaseGraphMapper.java
@@ -0,0 +1,6 @@
+package org.studiox.graph.persistence.mybatis.tk.base;
+
+import tk.mybatis.mapper.common.BaseMapper;
+import tk.mybatis.mapper.common.MySqlMapper;
+
+public interface BaseGraphMapper extends BaseMapper, MySqlMapper {}
diff --git a/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/dao/GraphEdgeDao.java b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/dao/GraphEdgeDao.java
new file mode 100644
index 0000000000000000000000000000000000000000..2943f2ee028cdd2cb8cae538175ef8b0d6713542
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/dao/GraphEdgeDao.java
@@ -0,0 +1,160 @@
+package org.studiox.graph.persistence.mybatis.tk.dao;
+
+import org.springframework.stereotype.Repository;
+import org.studiox.graph.persistence.mybatis.tk.base.BaseGraphDao;
+import org.studiox.graph.persistence.mybatis.tk.domain.GraphEdgeDO;
+import org.studiox.graph.persistence.mybatis.tk.mapper.GraphEdgeMapper;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.List;
+
+@Repository
+public class GraphEdgeDao extends BaseGraphDao {
+
+ @Resource private GraphEdgeMapper graphEdgeMapper;
+
+ @PostConstruct
+ private void init() {
+ mapper = graphEdgeMapper;
+ }
+
+ public Integer getGraphEdgeSize() {
+ return graphEdgeMapper.selectCount(null);
+ }
+
+ public List getGraphEdgeIds() {
+ return graphEdgeMapper.getGraphEdgeIds();
+ }
+
+ public List getGraphUniqueMinEdgeIds() {
+ return graphEdgeMapper.getGraphUniqueMinEdgeIds();
+ }
+
+ public List getGraphUniqueMaxEdgeIds() {
+ return graphEdgeMapper.getGraphUniqueMaxEdgeIds();
+ }
+
+ public Long getGraphEdgeContentSize(String sourceVertexUniq, String targetVertexUniq) {
+ return graphEdgeMapper.getGraphEdgeContentSize(sourceVertexUniq, targetVertexUniq);
+ }
+
+ public List getGraphEdgeContents(String sourceVertexUniq, String targetVertexUniq) {
+ return graphEdgeMapper.getGraphEdgeContents(sourceVertexUniq, targetVertexUniq);
+ }
+
+ public List getGraphEdgeDOs(GraphEdgeDO graphEdgeDO) {
+ return graphEdgeMapper.select(graphEdgeDO);
+ }
+
+ public GraphEdgeDO getOneGraphEdgeDoBySourceTargetUniq(
+ String sourceVertexUniq, String targetVertexUniq) {
+ return graphEdgeMapper.getOneGraphEdgeDoBySourceTargetUniq(sourceVertexUniq, targetVertexUniq);
+ }
+
+ public Long getGraphEdgeId(String content, String sourceVertexUniq, String targetVertexUniq) {
+ return graphEdgeMapper.getGraphEdgeId(content, sourceVertexUniq, targetVertexUniq);
+ }
+
+ public void updateGraphEdgeContentMd5(Long id) {
+ graphEdgeMapper.updateGraphEdgeContentMd5(id);
+ }
+
+ public void updateAllGraphEdgeContentMd5() {
+ graphEdgeMapper.updateAllGraphEdgeContentMd5();
+ }
+
+ public void updateJanusEdgeId(Long id, String janusEdgeId) {
+ graphEdgeMapper.updateJanusEdgeId(id, janusEdgeId);
+ }
+
+ public void updateJanusEdgeIdAndSourceTargetVertexId(
+ Long id, String janusEdgeId, Long sourceJanusVertexId, Long targetJanusVertexId) {
+ graphEdgeMapper.updateJanusEdgeIdAndSourceTargetVertexId(
+ id, janusEdgeId, sourceJanusVertexId, targetJanusVertexId);
+ }
+
+ public void updateNeo4jEdgeId(Long id, Long neo4jEdgeId) {
+ graphEdgeMapper.updateNeo4jEdgeId(id, neo4jEdgeId);
+ }
+
+ public void updateNeo4jEdgeIdAndSourceTargetVertexId(
+ Long id, Long neo4jEdgeId, Long sourceNeo4jVertexId, Long targetNeo4jVertexId) {
+ graphEdgeMapper.updateNeo4jEdgeIdAndSourceTargetVertexId(
+ id, neo4jEdgeId, sourceNeo4jVertexId, targetNeo4jVertexId);
+ }
+
+ public void updateNebulaEdgeId(Long id, String nebulaEdgeId) {
+ graphEdgeMapper.updateNebulaEdgeId(id, nebulaEdgeId);
+ }
+
+ public void updateNebulaEdgeIdAndSourceTargetVertexId(
+ Long id, String nebulaEdgeId, Long sourceNebulaVertexId, Long targetNebulaVertexId) {
+ graphEdgeMapper.updateNebulaEdgeIdAndSourceTargetVertexId(
+ id, nebulaEdgeId, sourceNebulaVertexId, targetNebulaVertexId);
+ }
+
+ public void updateSourceJanusVertexId(String sourceVertexUniq, Long sourceJanusVertexId) {
+ graphEdgeMapper.updateSourceJanusVertexId(sourceVertexUniq, sourceJanusVertexId);
+ }
+
+ public void updateTargetJanusVertexId(String sourceVertexUniq, Long targetJanusVertexId) {
+ graphEdgeMapper.updateTargetJanusVertexId(sourceVertexUniq, targetJanusVertexId);
+ }
+
+ public void updateAllSourceJanusVertexId() {
+ graphEdgeMapper.updateAllSourceJanusVertexId();
+ }
+
+ public void updateAllTargetJanusVertexId() {
+ graphEdgeMapper.updateAllTargetJanusVertexId();
+ }
+
+ public void updateAllSourceTargetJanusVertexId() {
+ graphEdgeMapper.updateAllSourceTargetJanusVertexId();
+ }
+
+ public void updateSourceNeo4jVertexId(String sourceVertexUniq, Long sourceNeo4jVertexId) {
+ graphEdgeMapper.updateSourceNeo4jVertexId(sourceVertexUniq, sourceNeo4jVertexId);
+ }
+
+ public void updateTargetNeo4jVertexId(String sourceVertexUniq, Long targetNeo4jVertexId) {
+ graphEdgeMapper.updateTargetNeo4jVertexId(sourceVertexUniq, targetNeo4jVertexId);
+ }
+
+ public void updateAllSourceNeo4jVertexId() {
+ graphEdgeMapper.updateAllSourceNeo4jVertexId();
+ }
+
+ public void updateAllTargetNeo4jVertexId() {
+ graphEdgeMapper.updateAllTargetNeo4jVertexId();
+ }
+
+ public void updateAllSourceTargetNeo4jVertexId() {
+ graphEdgeMapper.updateAllSourceTargetNeo4jVertexId();
+ }
+
+ public void updateSourceNebulaVertexId(String sourceVertexUniq, Long sourceNebulaVertexId) {
+ graphEdgeMapper.updateSourceNebulaVertexId(sourceVertexUniq, sourceNebulaVertexId);
+ }
+
+ public void updateTargetNebulaVertexId(String sourceVertexUniq, Long targetNebulaVertexId) {
+ graphEdgeMapper.updateTargetNebulaVertexId(sourceVertexUniq, targetNebulaVertexId);
+ }
+
+ public void updateAllSourceNebulaVertexId() {
+ graphEdgeMapper.updateAllSourceNebulaVertexId();
+ }
+
+ public void updateAllTargetNebulaVertexId() {
+ graphEdgeMapper.updateAllTargetNebulaVertexId();
+ }
+
+ public void updateAllSourceTargetNebulaVertexId() {
+ graphEdgeMapper.updateAllSourceTargetNebulaVertexId();
+ }
+
+ public void deleteGraphEdgeByDbId(Long dbId) {
+ graphEdgeMapper.deleteByPrimaryKey(dbId);
+ }
+}
diff --git a/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/dao/GraphVertexDao.java b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/dao/GraphVertexDao.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3db8fa3bb76d01c9a6da263ebc8a44c54df8c09
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/dao/GraphVertexDao.java
@@ -0,0 +1,65 @@
+package org.studiox.graph.persistence.mybatis.tk.dao;
+
+import org.springframework.stereotype.Repository;
+import org.studiox.graph.persistence.mybatis.tk.base.BaseGraphDao;
+import org.studiox.graph.persistence.mybatis.tk.domain.GraphVertexDO;
+import org.studiox.graph.persistence.mybatis.tk.mapper.GraphVertexMapper;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.List;
+
+@Repository
+public class GraphVertexDao extends BaseGraphDao {
+
+ @Resource private GraphVertexMapper graphVertexMapper;
+
+ @PostConstruct
+ private void init() {
+ mapper = graphVertexMapper;
+ }
+
+ public Integer getGraphVertexSize() {
+ return graphVertexMapper.selectCount(null);
+ }
+
+ public List getGraphVertexIds() {
+ return graphVertexMapper.getGraphVertexIds();
+ }
+
+ public List getGraphVertexUniqs() {
+ return graphVertexMapper.getGraphVertexUniqs();
+ }
+
+ public Long getGraphVertexIdByUniq(String uniq) {
+ return graphVertexMapper.getGraphVertexIdByUniq(uniq);
+ }
+
+ public Long getJanusVertexIdByUniq(String uniq) {
+ return graphVertexMapper.getJanusVertexIdByUniq(uniq);
+ }
+
+ public GraphVertexDO getGraphVertexDoByUniq(String uniq) {
+ return graphVertexMapper.getGraphVertexDoByUniq(uniq);
+ }
+
+ public List getGraphVertexDosByUniqLike(String likeUniqStr) {
+ return graphVertexMapper.getGraphVertexDosByUniqLike(likeUniqStr);
+ }
+
+ public void updateJanusVertexId(Long id, Long janusVertexId) {
+ graphVertexMapper.updateJanusVertexId(id, janusVertexId);
+ }
+
+ public void updateNeo4jVertexId(Long id, Long neo4jVertexId) {
+ graphVertexMapper.updateNeo4jVertexId(id, neo4jVertexId);
+ }
+
+ public void updateNebulaVertexId(Long id, Long nebulaVertexId) {
+ graphVertexMapper.updateNebulaVertexId(id, nebulaVertexId);
+ }
+
+ public void deleteGraphVertexByDbId(Long dbId) {
+ graphVertexMapper.deleteByPrimaryKey(dbId);
+ }
+}
diff --git a/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/domain/GraphEdgeDO.java b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/domain/GraphEdgeDO.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f9e13820f667a147596dd141e75a1f88add0cd9
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/domain/GraphEdgeDO.java
@@ -0,0 +1,222 @@
+package org.studiox.graph.persistence.mybatis.tk.domain;
+
+import org.studiox.graph.persistence.mybatis.tk.base.BaseGraphDO;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import java.util.Objects;
+
+@Entity
+@Table(name = "graph_edge")
+public class GraphEdgeDO extends BaseGraphDO {
+
+ @Column(name = "content")
+ private String content;
+
+ @Column(name = "content_md5")
+ private String contentMd5;
+
+ @Column(name = "source_vertex_uniq")
+ private String sourceVertexUniq;
+
+ @Column(name = "target_vertex_uniq")
+ private String targetVertexUniq;
+
+ @Column(name = "janus_edge_id")
+ private String janusEdgeId;
+
+ @Column(name = "neo4j_edge_id")
+ private Long neo4jEdgeId;
+
+ @Column(name = "nebula_edge_id")
+ private String nebulaEdgeId;
+
+ @Column(name = "source_janus_vertex_id")
+ private Long sourceJanusVertexId;
+
+ @Column(name = "target_janus_vertex_id")
+ private Long targetJanusVertexId;
+
+ @Column(name = "source_neo4j_vertex_id")
+ private Long sourceNeo4jVertexId;
+
+ @Column(name = "target_neo4j_vertex_id")
+ private Long targetNeo4jVertexId;
+
+ @Column(name = "source_nebula_vertex_id")
+ private Long sourceNebulaVertexId;
+
+ @Column(name = "target_nebula_vertex_id")
+ private Long targetNebulaVertexId;
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getContentMd5() {
+ return contentMd5;
+ }
+
+ public void setContentMd5(String contentMd5) {
+ this.contentMd5 = contentMd5;
+ }
+
+ public String getSourceVertexUniq() {
+ return sourceVertexUniq;
+ }
+
+ public void setSourceVertexUniq(String sourceVertexUniq) {
+ this.sourceVertexUniq = sourceVertexUniq;
+ }
+
+ public String getTargetVertexUniq() {
+ return targetVertexUniq;
+ }
+
+ public void setTargetVertexUniq(String targetVertexUniq) {
+ this.targetVertexUniq = targetVertexUniq;
+ }
+
+ public String getJanusEdgeId() {
+ return janusEdgeId;
+ }
+
+ public void setJanusEdgeId(String janusEdgeId) {
+ this.janusEdgeId = janusEdgeId;
+ }
+
+ public Long getNeo4jEdgeId() {
+ return neo4jEdgeId;
+ }
+
+ public void setNeo4jEdgeId(Long neo4jEdgeId) {
+ this.neo4jEdgeId = neo4jEdgeId;
+ }
+
+ public String getNebulaEdgeId() {
+ return nebulaEdgeId;
+ }
+
+ public void setNebulaEdgeId(String nebulaEdgeId) {
+ this.nebulaEdgeId = nebulaEdgeId;
+ }
+
+ public Long getSourceJanusVertexId() {
+ return sourceJanusVertexId;
+ }
+
+ public void setSourceJanusVertexId(Long sourceJanusVertexId) {
+ this.sourceJanusVertexId = sourceJanusVertexId;
+ }
+
+ public Long getTargetJanusVertexId() {
+ return targetJanusVertexId;
+ }
+
+ public void setTargetJanusVertexId(Long targetJanusVertexId) {
+ this.targetJanusVertexId = targetJanusVertexId;
+ }
+
+ public Long getSourceNeo4jVertexId() {
+ return sourceNeo4jVertexId;
+ }
+
+ public void setSourceNeo4jVertexId(Long sourceNeo4jVertexId) {
+ this.sourceNeo4jVertexId = sourceNeo4jVertexId;
+ }
+
+ public Long getTargetNeo4jVertexId() {
+ return targetNeo4jVertexId;
+ }
+
+ public void setTargetNeo4jVertexId(Long targetNeo4jVertexId) {
+ this.targetNeo4jVertexId = targetNeo4jVertexId;
+ }
+
+ public Long getSourceNebulaVertexId() {
+ return sourceNebulaVertexId;
+ }
+
+ public void setSourceNebulaVertexId(Long sourceNebulaVertexId) {
+ this.sourceNebulaVertexId = sourceNebulaVertexId;
+ }
+
+ public Long getTargetNebulaVertexId() {
+ return targetNebulaVertexId;
+ }
+
+ public void setTargetNebulaVertexId(Long targetNebulaVertexId) {
+ this.targetNebulaVertexId = targetNebulaVertexId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ GraphEdgeDO that = (GraphEdgeDO) o;
+ return Objects.equals(content, that.content)
+ && Objects.equals(contentMd5, that.contentMd5)
+ && Objects.equals(sourceVertexUniq, that.sourceVertexUniq)
+ && Objects.equals(targetVertexUniq, that.targetVertexUniq)
+ && Objects.equals(janusEdgeId, that.janusEdgeId)
+ && Objects.equals(neo4jEdgeId, that.neo4jEdgeId)
+ && Objects.equals(nebulaEdgeId, that.nebulaEdgeId)
+ && Objects.equals(sourceJanusVertexId, that.sourceJanusVertexId)
+ && Objects.equals(targetJanusVertexId, that.targetJanusVertexId)
+ && Objects.equals(sourceNeo4jVertexId, that.sourceNeo4jVertexId)
+ && Objects.equals(targetNeo4jVertexId, that.targetNeo4jVertexId)
+ && Objects.equals(sourceNebulaVertexId, that.sourceNebulaVertexId)
+ && Objects.equals(targetNebulaVertexId, that.targetNebulaVertexId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ super.hashCode(),
+ content,
+ contentMd5,
+ sourceVertexUniq,
+ targetVertexUniq,
+ janusEdgeId,
+ neo4jEdgeId,
+ nebulaEdgeId,
+ sourceJanusVertexId,
+ targetJanusVertexId,
+ sourceNeo4jVertexId,
+ targetNeo4jVertexId,
+ sourceNebulaVertexId,
+ targetNebulaVertexId);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("GraphEdgeDO{");
+ sb.append("content='").append(content).append('\'');
+ sb.append(", contentMd5='").append(contentMd5).append('\'');
+ sb.append(", sourceVertexUniq='").append(sourceVertexUniq).append('\'');
+ sb.append(", targetVertexUniq='").append(targetVertexUniq).append('\'');
+ sb.append(", janusEdgeId='").append(janusEdgeId).append('\'');
+ sb.append(", neo4jEdgeId=").append(neo4jEdgeId);
+ sb.append(", nebulaEdgeId='").append(nebulaEdgeId).append('\'');
+ sb.append(", sourceJanusVertexId=").append(sourceJanusVertexId);
+ sb.append(", targetJanusVertexId=").append(targetJanusVertexId);
+ sb.append(", sourceNeo4jVertexId=").append(sourceNeo4jVertexId);
+ sb.append(", targetNeo4jVertexId=").append(targetNeo4jVertexId);
+ sb.append(", sourceNebulaVertexId=").append(sourceNebulaVertexId);
+ sb.append(", targetNebulaVertexId=").append(targetNebulaVertexId);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/domain/GraphVertexDO.java b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/domain/GraphVertexDO.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ed9ef50948c92889134f54995bbd0e133cf4943
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/domain/GraphVertexDO.java
@@ -0,0 +1,104 @@
+package org.studiox.graph.persistence.mybatis.tk.domain;
+
+import org.studiox.graph.persistence.mybatis.tk.base.BaseGraphDO;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import java.util.Objects;
+
+@Entity
+@Table(name = "graph_vertex")
+public class GraphVertexDO extends BaseGraphDO {
+
+ @Column(name = "uniq")
+ private String uniq;
+
+ @Column(name = "janus_vertex_id")
+ private Long janusVertexId;
+
+ @Column(name = "neo4j_vertex_id")
+ private Long neo4jVertexId;
+
+ @Column(name = "nebula_vertex_id")
+ private Long nebulaVertexId;
+
+ @Column(name = "temp")
+ private Boolean temp;
+
+ public String getUniq() {
+ return uniq;
+ }
+
+ public void setUniq(String uniq) {
+ this.uniq = uniq;
+ }
+
+ public Long getJanusVertexId() {
+ return janusVertexId;
+ }
+
+ public void setJanusVertexId(Long janusVertexId) {
+ this.janusVertexId = janusVertexId;
+ }
+
+ public Long getNeo4jVertexId() {
+ return neo4jVertexId;
+ }
+
+ public void setNeo4jVertexId(Long neo4jVertexId) {
+ this.neo4jVertexId = neo4jVertexId;
+ }
+
+ public Long getNebulaVertexId() {
+ return nebulaVertexId;
+ }
+
+ public void setNebulaVertexId(Long nebulaVertexId) {
+ this.nebulaVertexId = nebulaVertexId;
+ }
+
+ public Boolean getTemp() {
+ return temp;
+ }
+
+ public void setTemp(Boolean temp) {
+ this.temp = temp;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ GraphVertexDO that = (GraphVertexDO) o;
+ return Objects.equals(uniq, that.uniq)
+ && Objects.equals(janusVertexId, that.janusVertexId)
+ && Objects.equals(neo4jVertexId, that.neo4jVertexId)
+ && Objects.equals(nebulaVertexId, that.nebulaVertexId)
+ && Objects.equals(temp, that.temp);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), uniq, janusVertexId, neo4jVertexId, nebulaVertexId, temp);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("GraphVertexDO{");
+ sb.append("uniq='").append(uniq).append('\'');
+ sb.append(", janusVertexId=").append(janusVertexId);
+ sb.append(", neo4jVertexId=").append(neo4jVertexId);
+ sb.append(", nebulaVertexId=").append(nebulaVertexId);
+ sb.append(", temp=").append(temp);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/mapper/GraphEdgeMapper.java b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/mapper/GraphEdgeMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..7db46d4b78388264a7a0a84d7e59408483e5f53d
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/mapper/GraphEdgeMapper.java
@@ -0,0 +1,187 @@
+package org.studiox.graph.persistence.mybatis.tk.mapper;
+
+import org.apache.ibatis.annotations.*;
+import org.studiox.graph.persistence.mybatis.tk.base.BaseGraphMapper;
+import org.studiox.graph.persistence.mybatis.tk.domain.GraphEdgeDO;
+
+import java.util.List;
+
+public interface GraphEdgeMapper extends BaseGraphMapper {
+
+ @Select("select id from graph_edge")
+ List getGraphEdgeIds();
+
+ @Select("select min(id) from graph_edge group by source_vertex_uniq,target_vertex_uniq")
+ List getGraphUniqueMinEdgeIds();
+
+ @Select("select max(id) from graph_edge group by source_vertex_uniq,target_vertex_uniq")
+ List getGraphUniqueMaxEdgeIds();
+
+ @Select(
+ "select count(*) from graph_edge where source_vertex_uniq=#{sourceVertexUniq} and target_vertex_uniq=#{targetVertexUniq}")
+ Long getGraphEdgeContentSize(
+ @Param("sourceVertexUniq") String sourceVertexUniq,
+ @Param("targetVertexUniq") String targetVertexUniq);
+
+ @Select(
+ "select content from graph_edge where source_vertex_uniq=#{sourceVertexUniq} and target_vertex_uniq=#{targetVertexUniq} order by create_time asc")
+ List getGraphEdgeContents(
+ @Param("sourceVertexUniq") String sourceVertexUniq,
+ @Param("targetVertexUniq") String targetVertexUniq);
+
+ @Select(
+ "select * from graph_edge where source_vertex_uniq=#{sourceVertexUniq} and target_vertex_uniq=#{targetVertexUniq} order by create_time asc limit 1")
+ @Results(
+ id = "graphEdgeDOMap",
+ value = {
+ @Result(id = true, column = "id", property = "id"),
+ @Result(column = "content", property = "content"),
+ @Result(column = "content_md5", property = "contentMd5"),
+ @Result(column = "type", property = "type"),
+ @Result(column = "owner", property = "owner"),
+ @Result(column = "source_vertex_uniq", property = "sourceVertexUniq"),
+ @Result(column = "target_vertex_uniq", property = "targetVertexUniq"),
+ @Result(column = "janus_edge_id", property = "janusEdgeId"),
+ @Result(column = "neo4j_edge_id", property = "neo4jEdgeId"),
+ @Result(column = "nebula_edge_id", property = "nebulaEdgeId"),
+ @Result(column = "source_janus_vertex_id", property = "sourceJanusVertexId"),
+ @Result(column = "target_janus_vertex_id", property = "targetJanusVertexId"),
+ @Result(column = "source_neo4j_vertex_id", property = "sourceNeo4jVertexId"),
+ @Result(column = "target_neo4j_vertex_id", property = "targetNeo4jVertexId"),
+ @Result(column = "source_nebula_vertex_id", property = "sourceNebulaVertexId"),
+ @Result(column = "target_nebula_vertex_id", property = "targetNebulaVertexId"),
+ @Result(column = "deleted", property = "deleted"),
+ @Result(column = "create_time", property = "createTime"),
+ @Result(column = "update_time", property = "updateTime")
+ })
+ GraphEdgeDO getOneGraphEdgeDoBySourceTargetUniq(
+ @Param("sourceVertexUniq") String sourceVertexUniq,
+ @Param("targetVertexUniq") String targetVertexUniq);
+
+ @Select(
+ "select id from graph_edge where (length(trim(content_md5))=0 or content_md5=MD5(#{content})) and source_vertex_uniq=#{sourceVertexUniq} and target_vertex_uniq=#{targetVertexUniq} and content=#{content} limit 1")
+ Long getGraphEdgeId(
+ @Param("content") String content,
+ @Param("sourceVertexUniq") String sourceVertexUniq,
+ @Param("targetVertexUniq") String targetVertexUniq);
+
+ @Update("update graph_edge set content_md5=MD5(content) where id=#{id}")
+ void updateGraphEdgeContentMd5(@Param("id") Long id);
+
+ @Update("update graph_edge set content_md5=MD5(content) where length(trim(content_md5))=0")
+ void updateAllGraphEdgeContentMd5();
+
+ @Update("update graph_edge set janus_edge_id=#{janusEdgeId} where id=#{id}")
+ void updateJanusEdgeId(@Param("id") Long id, @Param("janusEdgeId") String janusEdgeId);
+
+ @Update(
+ "update graph_edge set janus_edge_id=#{janusEdgeId},source_janus_vertex_id=#{sourceJanusVertexId},target_janus_vertex_id=#{targetJanusVertexId} where id=#{id}")
+ void updateJanusEdgeIdAndSourceTargetVertexId(
+ @Param("id") Long id,
+ @Param("janusEdgeId") String janusEdgeId,
+ @Param("sourceJanusVertexId") Long sourceJanusVertexId,
+ @Param("targetJanusVertexId") Long targetJanusVertexId);
+
+ @Update("update graph_edge set neo4j_edge_id=#{neo4jEdgeId} where id=#{id}")
+ void updateNeo4jEdgeId(@Param("id") Long id, @Param("neo4jEdgeId") Long neo4jEdgeId);
+
+ @Update(
+ "update graph_edge set neo4j_edge_id=#{neo4jEdgeId},source_neo4j_vertex_id=#{sourceNeo4jVertexId},target_neo4j_vertex_id=#{targetNeo4jVertexId} where id=#{id}")
+ void updateNeo4jEdgeIdAndSourceTargetVertexId(
+ @Param("id") Long id,
+ @Param("neo4jEdgeId") Long neo4jEdgeId,
+ @Param("sourceNeo4jVertexId") Long sourceNeo4jVertexId,
+ @Param("targetNeo4jVertexId") Long targetNeo4jVertexId);
+
+ @Update("update graph_edge set nebula_edge_id=#{nebulaEdgeId} where id=#{id}")
+ void updateNebulaEdgeId(@Param("id") Long id, @Param("nebulaEdgeId") String nebulaEdgeId);
+
+ @Update(
+ "update graph_edge set nebula_edge_id=#{nebulaEdgeId},source_nebula_vertex_id=#{sourceNebulaVertexId},target_nebula_vertex_id=#{targetNebulaVertexId} where id=#{id}")
+ void updateNebulaEdgeIdAndSourceTargetVertexId(
+ @Param("id") Long id,
+ @Param("nebulaEdgeId") String nebulaEdgeId,
+ @Param("sourceNebulaVertexId") Long sourceNebulaVertexId,
+ @Param("targetNebulaVertexId") Long targetNebulaVertexId);
+
+ @Update(
+ "update graph_edge set source_janus_vertex_id=#{sourceJanusVertexId} where source_vertex_uniq=#{sourceVertexUniq}")
+ void updateSourceJanusVertexId(
+ @Param("sourceVertexUniq") String sourceVertexUniq,
+ @Param("sourceJanusVertexId") Long sourceJanusVertexId);
+
+ @Update(
+ "update graph_edge set target_janus_vertex_id=#{targetJanusVertexId} where target_vertex_uniq=#{targetVertexUniq}")
+ void updateTargetJanusVertexId(
+ @Param("targetVertexUniq") String targetVertexUniq,
+ @Param("targetJanusVertexId") Long targetJanusVertexId);
+
+ @Update(
+ "update graph_edge a set source_janus_vertex_id=(select janus_vertex_id from graph_vertex b where a.source_vertex_uniq=b.uniq);")
+ void updateAllSourceJanusVertexId();
+
+ @Update(
+ "update graph_edge a set target_janus_vertex_id=(select janus_vertex_id from graph_vertex b where a.target_vertex_uniq=b.uniq);")
+ void updateAllTargetJanusVertexId();
+
+ @Update(
+ "update graph_edge a "
+ + "inner join graph_vertex b on a.source_vertex_uniq=b.uniq "
+ + "inner join graph_vertex c on a.target_vertex_uniq=c.uniq "
+ + "set a.source_janus_vertex_id=b.janus_vertex_id,a.target_janus_vertex_id=c.janus_vertex_id;")
+ void updateAllSourceTargetJanusVertexId();
+
+ @Update(
+ "update graph_edge set source_neo4j_vertex_id=#{sourceNeo4jVertexId} where source_vertex_uniq=#{sourceVertexUniq}")
+ void updateSourceNeo4jVertexId(
+ @Param("sourceVertexUniq") String sourceVertexUniq,
+ @Param("sourceNeo4jVertexId") Long sourceNeo4jVertexId);
+
+ @Update(
+ "update graph_edge set target_neo4j_vertex_id=#{targetNeo4jVertexId} where target_vertex_uniq=#{targetVertexUniq}")
+ void updateTargetNeo4jVertexId(
+ @Param("targetVertexUniq") String targetVertexUniq,
+ @Param("targetNeo4jVertexId") Long targetNeo4jVertexId);
+
+ @Update(
+ "update graph_edge a set source_neo4j_vertex_id=(select neo4j_vertex_id from graph_vertex b where a.source_vertex_uniq=b.uniq);")
+ void updateAllSourceNeo4jVertexId();
+
+ @Update(
+ "update graph_edge a set target_neo4j_vertex_id=(select neo4j_vertex_id from graph_vertex b where a.target_vertex_uniq=b.uniq);")
+ void updateAllTargetNeo4jVertexId();
+
+ @Update(
+ "update graph_edge a "
+ + "inner join graph_vertex b on a.source_vertex_uniq=b.uniq "
+ + "inner join graph_vertex c on a.target_vertex_uniq=c.uniq "
+ + "set a.source_neo4j_vertex_id=b.neo4j_vertex_id,a.target_neo4j_vertex_id=c.neo4j_vertex_id;")
+ void updateAllSourceTargetNeo4jVertexId();
+
+ @Update(
+ "update graph_edge set source_nebula_vertex_id=#{sourceNebulaVertexId} where source_vertex_uniq=#{sourceVertexUniq}")
+ void updateSourceNebulaVertexId(
+ @Param("sourceVertexUniq") String sourceVertexUniq,
+ @Param("sourceNebulaVertexId") Long sourceNebulaVertexId);
+
+ @Update(
+ "update graph_edge set target_nebula_vertex_id=#{targetNebulaVertexId} where target_vertex_uniq=#{targetVertexUniq}")
+ void updateTargetNebulaVertexId(
+ @Param("targetVertexUniq") String targetVertexUniq,
+ @Param("targetNebulaVertexId") Long targetNebulaVertexId);
+
+ @Update(
+ "update graph_edge a set source_nebula_vertex_id=(select nebula_vertex_id from graph_vertex b where a.source_vertex_uniq=b.uniq);")
+ void updateAllSourceNebulaVertexId();
+
+ @Update(
+ "update graph_edge a set target_nebula_vertex_id=(select nebula_vertex_id from graph_vertex b where a.target_vertex_uniq=b.uniq);")
+ void updateAllTargetNebulaVertexId();
+
+ @Update(
+ "update graph_edge a "
+ + "inner join graph_vertex b on a.source_vertex_uniq=b.uniq "
+ + "inner join graph_vertex c on a.target_vertex_uniq=c.uniq "
+ + "set a.source_nebula_vertex_id=b.nebula_vertex_id,a.target_nebula_vertex_id=c.nebula_vertex_id;")
+ void updateAllSourceTargetNebulaVertexId();
+}
diff --git a/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/mapper/GraphVertexMapper.java b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/mapper/GraphVertexMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..7c8b0dd2fc39b622215313225b21cf9a5dcbcd7c
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/mapper/GraphVertexMapper.java
@@ -0,0 +1,67 @@
+package org.studiox.graph.persistence.mybatis.tk.mapper;
+
+import org.apache.ibatis.annotations.*;
+import org.studiox.graph.persistence.mybatis.tk.base.BaseGraphMapper;
+import org.studiox.graph.persistence.mybatis.tk.domain.GraphVertexDO;
+
+import java.util.List;
+
+public interface GraphVertexMapper extends BaseGraphMapper {
+
+ @Select("select id from graph_vertex")
+ List getGraphVertexIds();
+
+ @Select("select uniq from graph_vertex")
+ List getGraphVertexUniqs();
+
+ @Select("select id from graph_vertex where uniq=#{uniq}")
+ Long getGraphVertexIdByUniq(@Param("uniq") String uniq);
+
+ @Select("select janus_vertex_id from graph_vertex where uniq=#{uniq}")
+ Long getJanusVertexIdByUniq(@Param("uniq") String uniq);
+
+ @Select("select * from graph_vertex where uniq=#{uniq}")
+ @Results(
+ id = "graphVertexDoByUniqMap",
+ value = {
+ @Result(id = true, column = "id", property = "id"),
+ @Result(column = "uniq", property = "uniq"),
+ @Result(column = "type", property = "type"),
+ @Result(column = "owner", property = "owner"),
+ @Result(column = "janus_vertex_id", property = "janusVertexId"),
+ @Result(column = "neo4j_vertex_id", property = "neo4jVertexId"),
+ @Result(column = "nebula_vertex_id", property = "nebulaVertexId"),
+ @Result(column = "temp", property = "temp"),
+ @Result(column = "deleted", property = "deleted"),
+ @Result(column = "create_time", property = "createTime"),
+ @Result(column = "update_time", property = "updateTime")
+ })
+ GraphVertexDO getGraphVertexDoByUniq(@Param("uniq") String uniq);
+
+ @Select("select * from graph_vertex where uniq like #{uniqLikeStr}")
+ @Results(
+ id = "graphVertexDosByUniqLikeMap",
+ value = {
+ @Result(id = true, column = "id", property = "id"),
+ @Result(column = "uniq", property = "uniq"),
+ @Result(column = "type", property = "type"),
+ @Result(column = "owner", property = "owner"),
+ @Result(column = "janus_vertex_id", property = "janusVertexId"),
+ @Result(column = "neo4j_vertex_id", property = "neo4jVertexId"),
+ @Result(column = "nebula_vertex_id", property = "nebulaVertexId"),
+ @Result(column = "temp", property = "temp"),
+ @Result(column = "deleted", property = "deleted"),
+ @Result(column = "create_time", property = "createTime"),
+ @Result(column = "update_time", property = "updateTime")
+ })
+ List getGraphVertexDosByUniqLike(@Param("uniqLikeStr") String uniqLikeStr);
+
+ @Update("update graph_vertex set janus_vertex_id=#{janusVertexId} where id=#{id}")
+ void updateJanusVertexId(@Param("id") Long id, @Param("janusVertexId") Long janusVertexId);
+
+ @Update("update graph_vertex set neo4j_vertex_id=#{neo4jVertexId} where id=#{id}")
+ void updateNeo4jVertexId(@Param("id") Long id, @Param("neo4jVertexId") Long neo4jVertexId);
+
+ @Update("update graph_vertex set nebula_vertex_id=#{nebulaVertexId} where id=#{id}")
+ void updateNebulaVertexId(@Param("id") Long id, @Param("nebulaVertexId") Long nebulaVertexId);
+}
diff --git a/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/service/GraphDbService.java b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/service/GraphDbService.java
new file mode 100644
index 0000000000000000000000000000000000000000..d288b2c8369e080eb267caf86cb076932b44e36c
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/main/java/org/studiox/graph/persistence/mybatis/tk/service/GraphDbService.java
@@ -0,0 +1,489 @@
+package org.studiox.graph.persistence.mybatis.tk.service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.studiox.graph.persistence.mybatis.tk.dao.GraphEdgeDao;
+import org.studiox.graph.persistence.mybatis.tk.dao.GraphVertexDao;
+import org.studiox.graph.persistence.mybatis.tk.domain.GraphEdgeDO;
+import org.studiox.graph.persistence.mybatis.tk.domain.GraphVertexDO;
+
+import java.util.Collections;
+import java.util.List;
+
+@Service
+public class GraphDbService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(GraphDbService.class);
+
+ @Autowired private GraphVertexDao graphVertexDao;
+
+ @Autowired private GraphEdgeDao graphEdgeDao;
+
+ public Integer getGraphVertexSize() {
+ try {
+ return graphVertexDao.getGraphVertexSize();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return null;
+ }
+
+ public List getGraphVertexIds() {
+ try {
+ return graphVertexDao.getGraphVertexIds();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return Collections.emptyList();
+ }
+
+ public List getGraphVertexUniqs() {
+ try {
+ return graphVertexDao.getGraphVertexUniqs();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return Collections.emptyList();
+ }
+
+ public Long getGraphVertexIdByUniq(String uniq) {
+ try {
+ return graphVertexDao.getGraphVertexIdByUniq(uniq);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return null;
+ }
+
+ public Long getJanusVertexIdByUniq(String uniq) {
+ try {
+ return graphVertexDao.getJanusVertexIdByUniq(uniq);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return null;
+ }
+
+ public GraphVertexDO getGraphVertexDoById(Long dbId) {
+ try {
+ return graphVertexDao.selectByPrimaryKey(dbId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return null;
+ }
+
+ public GraphVertexDO getGraphVertexDoByUniq(String uniq) {
+ try {
+ return graphVertexDao.getGraphVertexDoByUniq(uniq);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return null;
+ }
+
+ public List getGraphVertexDosByUniqLike(String likeUniqStr) {
+ try {
+ return graphVertexDao.getGraphVertexDosByUniqLike(likeUniqStr);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return Collections.emptyList();
+ }
+
+ public void insertGraphVertex(GraphVertexDO graphVertexDO) {
+ try {
+ graphVertexDao.insertSelective(graphVertexDO);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateGraphVertex(GraphVertexDO graphVertexDO) {
+ try {
+ graphVertexDao.updateByPrimaryKeySelective(graphVertexDO);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateJanusVertexId(Long id, Long janusVertexId) {
+ try {
+ graphVertexDao.updateJanusVertexId(id, janusVertexId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateNeo4jVertexId(Long id, Long neo4jVertexId) {
+ try {
+ graphVertexDao.updateNeo4jVertexId(id, neo4jVertexId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateNebulaVertexId(Long id, Long nebulaVertexId) {
+ try {
+ graphVertexDao.updateNebulaVertexId(id, nebulaVertexId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void deleteGraphVertexByDbId(Long dbId) {
+ try {
+ graphVertexDao.deleteGraphVertexByDbId(dbId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public Integer getGraphEdgeSize() {
+ try {
+ return graphEdgeDao.getGraphEdgeSize();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return null;
+ }
+
+ public List getGraphEdgeIds() {
+ try {
+ return graphEdgeDao.getGraphEdgeIds();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return Collections.emptyList();
+ }
+
+ public List getGraphUniqueMinEdgeIds() {
+ try {
+ return graphEdgeDao.getGraphUniqueMinEdgeIds();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return Collections.emptyList();
+ }
+
+ public List getGraphUniqueMaxEdgeIds() {
+ try {
+ return graphEdgeDao.getGraphUniqueMaxEdgeIds();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return Collections.emptyList();
+ }
+
+ public Long getGraphEdgeContentSize(String sourceVertexUniq, String targetVertexUniq) {
+ try {
+ return graphEdgeDao.getGraphEdgeContentSize(sourceVertexUniq, targetVertexUniq);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return null;
+ }
+
+ public List getGraphEdgeContents(String sourceVertexUniq, String targetVertexUniq) {
+ try {
+ return graphEdgeDao.getGraphEdgeContents(sourceVertexUniq, targetVertexUniq);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return Collections.emptyList();
+ }
+
+ public List getGraphEdgeDOs(GraphEdgeDO graphEdgeDO) {
+ try {
+ return graphEdgeDao.getGraphEdgeDOs(graphEdgeDO);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return Collections.emptyList();
+ }
+
+ public GraphEdgeDO getOneGraphEdgeDoBySourceTargetUniq(
+ String sourceVertexUniq, String targetVertexUniq) {
+ try {
+ return graphEdgeDao.getOneGraphEdgeDoBySourceTargetUniq(sourceVertexUniq, targetVertexUniq);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return null;
+ }
+
+ public Long getGraphEdgeId(String content, String sourceVertexUniq, String targetVertexUniq) {
+ try {
+ return graphEdgeDao.getGraphEdgeId(content, sourceVertexUniq, targetVertexUniq);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return null;
+ }
+
+ public GraphEdgeDO getGraphEdgeDoById(Long dbId) {
+ try {
+ return graphEdgeDao.selectByPrimaryKey(dbId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ return null;
+ }
+
+ public void insertGraphEdge(GraphEdgeDO graphEdgeDO) {
+ try {
+ graphEdgeDao.insertSelective(graphEdgeDO);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateGraphEdge(GraphEdgeDO graphEdgeDO) {
+ try {
+ graphEdgeDao.updateByPrimaryKeySelective(graphEdgeDO);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateGraphEdgeContentMd5(Long dbId) {
+ try {
+ graphEdgeDao.updateGraphEdgeContentMd5(dbId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateAllGraphEdgeContentMd5() {
+ try {
+ graphEdgeDao.updateAllGraphEdgeContentMd5();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateJanusEdgeId(Long id, String janusEdgeId) {
+ try {
+ graphEdgeDao.updateJanusEdgeId(id, janusEdgeId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateJanusEdgeIdAndSourceTargetVertexId(
+ Long id, String janusEdgeId, Long sourceJanusVertexId, Long targetJanusVertexId) {
+ try {
+ graphEdgeDao.updateJanusEdgeIdAndSourceTargetVertexId(
+ id, janusEdgeId, sourceJanusVertexId, targetJanusVertexId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateNeo4jEdgeId(Long id, Long neo4jEdgeId) {
+ try {
+ graphEdgeDao.updateNeo4jEdgeId(id, neo4jEdgeId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateNeo4jEdgeIdAndSourceTargetVertexId(
+ Long id, Long neo4jEdgeId, Long sourceNeo4jVertexId, Long targetNeo4jVertexId) {
+ try {
+ graphEdgeDao.updateNeo4jEdgeIdAndSourceTargetVertexId(
+ id, neo4jEdgeId, sourceNeo4jVertexId, targetNeo4jVertexId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateNebulaEdgeId(Long id, String nebulaEdgeId) {
+ try {
+ graphEdgeDao.updateNebulaEdgeId(id, nebulaEdgeId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateNebulaEdgeIdAndSourceTargetVertexId(
+ Long id, String nebulaEdgeId, Long sourceNebulaVertexId, Long targetNebulaVertexId) {
+ try {
+ graphEdgeDao.updateNebulaEdgeIdAndSourceTargetVertexId(
+ id, nebulaEdgeId, sourceNebulaVertexId, targetNebulaVertexId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateSourceJanusVertexId(String sourceVertexUniq, Long sourceJanusVertexId) {
+ try {
+ graphEdgeDao.updateSourceJanusVertexId(sourceVertexUniq, sourceJanusVertexId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateTargetJanusVertexId(String sourceVertexUniq, Long targetJanusVertexId) {
+ try {
+ graphEdgeDao.updateTargetJanusVertexId(sourceVertexUniq, targetJanusVertexId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateAllSourceJanusVertexId() {
+ try {
+ graphEdgeDao.updateAllSourceJanusVertexId();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateAllTargetJanusVertexId() {
+ try {
+ graphEdgeDao.updateAllTargetJanusVertexId();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateAllSourceTargetJanusVertexId() {
+ try {
+ graphEdgeDao.updateAllSourceTargetJanusVertexId();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateSourceNeo4jVertexId(String sourceVertexUniq, Long sourceNeo4jVertexId) {
+ try {
+ graphEdgeDao.updateSourceNeo4jVertexId(sourceVertexUniq, sourceNeo4jVertexId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateTargetNeo4jVertexId(String sourceVertexUniq, Long targetNeo4jVertexId) {
+ try {
+ graphEdgeDao.updateTargetNeo4jVertexId(sourceVertexUniq, targetNeo4jVertexId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateAllSourceNeo4jVertexId() {
+ try {
+ graphEdgeDao.updateAllSourceNeo4jVertexId();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateAllTargetNeo4jVertexId() {
+ try {
+ graphEdgeDao.updateAllTargetNeo4jVertexId();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateAllSourceTargetNeo4jVertexId() {
+ try {
+ graphEdgeDao.updateAllSourceTargetNeo4jVertexId();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateSourceNebulaVertexId(String sourceVertexUniq, Long sourceNebulaVertexId) {
+ try {
+ graphEdgeDao.updateSourceNebulaVertexId(sourceVertexUniq, sourceNebulaVertexId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateTargetNebulaVertexId(String sourceVertexUniq, Long targetNebulaVertexId) {
+ try {
+ graphEdgeDao.updateTargetNebulaVertexId(sourceVertexUniq, targetNebulaVertexId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateAllSourceNebulaVertexId() {
+ try {
+ graphEdgeDao.updateAllSourceNebulaVertexId();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateAllTargetNebulaVertexId() {
+ try {
+ graphEdgeDao.updateAllTargetNebulaVertexId();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateAllSourceTargetNebulaVertexId() {
+ try {
+ graphEdgeDao.updateAllSourceTargetNebulaVertexId();
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateGraphVertexDbUniq(String oldUniq, String newUniq) {
+ try {
+ GraphVertexDO graphVertexDO = graphVertexDao.getGraphVertexDoByUniq(oldUniq);
+ if (null != graphVertexDO) {
+ graphVertexDO.setUniq(newUniq);
+ graphVertexDao.updateByPrimaryKeySelective(graphVertexDO);
+ }
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void updateGraphEdgeDbSourceTargetUniq(String oldUniq, String newUniq) {
+ GraphEdgeDO sourceGraphEdgeDO = new GraphEdgeDO();
+ sourceGraphEdgeDO.setSourceVertexUniq(oldUniq);
+ try {
+ List graphEdgeDos = graphEdgeDao.select(sourceGraphEdgeDO);
+ if (null != graphEdgeDos) {
+ for (GraphEdgeDO obj : graphEdgeDos) {
+ obj.setSourceVertexUniq(newUniq);
+ graphEdgeDao.updateByPrimaryKeySelective(obj);
+ }
+ }
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ GraphEdgeDO targetGraphEdgeDO = new GraphEdgeDO();
+ targetGraphEdgeDO.setTargetVertexUniq(oldUniq);
+ try {
+ List graphEdgeDos = graphEdgeDao.select(targetGraphEdgeDO);
+ if (null != graphEdgeDos) {
+ for (GraphEdgeDO obj : graphEdgeDos) {
+ obj.setTargetVertexUniq(newUniq);
+ graphEdgeDao.updateByPrimaryKeySelective(obj);
+ }
+ }
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+
+ public void deleteGraphEdgeByDbId(Long dbId) {
+ try {
+ graphEdgeDao.deleteGraphEdgeByDbId(dbId);
+ } catch (Throwable t) {
+ LOGGER.error(t.getMessage(), t);
+ }
+ }
+}
diff --git a/graph-persistence/persistence-mybatis-tk/src/test/java/org/studiox/graph/persistence/mybatis/tk/TkMybatisSpringTest.java b/graph-persistence/persistence-mybatis-tk/src/test/java/org/studiox/graph/persistence/mybatis/tk/TkMybatisSpringTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..41da44904d3c4bf8ef09ff9c3297ad166ef0e0a8
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/test/java/org/studiox/graph/persistence/mybatis/tk/TkMybatisSpringTest.java
@@ -0,0 +1,271 @@
+package org.studiox.graph.persistence.mybatis.tk;
+
+import ch.vorburger.exec.ManagedProcessException;
+import ch.vorburger.mariadb4j.DB;
+import ch.vorburger.mariadb4j.DBConfigurationBuilder;
+import org.junit.jupiter.api.*;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.studiox.graph.persistence.mybatis.tk.domain.GraphEdgeDO;
+import org.studiox.graph.persistence.mybatis.tk.domain.GraphVertexDO;
+import org.studiox.graph.persistence.mybatis.tk.service.GraphDbService;
+
+import java.util.List;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(classes = TkMybatisSpring.class)
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class TkMybatisSpringTest {
+
+ private static DB db;
+
+ @Autowired private GraphDbService graphDbService;
+
+ @BeforeAll
+ public void beforeAll() {
+ DBConfigurationBuilder config = DBConfigurationBuilder.newBuilder();
+ config.setPort(13306);
+ config.setDeletingTemporaryBaseAndDataDirsOnShutdown(true);
+ try {
+ db = DB.newEmbeddedDB(config.build());
+ db.start();
+ db.source("mysql_ddl.sql", "test");
+ } catch (ManagedProcessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @AfterAll
+ public void afterAll() {
+ if (null != db) {
+ try {
+ db.stop();
+ } catch (ManagedProcessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void clean() {
+ List graphVertexIds = graphDbService.getGraphVertexIds();
+ if (null != graphVertexIds && graphVertexIds.size() > 0) {
+ for (Long graphVertexId : graphVertexIds) {
+ graphDbService.deleteGraphVertexByDbId(graphVertexId);
+ }
+ }
+ List graphEdgeIds = graphDbService.getGraphEdgeIds();
+ if (null != graphEdgeIds && graphEdgeIds.size() > 0) {
+ for (Long graphEdgeId : graphEdgeIds) {
+ graphDbService.deleteGraphEdgeByDbId(graphEdgeId);
+ }
+ }
+ }
+
+ @BeforeEach
+ public void beforeEach() {
+ clean();
+ }
+
+ @AfterEach
+ public void afterEach() {
+ clean();
+ }
+
+ @Test
+ @Order(1)
+ @DisplayName("test1")
+ public void test1() {
+ GraphVertexDO graphVertexDO1 = new GraphVertexDO();
+ graphVertexDO1.setUniq("uniq1");
+ graphVertexDO1.setType("type1");
+ graphVertexDO1.setOwner("owner1");
+ graphVertexDO1.setJanusVertexId(1L);
+ graphVertexDO1.setTemp(true);
+ graphVertexDO1.setDeleted(false);
+ graphDbService.insertGraphVertex(graphVertexDO1);
+
+ Integer count = graphDbService.getGraphVertexSize();
+ Assertions.assertEquals(1, count);
+
+ Assertions.assertEquals(1L, graphDbService.getJanusVertexIdByUniq("uniq1"));
+
+ List graphVertexIds = graphDbService.getGraphVertexIds();
+ Long graphVertexId = graphVertexIds.get(0);
+ GraphVertexDO graphVertexDO2 = graphDbService.getGraphVertexDoById(graphVertexId);
+ graphVertexDO2.setUniq("uniq2");
+ graphDbService.updateGraphVertex(graphVertexDO2);
+
+ GraphVertexDO graphVertexDO3 = graphDbService.getGraphVertexDoById(graphVertexId);
+ Assertions.assertEquals("uniq2", graphVertexDO3.getUniq());
+ Assertions.assertEquals(true, graphVertexDO3.getTemp());
+ Assertions.assertEquals(false, graphVertexDO3.getDeleted());
+ }
+
+ @Test
+ @Order(2)
+ @DisplayName("test2")
+ public void test2() {
+ GraphEdgeDO graphEdgeDO1 = new GraphEdgeDO();
+ graphEdgeDO1.setContent("select * from sys.version");
+ graphEdgeDO1.setType("typq1");
+ graphEdgeDO1.setOwner("owner1");
+ graphEdgeDO1.setSourceVertexUniq("uniq1");
+ graphEdgeDO1.setTargetVertexUniq("uniq2");
+ graphEdgeDO1.setJanusEdgeId("edge1");
+ graphEdgeDO1.setSourceJanusVertexId(1L);
+ graphEdgeDO1.setTargetJanusVertexId(1L);
+ graphDbService.insertGraphEdge(graphEdgeDO1);
+
+ Integer count = graphDbService.getGraphEdgeSize();
+ Assertions.assertEquals(1, count);
+
+ Assertions.assertEquals(1L, graphDbService.getGraphEdgeContentSize("uniq1", "uniq2"));
+
+ List graphEdgeIds = graphDbService.getGraphEdgeIds();
+ Long graphEdgeId = graphEdgeIds.get(0);
+ GraphEdgeDO graphEdgeDO2 = graphDbService.getGraphEdgeDoById(graphEdgeId);
+ graphEdgeDO2.setContent("select 1 from sys.version");
+ graphDbService.updateGraphEdge(graphEdgeDO2);
+
+ graphDbService.updateAllGraphEdgeContentMd5();
+
+ GraphEdgeDO graphEdgeDO3 = graphDbService.getGraphEdgeDoById(graphEdgeId);
+ Assertions.assertEquals("select 1 from sys.version", graphEdgeDO3.getContent());
+
+ GraphEdgeDO graphEdgeDO4 = new GraphEdgeDO();
+ graphEdgeDO4.setType("typq1");
+ List graphEdgeDOs = graphDbService.getGraphEdgeDOs(graphEdgeDO4);
+ Assertions.assertEquals(1, graphEdgeDOs.size());
+ Assertions.assertEquals("select 1 from sys.version", graphEdgeDOs.get(0).getContent());
+ }
+
+ @Test
+ @Order(3)
+ @DisplayName("test3")
+ public void test3() {
+ GraphVertexDO graphVertexDO1 = new GraphVertexDO();
+ graphVertexDO1.setUniq("ENTITY_TYPE_TABLE#test1.table1@service1");
+ graphDbService.insertGraphVertex(graphVertexDO1);
+
+ Long vertexId =
+ graphDbService.getGraphVertexIdByUniq("ENTITY_TYPE_TABLE#test1.table1@service1");
+ Assertions.assertNotNull(vertexId);
+
+ GraphVertexDO graphVertexDO2 = new GraphVertexDO();
+ graphVertexDO2.setUniq("ENTITY_TYPE_TABLE#test1.table2@service1");
+ graphDbService.insertGraphVertex(graphVertexDO2);
+ List vertexIds = graphDbService.getGraphVertexIds();
+ Assertions.assertEquals(2, vertexIds.size());
+
+ graphDbService.updateJanusVertexId(vertexId, 111L);
+ graphDbService.updateNeo4jVertexId(vertexId, 222L);
+ graphDbService.updateNebulaVertexId(vertexId, 333L);
+
+ GraphVertexDO graphVertexDO3 = graphDbService.getGraphVertexDoById(vertexId);
+ Assertions.assertNotNull(graphVertexDO3);
+ Assertions.assertEquals(111L, graphVertexDO3.getJanusVertexId().longValue());
+ Assertions.assertEquals(222L, graphVertexDO3.getNeo4jVertexId().longValue());
+ Assertions.assertEquals(333L, graphVertexDO3.getNebulaVertexId().longValue());
+
+ List graphVertexDOS =
+ graphDbService.getGraphVertexDosByUniqLike("ENTITY_TYPE_TABLE#%@service1");
+ Assertions.assertNotNull(graphVertexDOS);
+ Assertions.assertEquals(2, graphVertexDOS.size());
+
+ GraphEdgeDO graphEdgeDO1 = new GraphEdgeDO();
+ graphEdgeDO1.setContent("content1");
+ graphEdgeDO1.setSourceVertexUniq("ENTITY_TYPE_TABLE#test1.table1@service1");
+ graphEdgeDO1.setTargetVertexUniq("ENTITY_TYPE_TABLE#test1.table2@service1");
+ graphDbService.insertGraphEdge(graphEdgeDO1);
+
+ Long edgeId1 =
+ graphDbService.getGraphEdgeId(
+ "content1",
+ "ENTITY_TYPE_TABLE#test1.table1@service1",
+ "ENTITY_TYPE_TABLE#test1.table2@service1");
+ Assertions.assertNotNull(edgeId1);
+ Long edgeId2 =
+ graphDbService.getGraphEdgeId(
+ "content2",
+ "ENTITY_TYPE_TABLE#test1.table1@service1",
+ "ENTITY_TYPE_TABLE#test1.table2@service1");
+ Assertions.assertNull(edgeId2);
+ graphDbService.updateGraphEdgeContentMd5(edgeId1);
+ edgeId1 =
+ graphDbService.getGraphEdgeId(
+ "content1",
+ "ENTITY_TYPE_TABLE#test1.table1@service1",
+ "ENTITY_TYPE_TABLE#test1.table2@service1");
+ Assertions.assertNotNull(edgeId1);
+
+ List edgeIds = graphDbService.getGraphEdgeIds();
+ Assertions.assertEquals(1, edgeIds.size());
+ graphEdgeDO1 = graphDbService.getGraphEdgeDoById(edgeIds.get(0));
+ Long edgeId = graphEdgeDO1.getId();
+ graphDbService.updateJanusEdgeId(edgeId, "444");
+ graphDbService.updateJanusEdgeIdAndSourceTargetVertexId(
+ edgeId,
+ "444",
+ graphDbService.getJanusVertexIdByUniq("ENTITY_TYPE_TABLE#test1.table1@service1"),
+ graphDbService.getJanusVertexIdByUniq("ENTITY_TYPE_TABLE#test1.table2@service1"));
+ graphDbService.updateNeo4jEdgeId(edgeId, 555L);
+ graphDbService.updateNeo4jEdgeIdAndSourceTargetVertexId(edgeId, 555L, null, null);
+ graphDbService.updateNebulaEdgeId(edgeId, "666");
+ graphDbService.updateNebulaEdgeIdAndSourceTargetVertexId(edgeId, "666", null, null);
+
+ graphEdgeDO1 = graphDbService.getGraphEdgeDoById(edgeId);
+ Assertions.assertEquals("444", graphEdgeDO1.getJanusEdgeId());
+ Assertions.assertEquals(555L, graphEdgeDO1.getNeo4jEdgeId().longValue());
+ Assertions.assertEquals("666", graphEdgeDO1.getNebulaEdgeId());
+
+ // For H2 Test
+ graphDbService.updateAllSourceTargetJanusVertexId();
+ graphEdgeDO1 = graphDbService.getGraphEdgeDoById(edgeId);
+ Assertions.assertEquals(
+ graphEdgeDO1.getSourceJanusVertexId(),
+ graphDbService
+ .getGraphVertexDoByUniq(graphEdgeDO1.getSourceVertexUniq())
+ .getJanusVertexId());
+ Assertions.assertEquals(
+ graphEdgeDO1.getTargetJanusVertexId(),
+ graphDbService
+ .getGraphVertexDoByUniq(graphEdgeDO1.getTargetVertexUniq())
+ .getJanusVertexId());
+ graphDbService.updateAllSourceTargetNeo4jVertexId();
+ graphDbService.updateAllSourceTargetNebulaVertexId();
+
+ GraphEdgeDO graphEdgeDO2 = new GraphEdgeDO();
+ graphEdgeDO2.setContent("content2");
+ graphEdgeDO2.setSourceVertexUniq("ENTITY_TYPE_TABLE#test1.table2@service1");
+ graphEdgeDO2.setTargetVertexUniq("ENTITY_TYPE_TABLE#test1.table3@service1");
+ graphDbService.insertGraphEdge(graphEdgeDO2);
+
+ graphDbService.updateGraphVertexDbUniq(
+ "ENTITY_TYPE_TABLE#test1.table2@service1", "ENTITY_TYPE_TABLE#test1.table4@service1");
+
+ vertexId = graphDbService.getGraphVertexIdByUniq("ENTITY_TYPE_TABLE#test1.table2@service1");
+ Assertions.assertNull(vertexId);
+ vertexId = graphDbService.getGraphVertexIdByUniq("ENTITY_TYPE_TABLE#test1.table4@service1");
+ Assertions.assertNotNull(vertexId);
+
+ graphDbService.updateGraphEdgeDbSourceTargetUniq(
+ "ENTITY_TYPE_TABLE#test1.table2@service1", "ENTITY_TYPE_TABLE#test1.table4@service1");
+
+ List graphEdgeDBIds = graphDbService.getGraphEdgeIds();
+ Assertions.assertNotNull(graphEdgeDBIds);
+ for (Long graphEdgeDBId : graphEdgeDBIds) {
+ GraphEdgeDO graphEdgeDO = graphDbService.getGraphEdgeDoById(graphEdgeDBId);
+ if (graphEdgeDO.getContent().equals("content1")) {
+ Assertions.assertEquals(
+ "ENTITY_TYPE_TABLE#test1.table4@service1", graphEdgeDO.getTargetVertexUniq());
+ }
+ if (graphEdgeDO.getContent().equals("content2")) {
+ Assertions.assertEquals(
+ "ENTITY_TYPE_TABLE#test1.table4@service1", graphEdgeDO.getSourceVertexUniq());
+ }
+ }
+ }
+}
diff --git a/graph-persistence/persistence-mybatis-tk/src/test/resources/application.yml b/graph-persistence/persistence-mybatis-tk/src/test/resources/application.yml
new file mode 100644
index 0000000000000000000000000000000000000000..47fc76abe96399d9beaff1deea17a450f18b32d2
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/test/resources/application.yml
@@ -0,0 +1,15 @@
+spring:
+ main:
+ lazy-initialization: false
+ datasource:
+ url: jdbc:mysql://localhost:13306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
+ username: root
+ password:
+ driver-class-name: com.mysql.jdbc.Driver
+ hikari:
+ pool-name: HikariCP
+ minimum-idle: 2
+ maximum-pool-size: 5
+ connection-test-query: SELECT 1
+ max-lifetime: 1800000
+ connection-timeout: 30000
diff --git a/graph-persistence/persistence-mybatis-tk/src/test/resources/mysql_ddl.sql b/graph-persistence/persistence-mybatis-tk/src/test/resources/mysql_ddl.sql
new file mode 100644
index 0000000000000000000000000000000000000000..48cc95eeb62d757e9fe145bcf22fb758fd4eb86c
--- /dev/null
+++ b/graph-persistence/persistence-mybatis-tk/src/test/resources/mysql_ddl.sql
@@ -0,0 +1,53 @@
+create table if not exists `graph_vertex` (
+ `id` bigint(20) unsigned not null auto_increment comment '主键',
+ `uniq` varchar(255) not null default '' comment '顶点的唯一标识',
+ `type` varchar(20) not null default '' comment '顶点的类型',
+ `owner` varchar(50) not null default '' comment '所有者',
+ `janus_vertex_id` bigint(20) not null default 0 comment '顶点存储 JanusGraph Vertex Id',
+ `neo4j_vertex_id` bigint(20) not null default 0 comment '顶点存储 Neo4j Vertex Id',
+ `nebula_vertex_id` bigint(20) not null default 0 comment '顶点存储 NebulaGraph Vertex Id',
+ `temp` tinyint(1) not null default 0 comment '是否临时点(0:否 1:是),只存在数据库,不存在图中',
+ `deleted` tinyint(1) not null default 0 comment '是否删除(0:否 1:是)',
+ `create_time` timestamp not null default current_timestamp comment '顶点的创建时间',
+ `update_time` timestamp not null default current_timestamp comment '顶点的修改时间',
+ primary key (`id`),
+ unique key (`uniq`),
+ index (`janus_vertex_id`),
+ index (`neo4j_vertex_id`),
+ index (`nebula_vertex_id`)
+) engine=innodb auto_increment=1 default charset=utf8 comment='图中顶点集合';
+
+create table if not exists `graph_edge` (
+ `id` bigint(20) unsigned not null auto_increment comment '主键',
+ `content` mediumtext not null comment '边的记录内容',
+ `content_md5` char(32) not null default '' comment '边的记录内容MD5值',
+ `type` varchar(20) not null default '' comment '边的类型',
+ `owner` varchar(50) not null default '' comment '所有者',
+ `source_vertex_uniq` varchar(255) not null default '' comment '边的输入顶点的唯一标识',
+ `target_vertex_uniq` varchar(255) not null default '' comment '边的输出顶点的唯一标识',
+ `janus_edge_id` varchar(50) not null default '' comment '边存储 JanusGraph Edge Id',
+ `neo4j_edge_id` bigint(20) not null default 0 comment '边存储 Neo4j Edge Id',
+ `nebula_edge_id` varchar(50) not null default '' comment '边存储 NebulaGraph Edge Id',
+ `source_janus_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 JanusGraph Vertex Id',
+ `target_janus_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 JanusGraph Vertex Id',
+ `source_neo4j_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 Neo4j Vertex Id',
+ `target_neo4j_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 Neo4j Vertex Id',
+ `source_nebula_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 NebulaGraph Vertex Id',
+ `target_nebula_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 NebulaGraph Vertex Id',
+ `deleted` tinyint(1) not null default 0 comment '是否删除(0:否 1:是)',
+ `create_time` timestamp not null default current_timestamp comment '边的创建时间',
+ `update_time` timestamp not null default current_timestamp comment '边的修改时间',
+ primary key (`id`),
+ index (`content_md5`),
+ index (`source_vertex_uniq`),
+ index (`target_vertex_uniq`),
+ index (`janus_edge_id`),
+ index (`neo4j_edge_id`),
+ index (`nebula_edge_id`),
+ index (`source_janus_vertex_id`),
+ index (`target_janus_vertex_id`),
+ index (`source_neo4j_vertex_id`),
+ index (`target_neo4j_vertex_id`),
+ index (`source_nebula_vertex_id`),
+ index (`target_nebula_vertex_id`)
+) engine=innodb auto_increment=1 default charset=utf8 comment='图中边集合';
diff --git a/graph-persistence/persistence-mybatis/pom.xml b/graph-persistence/persistence-mybatis/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ded18ee9900f38b779aadbca6c28c4b00eaa3e26
--- /dev/null
+++ b/graph-persistence/persistence-mybatis/pom.xml
@@ -0,0 +1,40 @@
+
+
+ 4.0.0
+
+ org.studiox.graph
+ graph-persistence
+ 1.0.5-SNAPSHOT
+
+ org.studiox.graph.persistence
+ persistence-mybatis
+ 1.0.5-SNAPSHOT
+ jar
+
+
+ junit
+ junit
+ test
+
+
+ com.h2database
+ h2
+ test
+
+
+ mysql
+ mysql-connector-java
+ test
+
+
+ org.studiox.graph.persistence
+ persistence-model
+
+
+ org.mybatis
+ mybatis
+
+
+
diff --git a/graph-persistence/persistence-mybatis/src/main/java/org/studiox/graph/persistence/mybatis/dao/GraphEdgeDao.java b/graph-persistence/persistence-mybatis/src/main/java/org/studiox/graph/persistence/mybatis/dao/GraphEdgeDao.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ad1f5deac99fee35d2b1b7616d9f296aac99932
--- /dev/null
+++ b/graph-persistence/persistence-mybatis/src/main/java/org/studiox/graph/persistence/mybatis/dao/GraphEdgeDao.java
@@ -0,0 +1,54 @@
+package org.studiox.graph.persistence.mybatis.dao;
+
+import org.apache.ibatis.annotations.*;
+import org.studiox.graph.persistence.model.GraphEdgeDO;
+
+import java.util.List;
+
+public interface GraphEdgeDao {
+
+ @Select("select * from graph_edge")
+ @Results(
+ id = "graphEdgeDOMap",
+ value = {
+ @Result(id = true, column = "id", property = "id"),
+ @Result(column = "content", property = "content"),
+ @Result(column = "content_md5", property = "contentMd5"),
+ @Result(column = "type", property = "type"),
+ @Result(column = "owner", property = "owner"),
+ @Result(column = "source_vertex_uniq", property = "sourceVertexUniq"),
+ @Result(column = "target_vertex_uniq", property = "targetVertexUniq"),
+ @Result(column = "janus_edge_id", property = "janusEdgeId"),
+ @Result(column = "neo4j_edge_id", property = "neo4jEdgeId"),
+ @Result(column = "nebula_edge_id", property = "nebulaEdgeId"),
+ @Result(column = "source_janus_vertex_id", property = "sourceJanusVertexId"),
+ @Result(column = "target_janus_vertex_id", property = "targetJanusVertexId"),
+ @Result(column = "source_neo4j_vertex_id", property = "sourceNeo4jVertexId"),
+ @Result(column = "target_neo4j_vertex_id", property = "targetNeo4jVertexId"),
+ @Result(column = "source_nebula_vertex_id", property = "sourceNebulaVertexId"),
+ @Result(column = "target_nebula_vertex_id", property = "targetNebulaVertexId"),
+ @Result(column = "deleted", property = "deleted"),
+ @Result(column = "create_time", property = "createTime"),
+ @Result(column = "update_time", property = "updateTime")
+ })
+ List findAll();
+
+ @Insert(
+ "insert into graph_edge(content,type,owner,source_vertex_uniq,target_vertex_uniq,janus_edge_id,source_janus_vertex_id,target_janus_vertex_id) "
+ + "values (#{content},#{type},#{owner},#{sourceVertexUniq},#{targetVertexUniq},#{janusEdgeId},#{sourceJanusVertexId},#{targetJanusVertexId})")
+ void save(GraphEdgeDO graphEdgeDO);
+
+ @Update(
+ "update graph_edge set content=#{content},type=#{type},owner=#{owner},source_vertex_uniq=#{sourceVertexUniq},target_vertex_uniq=#{targetVertexUniq},janus_edge_id=#{janusEdgeId},"
+ + "source_janus_vertex_id=#{sourceJanusVertexId},target_janus_vertex_id=#{targetJanusVertexId},deleted=#{deleted},update_time=#{updateTime} where id=#{id}")
+ void update(GraphEdgeDO graphEdgeDO);
+
+ @Delete("delete from graph_edge where id=#{id}")
+ void delete(@Param("id") Long id);
+
+ @Select("select * from graph_edge where id=#{id}")
+ GraphEdgeDO findById(@Param("id") Long id);
+
+ @Select("select count(*) from graph_edge")
+ int findTotalNum();
+}
diff --git a/graph-persistence/persistence-mybatis/src/main/java/org/studiox/graph/persistence/mybatis/dao/GraphVertexDao.java b/graph-persistence/persistence-mybatis/src/main/java/org/studiox/graph/persistence/mybatis/dao/GraphVertexDao.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c17d4cad7beae4ebdcde83fd1d4165213bcff7b
--- /dev/null
+++ b/graph-persistence/persistence-mybatis/src/main/java/org/studiox/graph/persistence/mybatis/dao/GraphVertexDao.java
@@ -0,0 +1,46 @@
+package org.studiox.graph.persistence.mybatis.dao;
+
+import org.apache.ibatis.annotations.*;
+import org.studiox.graph.persistence.model.GraphVertexDO;
+
+import java.util.List;
+
+public interface GraphVertexDao {
+
+ @Select("select * from graph_vertex")
+ @Results(
+ id = "graphVertexDOMap",
+ value = {
+ @Result(id = true, column = "id", property = "id"),
+ @Result(column = "uniq", property = "uniq"),
+ @Result(column = "type", property = "type"),
+ @Result(column = "owner", property = "owner"),
+ @Result(column = "janus_vertex_id", property = "janusVertexId"),
+ @Result(column = "neo4j_vertex_id", property = "neo4jVertexId"),
+ @Result(column = "nebula_vertex_id", property = "nebulaVertexId"),
+ @Result(column = "temp", property = "temp"),
+ @Result(column = "deleted", property = "deleted"),
+ @Result(column = "create_time", property = "createTime"),
+ @Result(column = "update_time", property = "updateTime")
+ })
+ List findAll();
+
+ @Insert(
+ "insert into graph_vertex(uniq,type,owner,janus_vertex_id,temp) "
+ + "values (#{uniq},#{type},#{owner},#{janusVertexId},#{temp})")
+ void save(GraphVertexDO graphVertexDO);
+
+ @Update(
+ "update graph_vertex set uniq=#{uniq},type=#{type},owner=#{owner},janus_vertex_id=#{janusVertexId},"
+ + "temp=#{temp},deleted=#{deleted},update_time=#{updateTime} where id=#{id}")
+ void update(GraphVertexDO graphVertexDO);
+
+ @Delete("delete from graph_vertex where id=#{id}")
+ void delete(@Param("id") Long id);
+
+ @Select("select * from graph_vertex where id=#{id}")
+ GraphVertexDO findById(@Param("id") Long id);
+
+ @Select("select count(*) from graph_vertex")
+ int findTotalNum();
+}
diff --git a/graph-persistence/persistence-mybatis/src/test/java/org/studiox/graph/persistence/mybatis/test/MybatisTest.java b/graph-persistence/persistence-mybatis/src/test/java/org/studiox/graph/persistence/mybatis/test/MybatisTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f129679169c8f521c17ae4801d1564a221b3dca
--- /dev/null
+++ b/graph-persistence/persistence-mybatis/src/test/java/org/studiox/graph/persistence/mybatis/test/MybatisTest.java
@@ -0,0 +1,138 @@
+package org.studiox.graph.persistence.mybatis.test;
+
+import org.apache.ibatis.io.Resources;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.ibatis.session.SqlSessionFactoryBuilder;
+import org.junit.*;
+import org.junit.runners.MethodSorters;
+import org.studiox.graph.persistence.model.GraphEdgeDO;
+import org.studiox.graph.persistence.model.GraphVertexDO;
+import org.studiox.graph.persistence.mybatis.dao.GraphEdgeDao;
+import org.studiox.graph.persistence.mybatis.dao.GraphVertexDao;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class MybatisTest {
+
+ private static SqlSession session = null;
+
+ private static GraphVertexDao graphVertexDao;
+
+ private static GraphEdgeDao graphEdgeDao;
+
+ @BeforeClass
+ public static void init() {
+ InputStream inputStream = null;
+ try {
+ inputStream = Resources.getResourceAsStream("mybatis-config.xml");
+ SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
+ session = factory.openSession();
+ graphVertexDao = session.getMapper(GraphVertexDao.class);
+ graphEdgeDao = session.getMapper(GraphEdgeDao.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (null != inputStream) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ @AfterClass
+ public static void clean() {
+ if (null != session) {
+ session.commit();
+ session.close();
+ }
+ }
+
+ @Test
+ public void test1() {
+ List graphVertexDOs = graphVertexDao.findAll();
+ if (null != graphVertexDOs && graphVertexDOs.size() > 0) {
+ for (GraphVertexDO graphVertexDO : graphVertexDOs) {
+ graphVertexDao.delete(graphVertexDO.getId());
+ }
+ }
+ session.commit();
+ }
+
+ @Test
+ public void test2() {
+ GraphVertexDO graphVertexDO1 = new GraphVertexDO();
+ graphVertexDO1.setUniq("uniq1");
+ graphVertexDO1.setType("type1");
+ graphVertexDO1.setOwner("owner1");
+ graphVertexDO1.setJanusVertexId(1L);
+ graphVertexDO1.setTemp(true);
+ graphVertexDO1.setDeleted(false);
+ graphVertexDao.save(graphVertexDO1);
+
+ session.commit();
+
+ int count1 = graphVertexDao.findTotalNum();
+ Assert.assertEquals(1, count1);
+
+ List graphVertexDOs = graphVertexDao.findAll();
+ GraphVertexDO graphVertexDO2 = graphVertexDOs.get(0);
+ Long id = graphVertexDO2.getId();
+ graphVertexDO2.setUniq("uniq2");
+ graphVertexDao.update(graphVertexDO2);
+
+ session.commit();
+
+ GraphVertexDO graphVertexDO3 = graphVertexDao.findById(id);
+ Assert.assertEquals("uniq2", graphVertexDO3.getUniq());
+ Assert.assertEquals(true, graphVertexDO3.getTemp());
+ Assert.assertEquals(false, graphVertexDO3.getDeleted());
+ }
+
+ @Test
+ public void test3() {
+ List graphEdgeDOs = graphEdgeDao.findAll();
+ if (null != graphEdgeDOs && graphEdgeDOs.size() > 0) {
+ for (GraphEdgeDO graphEdgeDO : graphEdgeDOs) {
+ graphEdgeDao.delete(graphEdgeDO.getId());
+ }
+ }
+ session.commit();
+ }
+
+ @Test
+ public void test4() {
+ GraphEdgeDO graphEdgeDO1 = new GraphEdgeDO();
+ graphEdgeDO1.setContent("select * from sys.version");
+ graphEdgeDO1.setType("typq1");
+ graphEdgeDO1.setOwner("owner1");
+ graphEdgeDO1.setSourceVertexUniq("uniq1");
+ graphEdgeDO1.setTargetVertexUniq("uniq2");
+ graphEdgeDO1.setJanusEdgeId("edge1");
+ graphEdgeDO1.setSourceJanusVertexId(1L);
+ graphEdgeDO1.setTargetJanusVertexId(1L);
+ graphEdgeDao.save(graphEdgeDO1);
+
+ session.commit();
+
+ int count1 = graphEdgeDao.findTotalNum();
+ Assert.assertEquals(1, count1);
+
+ List graphEdgeDOs = graphEdgeDao.findAll();
+ GraphEdgeDO graphEdgeDO2 = graphEdgeDOs.get(0);
+ Long id = graphEdgeDO2.getId();
+ graphEdgeDO2.setContent("select 1 from sys.version");
+ graphEdgeDao.update(graphEdgeDO2);
+
+ session.commit();
+
+ GraphEdgeDO graphEdgeDO3 = graphEdgeDao.findById(id);
+ Assert.assertEquals("select 1 from sys.version", graphEdgeDO3.getContent());
+ }
+}
diff --git a/graph-persistence/persistence-mybatis/src/test/resources/jdbc.properties b/graph-persistence/persistence-mybatis/src/test/resources/jdbc.properties
new file mode 100644
index 0000000000000000000000000000000000000000..189dc13ead46c8f3eaa740157b8a9834d4f1ca2d
--- /dev/null
+++ b/graph-persistence/persistence-mybatis/src/test/resources/jdbc.properties
@@ -0,0 +1,13 @@
+# H2 Database
+#####################################
+jdbc.driver=org.h2.Driver
+jdbc.url=jdbc:h2:mem:test;MODE=MYSQL;DATABASE_TO_LOWER=FALSE;CASE_INSENSITIVE_IDENTIFIERS=TRUE;INIT=RUNSCRIPT FROM 'classpath:/mysql_ddl.sql'
+jdbc.username=root
+jdbc.password=123456
+#####################################
+# MySQL Database
+#jdbc.driver=com.mysql.jdbc.Driver
+#jdbc.url=jdbc:mysql://localhost:13306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
+#jdbc.username=root
+#jdbc.password=123456
+#####################################
diff --git a/graph-persistence/persistence-mybatis/src/test/resources/mybatis-config.xml b/graph-persistence/persistence-mybatis/src/test/resources/mybatis-config.xml
new file mode 100644
index 0000000000000000000000000000000000000000..48efec8089cc39f2900e2d9af4affab6b2e497b2
--- /dev/null
+++ b/graph-persistence/persistence-mybatis/src/test/resources/mybatis-config.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/graph-persistence/persistence-mybatis/src/test/resources/mysql_ddl.sql b/graph-persistence/persistence-mybatis/src/test/resources/mysql_ddl.sql
new file mode 100644
index 0000000000000000000000000000000000000000..48cc95eeb62d757e9fe145bcf22fb758fd4eb86c
--- /dev/null
+++ b/graph-persistence/persistence-mybatis/src/test/resources/mysql_ddl.sql
@@ -0,0 +1,53 @@
+create table if not exists `graph_vertex` (
+ `id` bigint(20) unsigned not null auto_increment comment '主键',
+ `uniq` varchar(255) not null default '' comment '顶点的唯一标识',
+ `type` varchar(20) not null default '' comment '顶点的类型',
+ `owner` varchar(50) not null default '' comment '所有者',
+ `janus_vertex_id` bigint(20) not null default 0 comment '顶点存储 JanusGraph Vertex Id',
+ `neo4j_vertex_id` bigint(20) not null default 0 comment '顶点存储 Neo4j Vertex Id',
+ `nebula_vertex_id` bigint(20) not null default 0 comment '顶点存储 NebulaGraph Vertex Id',
+ `temp` tinyint(1) not null default 0 comment '是否临时点(0:否 1:是),只存在数据库,不存在图中',
+ `deleted` tinyint(1) not null default 0 comment '是否删除(0:否 1:是)',
+ `create_time` timestamp not null default current_timestamp comment '顶点的创建时间',
+ `update_time` timestamp not null default current_timestamp comment '顶点的修改时间',
+ primary key (`id`),
+ unique key (`uniq`),
+ index (`janus_vertex_id`),
+ index (`neo4j_vertex_id`),
+ index (`nebula_vertex_id`)
+) engine=innodb auto_increment=1 default charset=utf8 comment='图中顶点集合';
+
+create table if not exists `graph_edge` (
+ `id` bigint(20) unsigned not null auto_increment comment '主键',
+ `content` mediumtext not null comment '边的记录内容',
+ `content_md5` char(32) not null default '' comment '边的记录内容MD5值',
+ `type` varchar(20) not null default '' comment '边的类型',
+ `owner` varchar(50) not null default '' comment '所有者',
+ `source_vertex_uniq` varchar(255) not null default '' comment '边的输入顶点的唯一标识',
+ `target_vertex_uniq` varchar(255) not null default '' comment '边的输出顶点的唯一标识',
+ `janus_edge_id` varchar(50) not null default '' comment '边存储 JanusGraph Edge Id',
+ `neo4j_edge_id` bigint(20) not null default 0 comment '边存储 Neo4j Edge Id',
+ `nebula_edge_id` varchar(50) not null default '' comment '边存储 NebulaGraph Edge Id',
+ `source_janus_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 JanusGraph Vertex Id',
+ `target_janus_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 JanusGraph Vertex Id',
+ `source_neo4j_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 Neo4j Vertex Id',
+ `target_neo4j_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 Neo4j Vertex Id',
+ `source_nebula_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 NebulaGraph Vertex Id',
+ `target_nebula_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 NebulaGraph Vertex Id',
+ `deleted` tinyint(1) not null default 0 comment '是否删除(0:否 1:是)',
+ `create_time` timestamp not null default current_timestamp comment '边的创建时间',
+ `update_time` timestamp not null default current_timestamp comment '边的修改时间',
+ primary key (`id`),
+ index (`content_md5`),
+ index (`source_vertex_uniq`),
+ index (`target_vertex_uniq`),
+ index (`janus_edge_id`),
+ index (`neo4j_edge_id`),
+ index (`nebula_edge_id`),
+ index (`source_janus_vertex_id`),
+ index (`target_janus_vertex_id`),
+ index (`source_neo4j_vertex_id`),
+ index (`target_neo4j_vertex_id`),
+ index (`source_nebula_vertex_id`),
+ index (`target_nebula_vertex_id`)
+) engine=innodb auto_increment=1 default charset=utf8 comment='图中边集合';
diff --git a/graph-persistence/persistence-spring-jdbc/pom.xml b/graph-persistence/persistence-spring-jdbc/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5dfe9a0f1862d544bab4a373dfb2ae8510d6af04
--- /dev/null
+++ b/graph-persistence/persistence-spring-jdbc/pom.xml
@@ -0,0 +1,40 @@
+
+
+ 4.0.0
+
+ org.studiox.graph
+ graph-persistence
+ 1.0.5-SNAPSHOT
+
+ org.studiox.graph.persistence
+ persistence-spring-jdbc
+ 1.0.5-SNAPSHOT
+ jar
+
+
+ junit
+ junit
+ test
+
+
+ ch.vorburger.mariaDB4j
+ mariaDB4j
+ test
+
+
+ mysql
+ mysql-connector-java
+ test
+
+
+ org.studiox.graph.persistence
+ persistence-model
+
+
+ org.springframework
+ spring-jdbc
+
+
+
diff --git a/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/dao/GraphEdgeDao.java b/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/dao/GraphEdgeDao.java
new file mode 100644
index 0000000000000000000000000000000000000000..649aa9d2ef639cec829b54c59d60fe6583aa6b8c
--- /dev/null
+++ b/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/dao/GraphEdgeDao.java
@@ -0,0 +1,20 @@
+package org.studiox.graph.persistence.spring.jdbc.dao;
+
+import org.studiox.graph.persistence.model.GraphEdgeDO;
+
+import java.util.List;
+
+public interface GraphEdgeDao {
+
+ List findAll();
+
+ int save(GraphEdgeDO graphEdgeDO);
+
+ int update(GraphEdgeDO graphEdgeDO);
+
+ int delete(Long id);
+
+ GraphEdgeDO findById(Long id);
+
+ int findTotalNum();
+}
diff --git a/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/dao/GraphVertexDao.java b/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/dao/GraphVertexDao.java
new file mode 100644
index 0000000000000000000000000000000000000000..f11807241af85e502b5bc7ba48fccfa8c2933fe7
--- /dev/null
+++ b/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/dao/GraphVertexDao.java
@@ -0,0 +1,20 @@
+package org.studiox.graph.persistence.spring.jdbc.dao;
+
+import org.studiox.graph.persistence.model.GraphVertexDO;
+
+import java.util.List;
+
+public interface GraphVertexDao {
+
+ List findAll();
+
+ int save(GraphVertexDO graphVertexDO);
+
+ int update(GraphVertexDO graphVertexDO);
+
+ int delete(Long id);
+
+ GraphVertexDO findById(Long id);
+
+ int findTotalNum();
+}
diff --git a/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/dao/impl/GraphEdgeDaoImpl.java b/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/dao/impl/GraphEdgeDaoImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..823d73f3c8787320a4998189effb3c76e16ccb86
--- /dev/null
+++ b/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/dao/impl/GraphEdgeDaoImpl.java
@@ -0,0 +1,86 @@
+package org.studiox.graph.persistence.spring.jdbc.dao.impl;
+
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.studiox.graph.persistence.model.GraphEdgeDO;
+import org.studiox.graph.persistence.spring.jdbc.dao.GraphEdgeDao;
+import org.studiox.graph.persistence.spring.jdbc.rowmapper.GraphEdgeDOMapper;
+
+import java.util.List;
+
+public class GraphEdgeDaoImpl implements GraphEdgeDao {
+
+ private JdbcTemplate jdbcTemplate;
+
+ public GraphEdgeDaoImpl(JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ @Override
+ public List findAll() {
+ String sql = "select * from graph_edge";
+ return jdbcTemplate.query(sql, new GraphEdgeDOMapper());
+ }
+
+ @Override
+ public int save(GraphEdgeDO graphEdgeDO) {
+ String sql =
+ "insert into graph_edge(content,type,owner,source_vertex_uniq,target_vertex_uniq,"
+ + "janus_edge_id,source_janus_vertex_id,target_janus_vertex_id) values (?,?,?,?,?,?,?,?)";
+ Object[] obj =
+ new Object[] {
+ graphEdgeDO.getContent(),
+ graphEdgeDO.getType(),
+ graphEdgeDO.getOwner(),
+ graphEdgeDO.getSourceVertexUniq(),
+ graphEdgeDO.getTargetVertexUniq(),
+ graphEdgeDO.getJanusEdgeId(),
+ graphEdgeDO.getSourceJanusVertexId(),
+ graphEdgeDO.getTargetJanusVertexId()
+ };
+ return jdbcTemplate.update(sql, obj);
+ }
+
+ @Override
+ public int update(GraphEdgeDO graphEdgeDO) {
+ String sql =
+ "update graph_edge set content=?,type=?,owner=?,source_vertex_uniq=?,target_vertex_uniq=?,"
+ + "janus_edge_id=?,source_janus_vertex_id=?,target_janus_vertex_id=?,deleted=?,update_time=? where id=?";
+ Object[] obj =
+ new Object[] {
+ graphEdgeDO.getContent(),
+ graphEdgeDO.getType(),
+ graphEdgeDO.getOwner(),
+ graphEdgeDO.getSourceVertexUniq(),
+ graphEdgeDO.getTargetVertexUniq(),
+ graphEdgeDO.getJanusEdgeId(),
+ graphEdgeDO.getSourceJanusVertexId(),
+ graphEdgeDO.getTargetJanusVertexId(),
+ graphEdgeDO.getDeleted(),
+ graphEdgeDO.getUpdateTime(),
+ graphEdgeDO.getId()
+ };
+ return jdbcTemplate.update(sql, obj);
+ }
+
+ @Override
+ public int delete(Long id) {
+ String sql = "delete from graph_edge where id=?";
+ return jdbcTemplate.update(sql, id);
+ }
+
+ @Override
+ public GraphEdgeDO findById(Long id) {
+ String sql = "select * from graph_edge where id=?";
+ return jdbcTemplate.queryForObject(sql, new GraphEdgeDOMapper(), id);
+ }
+
+ @Override
+ public int findTotalNum() {
+ String sql = "select count(*) from graph_edge";
+ return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> rs.getInt(1));
+ }
+}
diff --git a/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/dao/impl/GraphVertexDaoImpl.java b/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/dao/impl/GraphVertexDaoImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..0dd025c2a5880a25b8f2e5224df5cbfec662f707
--- /dev/null
+++ b/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/dao/impl/GraphVertexDaoImpl.java
@@ -0,0 +1,78 @@
+package org.studiox.graph.persistence.spring.jdbc.dao.impl;
+
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.studiox.graph.persistence.model.GraphVertexDO;
+import org.studiox.graph.persistence.spring.jdbc.dao.GraphVertexDao;
+import org.studiox.graph.persistence.spring.jdbc.rowmapper.GraphVertexDOMapper;
+
+import java.util.List;
+
+public class GraphVertexDaoImpl implements GraphVertexDao {
+
+ private JdbcTemplate jdbcTemplate;
+
+ public GraphVertexDaoImpl(JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ @Override
+ public List findAll() {
+ String sql = "select * from graph_vertex";
+ return jdbcTemplate.query(sql, new GraphVertexDOMapper());
+ }
+
+ @Override
+ public int save(GraphVertexDO graphVertexDO) {
+ String sql =
+ "insert into graph_vertex(uniq,type,owner,janus_vertex_id,temp) values (?,?,?,?,?)";
+ Object[] obj =
+ new Object[] {
+ graphVertexDO.getUniq(),
+ graphVertexDO.getType(),
+ graphVertexDO.getOwner(),
+ graphVertexDO.getJanusVertexId(),
+ graphVertexDO.getTemp()
+ };
+ return jdbcTemplate.update(sql, obj);
+ }
+
+ @Override
+ public int update(GraphVertexDO graphVertexDO) {
+ String sql =
+ "update graph_vertex set uniq=?,type=?,owner=?,janus_vertex_id=?,temp=?,deleted=?,update_time=? where id=?";
+ Object[] obj =
+ new Object[] {
+ graphVertexDO.getUniq(),
+ graphVertexDO.getType(),
+ graphVertexDO.getOwner(),
+ graphVertexDO.getJanusVertexId(),
+ graphVertexDO.getTemp(),
+ graphVertexDO.getDeleted(),
+ graphVertexDO.getUpdateTime(),
+ graphVertexDO.getId()
+ };
+ return jdbcTemplate.update(sql, obj);
+ }
+
+ @Override
+ public int delete(Long id) {
+ String sql = "delete from graph_vertex where id=?";
+ return jdbcTemplate.update(sql, id);
+ }
+
+ @Override
+ public GraphVertexDO findById(Long id) {
+ String sql = "select * from graph_vertex where id=?";
+ return jdbcTemplate.queryForObject(sql, new GraphVertexDOMapper(), id);
+ }
+
+ @Override
+ public int findTotalNum() {
+ String sql = "select count(*) from graph_vertex";
+ return jdbcTemplate.queryForObject(sql, (rs, rowNum) -> rs.getInt(1));
+ }
+}
diff --git a/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/rowmapper/GraphEdgeDOMapper.java b/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/rowmapper/GraphEdgeDOMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..891bb9064f661ecd4492b10f2b3e7c750c0ca64b
--- /dev/null
+++ b/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/rowmapper/GraphEdgeDOMapper.java
@@ -0,0 +1,35 @@
+package org.studiox.graph.persistence.spring.jdbc.rowmapper;
+
+import org.springframework.jdbc.core.RowMapper;
+import org.studiox.graph.persistence.model.GraphEdgeDO;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class GraphEdgeDOMapper implements RowMapper {
+
+ @Override
+ public GraphEdgeDO mapRow(ResultSet rs, int rowNum) throws SQLException {
+ GraphEdgeDO graphEdgeDO = new GraphEdgeDO();
+ graphEdgeDO.setId(rs.getLong("id"));
+ graphEdgeDO.setContent(rs.getString("content"));
+ graphEdgeDO.setContentMd5(rs.getString("content_md5"));
+ graphEdgeDO.setType(rs.getString("type"));
+ graphEdgeDO.setOwner(rs.getString("owner"));
+ graphEdgeDO.setSourceVertexUniq(rs.getString("source_vertex_uniq"));
+ graphEdgeDO.setTargetVertexUniq(rs.getString("target_vertex_uniq"));
+ graphEdgeDO.setJanusEdgeId(rs.getString("janus_edge_id"));
+ graphEdgeDO.setNeo4jEdgeId(rs.getLong("neo4j_edge_id"));
+ graphEdgeDO.setNebulaEdgeId(rs.getString("nebula_edge_id"));
+ graphEdgeDO.setSourceJanusVertexId(rs.getLong("source_janus_vertex_id"));
+ graphEdgeDO.setTargetJanusVertexId(rs.getLong("target_janus_vertex_id"));
+ graphEdgeDO.setSourceNeo4jVertexId(rs.getLong("source_neo4j_vertex_id"));
+ graphEdgeDO.setTargetNeo4jVertexId(rs.getLong("target_neo4j_vertex_id"));
+ graphEdgeDO.setSourceNebulaVertexId(rs.getLong("source_nebula_vertex_id"));
+ graphEdgeDO.setTargetNebulaVertexId(rs.getLong("target_nebula_vertex_id"));
+ graphEdgeDO.setDeleted(rs.getBoolean("deleted"));
+ graphEdgeDO.setCreateTime(rs.getTimestamp("create_time"));
+ graphEdgeDO.setUpdateTime(rs.getTimestamp("update_time"));
+ return graphEdgeDO;
+ }
+}
diff --git a/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/rowmapper/GraphVertexDOMapper.java b/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/rowmapper/GraphVertexDOMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..37d0c23e1256aedf6d00251ee30ec313ff689168
--- /dev/null
+++ b/graph-persistence/persistence-spring-jdbc/src/main/java/org/studiox/graph/persistence/spring/jdbc/rowmapper/GraphVertexDOMapper.java
@@ -0,0 +1,27 @@
+package org.studiox.graph.persistence.spring.jdbc.rowmapper;
+
+import org.springframework.jdbc.core.RowMapper;
+import org.studiox.graph.persistence.model.GraphVertexDO;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class GraphVertexDOMapper implements RowMapper {
+
+ @Override
+ public GraphVertexDO mapRow(ResultSet rs, int rowNum) throws SQLException {
+ GraphVertexDO graphVertexDO = new GraphVertexDO();
+ graphVertexDO.setId(rs.getLong("id"));
+ graphVertexDO.setUniq(rs.getString("uniq"));
+ graphVertexDO.setType(rs.getString("type"));
+ graphVertexDO.setOwner(rs.getString("owner"));
+ graphVertexDO.setJanusVertexId(rs.getLong("janus_vertex_id"));
+ graphVertexDO.setNeo4jVertexId(rs.getLong("neo4j_vertex_id"));
+ graphVertexDO.setNebulaVertexId(rs.getLong("nebula_vertex_id"));
+ graphVertexDO.setTemp(rs.getBoolean("temp"));
+ graphVertexDO.setDeleted(rs.getBoolean("deleted"));
+ graphVertexDO.setCreateTime(rs.getTimestamp("create_time"));
+ graphVertexDO.setUpdateTime(rs.getTimestamp("update_time"));
+ return graphVertexDO;
+ }
+}
diff --git a/graph-persistence/persistence-spring-jdbc/src/test/java/org/studiox/graph/persistence/spring/jdbc/test/SpringJdbcTest.java b/graph-persistence/persistence-spring-jdbc/src/test/java/org/studiox/graph/persistence/spring/jdbc/test/SpringJdbcTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..68fee8b1bc8fddcf5601a619f657c619daa1f249
--- /dev/null
+++ b/graph-persistence/persistence-spring-jdbc/src/test/java/org/studiox/graph/persistence/spring/jdbc/test/SpringJdbcTest.java
@@ -0,0 +1,155 @@
+package org.studiox.graph.persistence.spring.jdbc.test;
+
+import ch.vorburger.exec.ManagedProcessException;
+import ch.vorburger.mariadb4j.DB;
+import ch.vorburger.mariadb4j.DBConfigurationBuilder;
+import org.junit.*;
+import org.junit.runners.MethodSorters;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+import org.studiox.graph.persistence.model.GraphEdgeDO;
+import org.studiox.graph.persistence.model.GraphVertexDO;
+import org.studiox.graph.persistence.spring.jdbc.dao.GraphEdgeDao;
+import org.studiox.graph.persistence.spring.jdbc.dao.GraphVertexDao;
+import org.studiox.graph.persistence.spring.jdbc.dao.impl.GraphEdgeDaoImpl;
+import org.studiox.graph.persistence.spring.jdbc.dao.impl.GraphVertexDaoImpl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Properties;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class SpringJdbcTest {
+
+ private static DB db;
+
+ private static GraphVertexDao graphVertexDao;
+
+ private static GraphEdgeDao graphEdgeDao;
+
+ @BeforeClass
+ public static void init() {
+ DBConfigurationBuilder config = DBConfigurationBuilder.newBuilder();
+ config.setPort(13306);
+ config.setDeletingTemporaryBaseAndDataDirsOnShutdown(true);
+ try {
+ db = DB.newEmbeddedDB(config.build());
+ db.start();
+ db.source("mysql_ddl.sql", "test");
+ } catch (ManagedProcessException e) {
+ e.printStackTrace();
+ }
+
+ Properties properties = new Properties();
+ InputStream inputStream =
+ Thread.currentThread().getContextClassLoader().getResourceAsStream("jdbc.properties");
+ try {
+ properties.load(inputStream);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (null != inputStream) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
+ driverManagerDataSource.setDriverClassName(properties.getProperty("jdbc.driver"));
+ driverManagerDataSource.setUrl(properties.getProperty("jdbc.url"));
+ driverManagerDataSource.setUsername(properties.getProperty("jdbc.username"));
+ driverManagerDataSource.setPassword(properties.getProperty("jdbc.password"));
+
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(driverManagerDataSource);
+
+ graphVertexDao = new GraphVertexDaoImpl(jdbcTemplate);
+ graphEdgeDao = new GraphEdgeDaoImpl(jdbcTemplate);
+ }
+
+ @AfterClass
+ public static void clean() {
+ if (null != db) {
+ try {
+ db.stop();
+ } catch (ManagedProcessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Test
+ public void test1() {
+ List graphVertexDOs = graphVertexDao.findAll();
+ if (null != graphVertexDOs && graphVertexDOs.size() > 0) {
+ for (GraphVertexDO graphVertexDO : graphVertexDOs) {
+ graphVertexDao.delete(graphVertexDO.getId());
+ }
+ }
+ }
+
+ @Test
+ public void test2() {
+ GraphVertexDO graphVertexDO1 = new GraphVertexDO();
+ graphVertexDO1.setUniq("uniq1");
+ graphVertexDO1.setType("type1");
+ graphVertexDO1.setOwner("owner1");
+ graphVertexDO1.setJanusVertexId(1L);
+ graphVertexDO1.setTemp(true);
+ graphVertexDO1.setDeleted(false);
+ graphVertexDao.save(graphVertexDO1);
+
+ int count1 = graphVertexDao.findTotalNum();
+ Assert.assertEquals(1, count1);
+
+ List graphVertexDOs = graphVertexDao.findAll();
+ GraphVertexDO graphVertexDO2 = graphVertexDOs.get(0);
+ Long id = graphVertexDO2.getId();
+ graphVertexDO2.setUniq("uniq2");
+ graphVertexDao.update(graphVertexDO2);
+
+ GraphVertexDO graphVertexDO3 = graphVertexDao.findById(id);
+ Assert.assertEquals("uniq2", graphVertexDO3.getUniq());
+ Assert.assertEquals(true, graphVertexDO3.getTemp());
+ Assert.assertEquals(false, graphVertexDO3.getDeleted());
+ }
+
+ @Test
+ public void test3() {
+ List graphEdgeDOs = graphEdgeDao.findAll();
+ if (null != graphEdgeDOs && graphEdgeDOs.size() > 0) {
+ for (GraphEdgeDO graphEdgeDO : graphEdgeDOs) {
+ graphEdgeDao.delete(graphEdgeDO.getId());
+ }
+ }
+ }
+
+ @Test
+ public void test4() {
+ GraphEdgeDO graphEdgeDO1 = new GraphEdgeDO();
+ graphEdgeDO1.setContent("select * from sys.version");
+ graphEdgeDO1.setType("typq1");
+ graphEdgeDO1.setOwner("owner1");
+ graphEdgeDO1.setSourceVertexUniq("uniq1");
+ graphEdgeDO1.setTargetVertexUniq("uniq2");
+ graphEdgeDO1.setJanusEdgeId("edge1");
+ graphEdgeDO1.setSourceJanusVertexId(1L);
+ graphEdgeDO1.setTargetJanusVertexId(1L);
+ graphEdgeDao.save(graphEdgeDO1);
+
+ int count1 = graphEdgeDao.findTotalNum();
+ Assert.assertEquals(1, count1);
+
+ List graphEdgeDOs = graphEdgeDao.findAll();
+ GraphEdgeDO graphEdgeDO2 = graphEdgeDOs.get(0);
+ Long id = graphEdgeDO2.getId();
+ graphEdgeDO2.setContent("select 1 from sys.version");
+ graphEdgeDao.update(graphEdgeDO2);
+
+ GraphEdgeDO graphEdgeDO3 = graphEdgeDao.findById(id);
+ Assert.assertEquals("select 1 from sys.version", graphEdgeDO3.getContent());
+ }
+}
diff --git a/graph-persistence/persistence-spring-jdbc/src/test/resources/jdbc.properties b/graph-persistence/persistence-spring-jdbc/src/test/resources/jdbc.properties
new file mode 100644
index 0000000000000000000000000000000000000000..6431bc709ef22056bfa0f439f97fbe7b9079e15a
--- /dev/null
+++ b/graph-persistence/persistence-spring-jdbc/src/test/resources/jdbc.properties
@@ -0,0 +1,18 @@
+# H2 Database
+#####################################
+#jdbc.driver=org.h2.Driver
+#jdbc.url=jdbc:h2:mem:test;MODE=MYSQL;DATABASE_TO_LOWER=FALSE;CASE_INSENSITIVE_IDENTIFIERS=TRUE;INIT=RUNSCRIPT FROM 'classpath:/mysql_ddl.sql'
+#jdbc.username=root
+#jdbc.password=123456
+#####################################
+# MySQL Database
+jdbc.driver=com.mysql.jdbc.Driver
+jdbc.url=jdbc:mysql://localhost:13306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
+jdbc.username=root
+jdbc.password=
+#####################################
+# MySQL uses a test database by default, and a root user with no password is also a default.
+#####################################
+# ubuntu下缺少libncurses*
+# 解决方法:sudo apt-cache search libncurses* 搜索下,然后使用 sudo apt-get install $(libname) 安装即可
+#####################################
diff --git a/graph-persistence/persistence-spring-jdbc/src/test/resources/mysql_ddl.sql b/graph-persistence/persistence-spring-jdbc/src/test/resources/mysql_ddl.sql
new file mode 100644
index 0000000000000000000000000000000000000000..48cc95eeb62d757e9fe145bcf22fb758fd4eb86c
--- /dev/null
+++ b/graph-persistence/persistence-spring-jdbc/src/test/resources/mysql_ddl.sql
@@ -0,0 +1,53 @@
+create table if not exists `graph_vertex` (
+ `id` bigint(20) unsigned not null auto_increment comment '主键',
+ `uniq` varchar(255) not null default '' comment '顶点的唯一标识',
+ `type` varchar(20) not null default '' comment '顶点的类型',
+ `owner` varchar(50) not null default '' comment '所有者',
+ `janus_vertex_id` bigint(20) not null default 0 comment '顶点存储 JanusGraph Vertex Id',
+ `neo4j_vertex_id` bigint(20) not null default 0 comment '顶点存储 Neo4j Vertex Id',
+ `nebula_vertex_id` bigint(20) not null default 0 comment '顶点存储 NebulaGraph Vertex Id',
+ `temp` tinyint(1) not null default 0 comment '是否临时点(0:否 1:是),只存在数据库,不存在图中',
+ `deleted` tinyint(1) not null default 0 comment '是否删除(0:否 1:是)',
+ `create_time` timestamp not null default current_timestamp comment '顶点的创建时间',
+ `update_time` timestamp not null default current_timestamp comment '顶点的修改时间',
+ primary key (`id`),
+ unique key (`uniq`),
+ index (`janus_vertex_id`),
+ index (`neo4j_vertex_id`),
+ index (`nebula_vertex_id`)
+) engine=innodb auto_increment=1 default charset=utf8 comment='图中顶点集合';
+
+create table if not exists `graph_edge` (
+ `id` bigint(20) unsigned not null auto_increment comment '主键',
+ `content` mediumtext not null comment '边的记录内容',
+ `content_md5` char(32) not null default '' comment '边的记录内容MD5值',
+ `type` varchar(20) not null default '' comment '边的类型',
+ `owner` varchar(50) not null default '' comment '所有者',
+ `source_vertex_uniq` varchar(255) not null default '' comment '边的输入顶点的唯一标识',
+ `target_vertex_uniq` varchar(255) not null default '' comment '边的输出顶点的唯一标识',
+ `janus_edge_id` varchar(50) not null default '' comment '边存储 JanusGraph Edge Id',
+ `neo4j_edge_id` bigint(20) not null default 0 comment '边存储 Neo4j Edge Id',
+ `nebula_edge_id` varchar(50) not null default '' comment '边存储 NebulaGraph Edge Id',
+ `source_janus_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 JanusGraph Vertex Id',
+ `target_janus_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 JanusGraph Vertex Id',
+ `source_neo4j_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 Neo4j Vertex Id',
+ `target_neo4j_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 Neo4j Vertex Id',
+ `source_nebula_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 NebulaGraph Vertex Id',
+ `target_nebula_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 NebulaGraph Vertex Id',
+ `deleted` tinyint(1) not null default 0 comment '是否删除(0:否 1:是)',
+ `create_time` timestamp not null default current_timestamp comment '边的创建时间',
+ `update_time` timestamp not null default current_timestamp comment '边的修改时间',
+ primary key (`id`),
+ index (`content_md5`),
+ index (`source_vertex_uniq`),
+ index (`target_vertex_uniq`),
+ index (`janus_edge_id`),
+ index (`neo4j_edge_id`),
+ index (`nebula_edge_id`),
+ index (`source_janus_vertex_id`),
+ index (`target_janus_vertex_id`),
+ index (`source_neo4j_vertex_id`),
+ index (`target_neo4j_vertex_id`),
+ index (`source_nebula_vertex_id`),
+ index (`target_nebula_vertex_id`)
+) engine=innodb auto_increment=1 default charset=utf8 comment='图中边集合';
diff --git a/graph-persistence/pom.xml b/graph-persistence/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e0be971754f7de6815448b42f73693981f979d3f
--- /dev/null
+++ b/graph-persistence/pom.xml
@@ -0,0 +1,22 @@
+
+
+ 4.0.0
+
+ org.studiox
+ graph
+ 1.0.5-SNAPSHOT
+
+ org.studiox.graph
+ graph-persistence
+ 1.0.5-SNAPSHOT
+ pom
+
+ persistence-model
+ persistence-mybatis
+ persistence-mybatis-plus
+ persistence-mybatis-tk
+ persistence-spring-jdbc
+
+
diff --git a/graph-runtime/pom.xml b/graph-runtime/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4d7130e0ea18afda89ebff618192d1b2ea9ad918
--- /dev/null
+++ b/graph-runtime/pom.xml
@@ -0,0 +1,87 @@
+
+
+ 4.0.0
+
+ org.studiox
+ graph
+ 1.0.5-SNAPSHOT
+
+ org.studiox.graph
+ graph-runtime
+ 1.0.5-SNAPSHOT
+ jar
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ ch.vorburger.mariaDB4j
+ mariaDB4j
+
+
+ mysql
+ mysql-connector-java
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.studiox.graph.persistence
+ persistence-mybatis-tk
+
+
+ org.springdoc
+ springdoc-openapi-ui
+
+
+ org.studiox.graph.janusgraph
+ janusgraph-latest
+
+
+ junit
+ junit
+
+
+ com.google.guava
+ guava
+
+
+ org.codehaus.groovy
+ *
+
+
+
+
+ com.google.guava
+ guava
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+
+ false
+
+
+
+
+
diff --git a/graph-runtime/src/main/java/org/studiox/graph/runtime/GraphRuntimeServer.java b/graph-runtime/src/main/java/org/studiox/graph/runtime/GraphRuntimeServer.java
new file mode 100644
index 0000000000000000000000000000000000000000..6cd27f44c24d38e43f8d4160ef74a17e949138cc
--- /dev/null
+++ b/graph-runtime/src/main/java/org/studiox/graph/runtime/GraphRuntimeServer.java
@@ -0,0 +1,26 @@
+package org.studiox.graph.runtime;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+import org.studiox.graph.runtime.config.GraphBanner;
+import tk.mybatis.spring.annotation.MapperScan;
+
+@SpringBootApplication
+@MapperScan(basePackages = {"org.studiox.graph.persistence.mybatis.tk.mapper"})
+@ComponentScan(
+ basePackages = {
+ "org.studiox.graph.persistence.mybatis.tk.base",
+ "org.studiox.graph.persistence.mybatis.tk.domain",
+ "org.studiox.graph.persistence.mybatis.tk.dao",
+ "org.studiox.graph.persistence.mybatis.tk.service",
+ "org.studiox.graph.runtime"
+ })
+public class GraphRuntimeServer {
+
+ public static void main(String[] args) {
+ SpringApplication springApplication = new SpringApplication(GraphRuntimeServer.class);
+ springApplication.setBanner(new GraphBanner());
+ springApplication.run(args);
+ }
+}
diff --git a/graph-runtime/src/main/java/org/studiox/graph/runtime/config/GraphBanner.java b/graph-runtime/src/main/java/org/studiox/graph/runtime/config/GraphBanner.java
new file mode 100644
index 0000000000000000000000000000000000000000..c5776069023ce386cc5b23d4fe7d58d2446c6fc6
--- /dev/null
+++ b/graph-runtime/src/main/java/org/studiox/graph/runtime/config/GraphBanner.java
@@ -0,0 +1,28 @@
+package org.studiox.graph.runtime.config;
+
+import org.springframework.boot.Banner;
+import org.springframework.boot.ansi.AnsiColor;
+import org.springframework.boot.ansi.AnsiOutput;
+import org.springframework.core.env.Environment;
+
+import java.io.PrintStream;
+
+public class GraphBanner implements Banner {
+
+ private static final String BANNER =
+ " ____ _ _ _ __ __ ____ _ \n"
+ + " / ___|| |_ _ _ __| (_) ___\\ \\/ / / ___|_ __ __ _ _ __ | |__ \n"
+ + " \\___ \\| __| | | |/ _` | |/ _ \\\\ / | | _| '__/ _` | '_ \\| '_ \\ \n"
+ + " ___) | |_| |_| | (_| | | (_) / \\ | |_| | | | (_| | |_) | | | |\n"
+ + " |____/ \\__|\\__,_|\\__,_|_|\\___/_/\\_\\ \\____|_| \\__,_| .__/|_| |_|\n"
+ + " |_| ";
+
+ private static final String BANNER_SITE = "http://patorjk.com/software/taag";
+
+ private static final String PROJECT_SITE = "https://gitee.com/studiox/graph";
+
+ @Override
+ public void printBanner(Environment environment, Class> sourceClass, PrintStream printStream) {
+ printStream.println(AnsiOutput.toString(AnsiColor.GREEN, BANNER));
+ }
+}
diff --git a/graph-runtime/src/main/java/org/studiox/graph/runtime/config/RuntimeConfig.java b/graph-runtime/src/main/java/org/studiox/graph/runtime/config/RuntimeConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a0f2a76f0e199bc15612b972d1e43d16ed34c1f
--- /dev/null
+++ b/graph-runtime/src/main/java/org/studiox/graph/runtime/config/RuntimeConfig.java
@@ -0,0 +1,74 @@
+package org.studiox.graph.runtime.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class RuntimeConfig {
+
+ @Value("${graph.gremlin.enabled:false}")
+ private boolean graphGremlinEnabled;
+
+ @Value("${graph.gremlin.port:8082}")
+ private Integer graphGremlinPort;
+
+ @Value("${database.embedded.enabled:false}")
+ private boolean databaseEmbeddedEnabled;
+
+ @Value("${database.embedded.port:13306}")
+ private Integer databaseEmbeddedPort;
+
+ @Value("${database.embedded.file:mysql_ddl.sql}")
+ private String databaseEmbeddedFile;
+
+ @Value("${database.embedded.schema:test}")
+ private String databaseEmbeddedSchema;
+
+ public boolean isGraphGremlinEnabled() {
+ return graphGremlinEnabled;
+ }
+
+ public void setGraphGremlinEnabled(boolean graphGremlinEnabled) {
+ this.graphGremlinEnabled = graphGremlinEnabled;
+ }
+
+ public Integer getGraphGremlinPort() {
+ return graphGremlinPort;
+ }
+
+ public void setGraphGremlinPort(Integer graphGremlinPort) {
+ this.graphGremlinPort = graphGremlinPort;
+ }
+
+ public boolean isDatabaseEmbeddedEnabled() {
+ return databaseEmbeddedEnabled;
+ }
+
+ public void setDatabaseEmbeddedEnabled(boolean databaseEmbeddedEnabled) {
+ this.databaseEmbeddedEnabled = databaseEmbeddedEnabled;
+ }
+
+ public Integer getDatabaseEmbeddedPort() {
+ return databaseEmbeddedPort;
+ }
+
+ public void setDatabaseEmbeddedPort(Integer databaseEmbeddedPort) {
+ this.databaseEmbeddedPort = databaseEmbeddedPort;
+ }
+
+ public String getDatabaseEmbeddedFile() {
+ return databaseEmbeddedFile;
+ }
+
+ public void setDatabaseEmbeddedFile(String databaseEmbeddedFile) {
+ this.databaseEmbeddedFile = databaseEmbeddedFile;
+ }
+
+ public String getDatabaseEmbeddedSchema() {
+ return databaseEmbeddedSchema;
+ }
+
+ public void setDatabaseEmbeddedSchema(String databaseEmbeddedSchema) {
+ this.databaseEmbeddedSchema = databaseEmbeddedSchema;
+ }
+}
diff --git a/graph-runtime/src/main/java/org/studiox/graph/runtime/config/Swagger3Config.java b/graph-runtime/src/main/java/org/studiox/graph/runtime/config/Swagger3Config.java
new file mode 100644
index 0000000000000000000000000000000000000000..3899683783d2eac8da356ffb093d44f53c3bb002
--- /dev/null
+++ b/graph-runtime/src/main/java/org/studiox/graph/runtime/config/Swagger3Config.java
@@ -0,0 +1,45 @@
+package org.studiox.graph.runtime.config;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import org.springdoc.core.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class Swagger3Config {
+
+ @Bean
+ public OpenAPI graphOpenApi() {
+ return new OpenAPI()
+ .info(
+ new Info()
+ .title("Studiox Graph Runtime OpenAPI Docs")
+ .description("REST API powered by OpenAPI v3.0 (Swagger3)")
+ .version("1.0.0-SNAPSHOT"));
+ }
+
+ @Bean
+ public GroupedOpenApi systemApi() {
+ return GroupedOpenApi.builder()
+ .group("system")
+ .pathsToMatch("/studiox/api/graph/runtime/v1/system/**")
+ .build();
+ }
+
+ @Bean
+ public GroupedOpenApi graphApi() {
+ return GroupedOpenApi.builder()
+ .group("graph")
+ .pathsToMatch("/studiox/api/graph/runtime/v1/graph/**")
+ .build();
+ }
+
+ @Bean
+ public GroupedOpenApi lineageApi() {
+ return GroupedOpenApi.builder()
+ .group("lineage")
+ .pathsToMatch("/studiox/api/graph/runtime/v1/lineage/**")
+ .build();
+ }
+}
diff --git a/graph-runtime/src/main/java/org/studiox/graph/runtime/controller/GraphController.java b/graph-runtime/src/main/java/org/studiox/graph/runtime/controller/GraphController.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b07e72fda8f721baf08f685d25f93c605715dbe
--- /dev/null
+++ b/graph-runtime/src/main/java/org/studiox/graph/runtime/controller/GraphController.java
@@ -0,0 +1,44 @@
+package org.studiox.graph.runtime.controller;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.studiox.graph.runtime.service.GraphService;
+
+import java.util.List;
+
+@RestController
+@RequestMapping(value = "/studiox/api/graph/runtime/v1/graph")
+@Tag(name = "Graph API Interface", description = "Graph API 接口")
+public class GraphController {
+
+ @Autowired private GraphService graphService;
+
+ @RequestMapping(value = "/vertex", method = RequestMethod.POST)
+ public void addGraphVertex(@RequestParam(value = "unique", required = true) String unique) {
+ graphService.addGraphVertex(unique);
+ }
+
+ @RequestMapping(value = "/vertices", method = RequestMethod.GET)
+ public List getAllGraphVertexUniqueNames() {
+ return graphService.getAllGraphVertexUniqueNames();
+ }
+
+ @RequestMapping(value = "/edge", method = RequestMethod.POST)
+ public void addGraphEdge(
+ @RequestParam(value = "content", required = true) String content,
+ @RequestParam(value = "sourceUnique", required = true) String sourceUnique,
+ @RequestParam(value = "targetUnique", required = true) String targetUnique) {
+ graphService.addGraphEdge(content, sourceUnique, targetUnique);
+ }
+
+ @RequestMapping(value = "/edges", method = RequestMethod.GET)
+ public List getGraphEdgeContentsBySourceTargetUnique(
+ @RequestParam(value = "sourceUnique", required = true) String sourceUnique,
+ @RequestParam(value = "targetUnique", required = true) String targetUnique) {
+ return graphService.getGraphEdgeContentsBySourceTargetUnique(sourceUnique, targetUnique);
+ }
+}
diff --git a/graph-runtime/src/main/java/org/studiox/graph/runtime/controller/LineageController.java b/graph-runtime/src/main/java/org/studiox/graph/runtime/controller/LineageController.java
new file mode 100644
index 0000000000000000000000000000000000000000..ad1fc62ffb6ab9b7aa51e7e5b4e3e0ad3c3a1c8c
--- /dev/null
+++ b/graph-runtime/src/main/java/org/studiox/graph/runtime/controller/LineageController.java
@@ -0,0 +1,73 @@
+package org.studiox.graph.runtime.controller;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.studiox.graph.common.GraphLineage;
+import org.studiox.graph.runtime.service.GraphService;
+
+@RestController
+@RequestMapping(value = "/studiox/api/graph/runtime/v1/lineage")
+@Tag(name = "Lineage API Interface", description = "Lineage API 接口")
+public class LineageController {
+
+ @Autowired private GraphService graphRuntimeService;
+
+ @Operation(
+ summary = "查询血缘版本信息",
+ description = "根据指定条件查询并返回血缘版本信息",
+ parameters = {
+ @Parameter(
+ name = "version",
+ schema = @Schema(implementation = String.class),
+ description = "版本信息")
+ },
+ responses = {
+ @ApiResponse(
+ description = "返回查询结果",
+ content =
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = String.class))),
+ @ApiResponse(responseCode = "400", description = "返回 400 Error")
+ })
+ @RequestMapping(value = "/version", method = RequestMethod.GET)
+ public String getVersion(@RequestParam(value = "version", required = false) String version) {
+ return "Graph Runtime Server Version: " + version;
+ }
+
+ @RequestMapping(value = "/lineageInfo", method = RequestMethod.GET)
+ public GraphLineage getLineageInfo(
+ @RequestParam(value = "unique", required = true) String unique,
+ @RequestParam(value = "depth", required = false, defaultValue = "-1") Integer depth,
+ @RequestParam(value = "skipDeleted", required = false, defaultValue = "true")
+ Boolean skipDeleted) {
+ return graphRuntimeService.getLineage(unique, depth, skipDeleted);
+ }
+
+ @RequestMapping(value = "/impactInfo", method = RequestMethod.GET)
+ public GraphLineage getImpactInfo(
+ @RequestParam(value = "unique", required = true) String unique,
+ @RequestParam(value = "depth", required = false, defaultValue = "-1") Integer depth,
+ @RequestParam(value = "skipDeleted", required = false, defaultValue = "true")
+ Boolean skipDeleted) {
+ return graphRuntimeService.getImpact(unique, depth, skipDeleted);
+ }
+
+ @RequestMapping(value = "/fullLineageInfo", method = RequestMethod.GET)
+ public GraphLineage getFullLineageInfo(
+ @RequestParam(value = "unique", required = true) String unique,
+ @RequestParam(value = "depth", required = false, defaultValue = "-1") Integer depth,
+ @RequestParam(value = "skipDeleted", required = false, defaultValue = "true")
+ Boolean skipDeleted) {
+ return graphRuntimeService.getFullLineage(unique, depth, skipDeleted);
+ }
+}
diff --git a/graph-runtime/src/main/java/org/studiox/graph/runtime/controller/SystemController.java b/graph-runtime/src/main/java/org/studiox/graph/runtime/controller/SystemController.java
new file mode 100644
index 0000000000000000000000000000000000000000..4bd8dc90960e9d3e54d6d868250f1589e66f1c39
--- /dev/null
+++ b/graph-runtime/src/main/java/org/studiox/graph/runtime/controller/SystemController.java
@@ -0,0 +1,16 @@
+package org.studiox.graph.runtime.controller;
+
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping(value = "/studiox/api/graph/runtime/v1/system")
+public class SystemController {
+
+ @GetMapping(value = "/health", produces = MediaType.APPLICATION_JSON_VALUE)
+ public String health() {
+ return "The Sun Also Rises";
+ }
+}
diff --git a/graph-runtime/src/main/java/org/studiox/graph/runtime/service/GraphService.java b/graph-runtime/src/main/java/org/studiox/graph/runtime/service/GraphService.java
new file mode 100644
index 0000000000000000000000000000000000000000..67d971f1fa3979ab0c49ae81f594ecff7dfff26b
--- /dev/null
+++ b/graph-runtime/src/main/java/org/studiox/graph/runtime/service/GraphService.java
@@ -0,0 +1,140 @@
+package org.studiox.graph.runtime.service;
+
+import org.apache.commons.lang3.StringUtils;
+import org.janusgraph.core.JanusGraph;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.studiox.graph.common.GraphLineage;
+import org.studiox.graph.common.IGraphWrapper;
+import org.studiox.graph.common.exception.GraphException;
+import org.studiox.graph.janusgraph.latest.JanusGraphLatest;
+import org.studiox.graph.persistence.mybatis.tk.domain.GraphEdgeDO;
+import org.studiox.graph.persistence.mybatis.tk.domain.GraphVertexDO;
+import org.studiox.graph.persistence.mybatis.tk.service.GraphDbService;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.util.List;
+
+@Service
+public class GraphService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(GraphService.class);
+
+ private IGraphWrapper graphWrapper;
+
+ @Autowired private GraphDbService graphDbService;
+
+ @PostConstruct
+ public void init() {
+ try {
+ graphWrapper = new JanusGraphLatest(LOGGER);
+ graphWrapper.open();
+ } catch (GraphException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+
+ @PreDestroy
+ public void clean() {
+ if (null != graphWrapper) {
+ graphWrapper.close();
+ }
+ }
+
+ public JanusGraph getJanusGraphInstance() {
+ return ((JanusGraphLatest) graphWrapper).getJanusGraph();
+ }
+
+ public void addGraphVertex(String unique) {
+ if (StringUtils.isBlank(unique)) {
+ return;
+ }
+ Long vertexDbId = graphDbService.getGraphVertexIdByUniq(unique);
+ if (null != vertexDbId) {
+ return;
+ }
+ Long vertexGraphId = graphWrapper.createVertex(unique, null, null);
+ GraphVertexDO graphVertexDO = new GraphVertexDO();
+ graphVertexDO.setUniq(unique);
+ graphVertexDO.setJanusVertexId(vertexGraphId);
+ graphDbService.insertGraphVertex(graphVertexDO);
+ }
+
+ public List getAllGraphVertexUniqueNames() {
+ return graphDbService.getGraphVertexUniqs();
+ }
+
+ public void addGraphEdge(String content, String sourceUnique, String targetUnique) {
+ if (StringUtils.isBlank(content)
+ || StringUtils.isBlank(sourceUnique)
+ || StringUtils.isBlank(targetUnique)) {
+ return;
+ }
+ List contents = graphDbService.getGraphEdgeContents(sourceUnique, targetUnique);
+ if (null == contents || contents.isEmpty()) {
+ Long sourceVertexGraphId;
+ GraphVertexDO graphVertexDO = graphDbService.getGraphVertexDoByUniq(sourceUnique);
+ if (null == graphVertexDO) {
+ sourceVertexGraphId = graphWrapper.createVertexNotPreCheck(sourceUnique, null, null);
+ graphVertexDO = new GraphVertexDO();
+ graphVertexDO.setUniq(sourceUnique);
+ graphVertexDO.setJanusVertexId(sourceVertexGraphId);
+ graphDbService.insertGraphVertex(graphVertexDO);
+ } else {
+ sourceVertexGraphId = graphVertexDO.getJanusVertexId();
+ }
+ Long targetVertexGraphId;
+ graphVertexDO = graphDbService.getGraphVertexDoByUniq(targetUnique);
+ if (null == graphVertexDO) {
+ targetVertexGraphId = graphWrapper.createVertexNotPreCheck(targetUnique, null, null);
+ graphVertexDO = new GraphVertexDO();
+ graphVertexDO.setUniq(targetUnique);
+ graphVertexDO.setJanusVertexId(targetVertexGraphId);
+ graphDbService.insertGraphVertex(graphVertexDO);
+ } else {
+ targetVertexGraphId = graphVertexDO.getJanusVertexId();
+ }
+ String graphEdgeId =
+ graphWrapper.createEdgeNotPreCheck(
+ content, null, sourceVertexGraphId, targetVertexGraphId, null);
+ GraphEdgeDO graphEdgeDO = new GraphEdgeDO();
+ graphEdgeDO.setContent(content);
+ graphEdgeDO.setSourceVertexUniq(sourceUnique);
+ graphEdgeDO.setTargetVertexUniq(targetUnique);
+ graphEdgeDO.setJanusEdgeId(graphEdgeId);
+ graphEdgeDO.setSourceJanusVertexId(sourceVertexGraphId);
+ graphEdgeDO.setTargetJanusVertexId(targetVertexGraphId);
+ graphDbService.insertGraphEdge(graphEdgeDO);
+ graphDbService.updateGraphEdgeContentMd5(graphEdgeDO.getId());
+ } else if (!contents.contains(content)) {
+ GraphEdgeDO graphEdgeDO =
+ graphDbService.getOneGraphEdgeDoBySourceTargetUniq(sourceUnique, targetUnique);
+ graphEdgeDO.setId(null);
+ graphEdgeDO.setContent(content);
+ graphEdgeDO.setContentMd5(null);
+ graphEdgeDO.setCreateTime(null);
+ graphEdgeDO.setUpdateTime(null);
+ graphDbService.insertGraphEdge(graphEdgeDO);
+ }
+ }
+
+ public List getGraphEdgeContentsBySourceTargetUnique(
+ String sourceUnique, String targetUnique) {
+ return graphDbService.getGraphEdgeContents(sourceUnique, targetUnique);
+ }
+
+ public GraphLineage getImpact(String vertexUniq, Integer depth, boolean skipDeleted) {
+ return graphWrapper.getImpact(vertexUniq, depth, skipDeleted);
+ }
+
+ public GraphLineage getLineage(String vertexUniq, Integer depth, boolean skipDeleted) {
+ return graphWrapper.getLineage(vertexUniq, depth, skipDeleted);
+ }
+
+ public GraphLineage getFullLineage(String vertexUniq, Integer depth, boolean skipDeleted) {
+ return graphWrapper.getFullLineage(vertexUniq, depth, skipDeleted);
+ }
+}
diff --git a/graph-runtime/src/main/java/org/studiox/graph/runtime/service/GremlinService.java b/graph-runtime/src/main/java/org/studiox/graph/runtime/service/GremlinService.java
new file mode 100644
index 0000000000000000000000000000000000000000..423f7ab0ecb8a02db9e8090f3c672acd36179b23
--- /dev/null
+++ b/graph-runtime/src/main/java/org/studiox/graph/runtime/service/GremlinService.java
@@ -0,0 +1,43 @@
+package org.studiox.graph.runtime.service;
+
+import org.apache.tinkerpop.gremlin.server.GraphGremlinServer;
+import org.janusgraph.core.JanusGraph;
+import org.janusgraph.graphdb.server.JanusGraphSettings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.studiox.graph.runtime.config.RuntimeConfig;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+@Service
+public class GremlinService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(GremlinService.class);
+
+ @Autowired private RuntimeConfig runtimeConfig;
+
+ @Autowired private GraphService graphService;
+
+ private GraphGremlinServer graphGremlinServer;
+
+ @PostConstruct
+ public void init() {
+ if (runtimeConfig.isGraphGremlinEnabled()) {
+ JanusGraphSettings janusGraphSettings = GraphGremlinServer.createJanusGraphSettings();
+ janusGraphSettings.port = runtimeConfig.getGraphGremlinPort();
+ JanusGraph janusGraph = graphService.getJanusGraphInstance();
+ graphGremlinServer = new GraphGremlinServer(janusGraphSettings, janusGraph);
+ graphGremlinServer.start();
+ }
+ }
+
+ @PreDestroy
+ public void clean() {
+ if (runtimeConfig.isGraphGremlinEnabled() && null != graphGremlinServer) {
+ graphGremlinServer.stop();
+ }
+ }
+}
diff --git a/graph-runtime/src/main/java/org/studiox/graph/runtime/service/MariaDBService.java b/graph-runtime/src/main/java/org/studiox/graph/runtime/service/MariaDBService.java
new file mode 100644
index 0000000000000000000000000000000000000000..656a49f13fa852a0d88f12685485eed2bde9b7a0
--- /dev/null
+++ b/graph-runtime/src/main/java/org/studiox/graph/runtime/service/MariaDBService.java
@@ -0,0 +1,51 @@
+package org.studiox.graph.runtime.service;
+
+import ch.vorburger.exec.ManagedProcessException;
+import ch.vorburger.mariadb4j.DB;
+import ch.vorburger.mariadb4j.DBConfigurationBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.studiox.graph.runtime.config.RuntimeConfig;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+@Service
+public class MariaDBService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(MariaDBService.class);
+
+ @Autowired private RuntimeConfig runtimeConfig;
+
+ private DB db;
+
+ @PostConstruct
+ public void init() {
+ if (runtimeConfig.isDatabaseEmbeddedEnabled()) {
+ DBConfigurationBuilder config = DBConfigurationBuilder.newBuilder();
+ config.setPort(runtimeConfig.getDatabaseEmbeddedPort());
+ config.setDeletingTemporaryBaseAndDataDirsOnShutdown(true);
+ try {
+ db = DB.newEmbeddedDB(config.build());
+ db.start();
+ db.source(
+ runtimeConfig.getDatabaseEmbeddedFile(), runtimeConfig.getDatabaseEmbeddedSchema());
+ } catch (ManagedProcessException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ @PreDestroy
+ public void clean() {
+ if (null != db) {
+ try {
+ db.stop();
+ } catch (ManagedProcessException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+ }
+}
diff --git a/graph-runtime/src/main/resources/application.yml b/graph-runtime/src/main/resources/application.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2023a39b991671a5faf245830e0d058ad4cabb66
--- /dev/null
+++ b/graph-runtime/src/main/resources/application.yml
@@ -0,0 +1,61 @@
+server:
+ port: 8081
+ context-path: /
+ use-forward-headers: true
+ tomcat:
+ remote-ip-header: X-Real-IP
+ protocol-header: X-Forwarded-Proto
+
+graph:
+ gremlin:
+ enabled: true
+ port: 8082
+
+database:
+ embedded:
+ enabled: true
+ port: 13306
+ file: mysql_ddl.sql
+ schema: test
+
+spring:
+ output:
+ ansi:
+ enabled: ALWAYS
+ main:
+ lazy-initialization: false
+ http:
+ encoding:
+ force: true
+ enabled: true
+ charset: UTF-8
+ servlet:
+ multipart:
+ enabled: true
+ max-file-size: 100MB
+ max-request-size: 1000MB
+ datasource:
+ url: jdbc:mysql://localhost:13306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
+ username: root
+ password:
+ driver-class-name: com.mysql.jdbc.Driver
+ hikari:
+ pool-name: HikariCP
+ minimum-idle: 2
+ maximum-pool-size: 5
+ connection-test-query: SELECT 1
+ max-lifetime: 1800000
+ connection-timeout: 30000
+
+logging:
+ config: classpath:logback-console.xml
+ level:
+ root: INFO
+
+#默认为true开启
+springdoc:
+ api-docs:
+ path: /api-docs
+ enabled: true
+ swagger-ui:
+ path: /swagger
diff --git a/graph-runtime/src/main/resources/graph.properties b/graph-runtime/src/main/resources/graph.properties
new file mode 100755
index 0000000000000000000000000000000000000000..028881eac35990e8878e4f2500384c658aaa54f8
--- /dev/null
+++ b/graph-runtime/src/main/resources/graph.properties
@@ -0,0 +1,27 @@
+###################################################################
+graph.schema.default=none
+graph.storage.batch-loading=true
+###################################################################
+graph.cache.db-cache=false
+graph.ids.block-size=20000000
+graph.ids.renew-timeout=3600000
+graph.storage.buffer-size=20240
+###################################################################
+graph.gremlin.graph=org.janusgraph.core.JanusGraphFactory
+###################################################################
+graph.storage.backend=inmemory
+###################################################################
+#graph.storage.backend=hbase
+#graph.storage.hostname=localhost
+#graph.storage.hbase.table=graph_table_1
+#graph.storage.hbase.ext.zookeeper.znode.parent=/hbase1
+###################################################################
+#graph.storage.hbase.region-count=9
+#graph.storage.hbase.regions-per-server=3
+#graph.storage.hbase.ext.hbase.rpc.timeout=300000
+#graph.storage.hbase.ext.hbase.client.operation.timeout=300000
+#graph.storage.hbase.ext.hbase.client.scanner.timeout.period=300000
+###################################################################
+#graph.index.search.backend=elasticsearch
+#graph.index.search.hostname=localhost:9200
+###################################################################
diff --git a/graph-runtime/src/main/resources/logback-console.xml b/graph-runtime/src/main/resources/logback-console.xml
new file mode 100644
index 0000000000000000000000000000000000000000..79500aec47fc44c78423e34f609b432394f8900a
--- /dev/null
+++ b/graph-runtime/src/main/resources/logback-console.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+ [%d{yyyy-MM-dd HH:mm:ss.SSS}] [%level] [%thread] [%logger{50}] >>> [graph-runtime-server] msg=%msg%n
+
+
+
+
+
+
+
+
+
diff --git a/graph-runtime/src/main/resources/logback-file.xml b/graph-runtime/src/main/resources/logback-file.xml
new file mode 100644
index 0000000000000000000000000000000000000000..15aa764d86123936f96d013117569f1cb98021f8
--- /dev/null
+++ b/graph-runtime/src/main/resources/logback-file.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ ${log_dir}/graph-runtime-server.log
+
+ ${log_dir}/graph-runtime-server-%i.log
+ 1
+ 9
+
+
+ 100MB
+
+
+
+ [%d{yyyy-MM-dd HH:mm:ss.SSS}] [%level] [%thread] [%logger{50}] >>> [graph-runtime-server] msg=%msg%n
+
+
+
+
+
+
+
+
+
diff --git a/graph-runtime/src/main/resources/mysql_ddl.sql b/graph-runtime/src/main/resources/mysql_ddl.sql
new file mode 100644
index 0000000000000000000000000000000000000000..48cc95eeb62d757e9fe145bcf22fb758fd4eb86c
--- /dev/null
+++ b/graph-runtime/src/main/resources/mysql_ddl.sql
@@ -0,0 +1,53 @@
+create table if not exists `graph_vertex` (
+ `id` bigint(20) unsigned not null auto_increment comment '主键',
+ `uniq` varchar(255) not null default '' comment '顶点的唯一标识',
+ `type` varchar(20) not null default '' comment '顶点的类型',
+ `owner` varchar(50) not null default '' comment '所有者',
+ `janus_vertex_id` bigint(20) not null default 0 comment '顶点存储 JanusGraph Vertex Id',
+ `neo4j_vertex_id` bigint(20) not null default 0 comment '顶点存储 Neo4j Vertex Id',
+ `nebula_vertex_id` bigint(20) not null default 0 comment '顶点存储 NebulaGraph Vertex Id',
+ `temp` tinyint(1) not null default 0 comment '是否临时点(0:否 1:是),只存在数据库,不存在图中',
+ `deleted` tinyint(1) not null default 0 comment '是否删除(0:否 1:是)',
+ `create_time` timestamp not null default current_timestamp comment '顶点的创建时间',
+ `update_time` timestamp not null default current_timestamp comment '顶点的修改时间',
+ primary key (`id`),
+ unique key (`uniq`),
+ index (`janus_vertex_id`),
+ index (`neo4j_vertex_id`),
+ index (`nebula_vertex_id`)
+) engine=innodb auto_increment=1 default charset=utf8 comment='图中顶点集合';
+
+create table if not exists `graph_edge` (
+ `id` bigint(20) unsigned not null auto_increment comment '主键',
+ `content` mediumtext not null comment '边的记录内容',
+ `content_md5` char(32) not null default '' comment '边的记录内容MD5值',
+ `type` varchar(20) not null default '' comment '边的类型',
+ `owner` varchar(50) not null default '' comment '所有者',
+ `source_vertex_uniq` varchar(255) not null default '' comment '边的输入顶点的唯一标识',
+ `target_vertex_uniq` varchar(255) not null default '' comment '边的输出顶点的唯一标识',
+ `janus_edge_id` varchar(50) not null default '' comment '边存储 JanusGraph Edge Id',
+ `neo4j_edge_id` bigint(20) not null default 0 comment '边存储 Neo4j Edge Id',
+ `nebula_edge_id` varchar(50) not null default '' comment '边存储 NebulaGraph Edge Id',
+ `source_janus_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 JanusGraph Vertex Id',
+ `target_janus_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 JanusGraph Vertex Id',
+ `source_neo4j_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 Neo4j Vertex Id',
+ `target_neo4j_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 Neo4j Vertex Id',
+ `source_nebula_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 NebulaGraph Vertex Id',
+ `target_nebula_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 NebulaGraph Vertex Id',
+ `deleted` tinyint(1) not null default 0 comment '是否删除(0:否 1:是)',
+ `create_time` timestamp not null default current_timestamp comment '边的创建时间',
+ `update_time` timestamp not null default current_timestamp comment '边的修改时间',
+ primary key (`id`),
+ index (`content_md5`),
+ index (`source_vertex_uniq`),
+ index (`target_vertex_uniq`),
+ index (`janus_edge_id`),
+ index (`neo4j_edge_id`),
+ index (`nebula_edge_id`),
+ index (`source_janus_vertex_id`),
+ index (`target_janus_vertex_id`),
+ index (`source_neo4j_vertex_id`),
+ index (`target_neo4j_vertex_id`),
+ index (`source_nebula_vertex_id`),
+ index (`target_nebula_vertex_id`)
+) engine=innodb auto_increment=1 default charset=utf8 comment='图中边集合';
diff --git a/graph-runtime/src/main/resources/static/css/graphStyle.css b/graph-runtime/src/main/resources/static/css/graphStyle.css
new file mode 100644
index 0000000000000000000000000000000000000000..9eeb10b48b881b499137201fead75e8efe787913
--- /dev/null
+++ b/graph-runtime/src/main/resources/static/css/graphStyle.css
@@ -0,0 +1,80 @@
+.edge {
+ stroke: #999;
+ stroke-opacity: 0.8;
+}
+
+.old_edge0 {
+ stroke: #999;
+ stroke-opacity: 0.6;
+}
+
+.node circle {
+ stroke: #000;
+ stroke-width: 1.5px;
+}
+
+.node text {
+ font: 10px sans-serif;
+}
+
+.node:hover circle {
+ stroke-opacity: 0.6;
+}
+
+.pinned circle {
+ stroke: #000;
+ stroke-width: 1.5px;
+}
+
+.pinned text {
+ font: 10px sans-serif;
+}
+
+.pinned:hover circle {
+ stroke-opacity: 0.6;
+}
+
+.old_node0 circle {
+ stroke-opacity: 0.9;
+}
+
+.old_node0 text {
+ font: 10px sans-serif;
+ opacity: 0.9;
+ color: #000;/* Fallback for older browsers */
+ color: rgba(0,0,0,0.5);
+}
+
+.cell {
+ fill: none;
+ pointer-events: all;
+}
+
+.links line {
+ stroke: #999;
+ stroke-opacity: 0.6;
+}
+
+path {
+ fill: none;
+}
+
+/*
+
+.nodes circle {
+ stroke: #fff;
+ stroke-width: 1.5px;
+}
+
+.text1 text{
+ font: 10px sans-serif;
+}
+*/
+/*.table { border:0px solid black; padding:10px; width:1400px; overflow:hidden;border-spacing:0;border-collapse:collapse;}
+.left { float:left; width:960px; }
+.right { float:right; width:400px; }
+
+td, th {
+ padding: 1px 4px;
+}
+*/
\ No newline at end of file
diff --git a/graph-runtime/src/main/resources/static/css/styles.css b/graph-runtime/src/main/resources/static/css/styles.css
new file mode 100644
index 0000000000000000000000000000000000000000..fe7057c36f3461f0b62a9f4254b16cc541b562f4
--- /dev/null
+++ b/graph-runtime/src/main/resources/static/css/styles.css
@@ -0,0 +1,348 @@
+/* -----------------------
+Base styles
+------------------------*/
+
+body
+{
+ margin: 0;
+ padding: 0;
+ color: #333;
+ background-color: #eee;
+ font: 1em/1.2 "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif;
+ height: 100%;
+}
+
+h1,h2,h3,h4,h5,h6
+{
+ margin: 0 0 .5em;
+ font-weight: 500;
+ line-height: 1.1;
+}
+
+h1 { font-size: 2.25em; } /* 36px */
+h2 { font-size: 1.75em; } /* 28px */
+h3 { font-size: 1.375em; } /* 22px */
+h4 { font-size: 1.125em; } /* 18px */
+h5 { font-size: 1em; } /* 16px */
+h6 { font-size: .875em; } /* 14px */
+
+p
+{
+ margin: 0 0 1.5em;
+ line-height: 1.5;
+}
+
+blockquote
+{
+ padding: 1em 2em;
+ margin: 0 0 2em;
+ border-left: 5px solid #eee;
+}
+
+hr
+{
+ height: 0;
+ margin-top: 1em;
+ margin-bottom: 2em;
+ border: 0;
+ border-top: 1px solid #ddd;
+}
+
+table
+{
+ background-color: transparent;
+ border-spacing: 0;
+ border-collapse: collapse;
+ border-top: 1px solid #ddd;
+}
+
+th, td
+{
+ padding: .5em 1em;
+ vertical-align: top;
+ text-align: left;
+ border-bottom: 1px solid #ddd;
+}
+
+a:link { color: royalblue; }
+a:visited { color: purple; }
+a:focus { color: black; }
+a:hover { color: green; }
+a:active { color: red; }
+
+input[type="number"] {
+ width:50px;
+}
+
+/* -----------------------
+Layout styles
+------------------------*/
+
+.header
+{
+ color: #000;
+ background: #ddd;
+ padding: 0.2em 1.25em;
+}
+
+.header-heading { margin: 0; }
+
+.nav-bar
+{
+ color: #ddd;
+ background: #000;
+ padding: 0;
+}
+
+.container
+{
+ padding: 1em 1.25em;
+ margin: 0 auto;
+}
+
+.nav.container {
+ display: grid;
+ grid-template-rows: auto 15%;
+}
+
+.nav.inputs_container_top {
+ grid-row: 1 / 2;
+ display: grid;
+ grid-template-columns: auto auto auto auto auto;
+ grid-auto-flow: row;
+}
+
+.nav.inputs_container_bottom {
+ grid-row: 1 / 2;
+ display: grid;
+ grid-template-columns: auto auto auto auto;
+ grid-auto-flow: row;
+}
+.nav.input_unit_container {
+ padding: 5px;
+ align-self: center;
+}
+
+.nav.input_label {
+ white-space:nowrap;
+}
+
+.nav.controls {
+ grid-row: 1 / span 3;
+ justify-self: center;
+ align-self: center;
+}
+
+.content
+{
+ padding: 0em 0em;
+ background-color: #fff;
+ height: 80vh;
+}
+
+.main, .aside
+{
+ margin-bottom: 1em;
+ padding: 0em;
+ font: 12px sans-serif;
+}
+
+.main
+{
+ position: absolute;
+ left: 0;
+ width: 100%;
+ height: 80vh;
+}
+
+.left_bar
+{
+ position: absolute;
+ left: 0;
+ margin-left: 1em;
+ max-width: 275px;
+}
+
+.right_bar
+{
+ position: absolute;
+ right: 0;
+ margin-right: 1em;
+ max-width: 275px;
+}
+
+.footer
+{
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ color: #fff;
+ background: #000;
+}
+
+/* -----------------------
+Nav
+------------------------*/
+
+.nav
+{
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.nav li
+{
+ display: inline;
+ margin: 0;
+}
+
+.nav a
+{
+ display: block;
+ padding: .7em 1.25em;
+ color: #fff;
+ text-decoration: none;
+ border-bottom: 1px solid gray;
+}
+
+.nav a:link { color: white; }
+.nav a:visited { color: white; }
+
+.nav a:focus
+{
+ color: black;
+ background-color: white;
+}
+
+.nav a:hover
+{
+ color: white;
+ background-color: green;
+}
+
+.nav a:active
+{
+ color: white;
+ background-color: red;
+}
+
+/* -----------------------
+Side styles
+------------------------*/
+.aside li
+{
+ padding-left: 0;
+ margin-left: -5px;
+ list-style: none;
+}
+.aside div
+{
+ margin: 1em 0 1em 0;
+}
+/* -----------------------
+Single styles
+------------------------*/
+
+.img-responsive { max-width: 100%; }
+
+.btn
+{
+ color: #fff !important;
+ background-color: royalblue;
+ border-color: #222;
+ display: inline-block;
+ padding: .5em 1em;
+ margin-bottom: 0;
+ font-weight: 400;
+ line-height: 1.2;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ cursor: pointer;
+ border: 1px solid transparent;
+ border-radius: .2em;
+ text-decoration: none;
+}
+
+.btn:hover
+{
+ color: #fff !important;
+ background-color: green;
+}
+
+.btn:focus
+{
+ color: #fff !important;
+ background-color: black;
+}
+
+.btn:active
+{
+ color: #fff !important;
+ background-color: red;
+}
+
+.table
+{
+ width: 100%;
+ max-width: 100%;
+ margin-bottom: 20px;
+}
+
+.list-unstyled
+{
+ padding-left: 0;
+ list-style: none;
+}
+
+.list-inline
+{
+ padding-left: 0;
+ margin-left: -5px;
+ list-style: none;
+}
+
+.list-inline > li
+{
+ display: inline-block;
+ padding-right: 5px;
+ padding-left: 5px;
+}
+
+/* -----------------------
+Wide styles
+------------------------*/
+
+@media (min-width: 55em)
+{
+ .header { padding: 0.2em 3em; }
+ .nav-bar { padding: 0.5em 3em; }
+ .content { padding: 0em 0em; }
+
+ .main
+ {
+ margin-right: 0%;
+ margin-bottom: 1em;
+ }
+
+ .aside
+ {
+ float: left;
+ margin-bottom: 1em;
+ margin-top: 1em;
+ }
+
+ .nav li
+ {
+ display: inline;
+ margin: 0 1em 0 0;
+ }
+
+ .nav a
+ {
+ display: inline;
+ padding: 0;
+ border-bottom: 0;
+ }
+}
\ No newline at end of file
diff --git a/graph-runtime/src/main/resources/static/graph.html b/graph-runtime/src/main/resources/static/graph.html
new file mode 100644
index 0000000000000000000000000000000000000000..fde2d14fd24c7e01fccb03b71f526d52e36ee6c7
--- /dev/null
+++ b/graph-runtime/src/main/resources/static/graph.html
@@ -0,0 +1,438 @@
+
+
+
+
+
+ Graphexp, graph explorer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Get graph info
+ Show/hide graph info
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/graph-runtime/src/main/resources/static/scripts/editGraph.js b/graph-runtime/src/main/resources/static/scripts/editGraph.js
new file mode 100644
index 0000000000000000000000000000000000000000..70c81f174b2a07f8236be80f2a43b087690ed81a
--- /dev/null
+++ b/graph-runtime/src/main/resources/static/scripts/editGraph.js
@@ -0,0 +1,135 @@
+ function editGraph() {
+ var x = document.getElementById("editGraph")
+ if(x.style.display == "none"){
+ x.style.display = "block";
+ }
+ else{
+ x.style.display ="none" ;
+ }
+ document.getElementById("addVertexForm").style.display='none';
+ document.getElementById("editVertexForm").style.display='none';
+ document.getElementById("addEditEdgeForm").style.display='none';
+
+ }
+
+ function addVertexForm() {
+ document.getElementById("addVertexForm").style.display='block';
+ document.getElementById("editVertexForm").style.display='none';
+ document.getElementById("addEditEdgeForm").style.display='none';
+ }
+
+ function editVertexForm() {
+ document.getElementById("addVertexForm").style.display='none';
+ document.getElementById("editVertexForm").style.display='block';
+ document.getElementById("addEditEdgeForm").style.display='none';
+ }
+
+
+ function addEditEdgeForm() {
+ document.getElementById("addVertexForm").style.display='none';
+ document.getElementById("editVertexForm").style.display='none';
+ document.getElementById("addEditEdgeForm").style.display='block';
+
+ }
+
+ function addVertex() {
+
+ let vertexLabel = $('#vertexLabel').val();
+ let vertexPropertyName = $('#vertexPropertyName').val();
+ //vertexPropertyName = vertexPropertyName.replace(/\s/g,'');
+ let vertexPropertyValue = $('#vertexPropertyValue').val();
+ //vertexPropertyValue = vertexPropertyValue.replace(/\s/g,'');
+ propertyName = vertexPropertyName.split(",");
+ propertyValue = vertexPropertyValue.split(",");
+ var valueLen = propertyValue.length;
+ var nameLen = propertyName.length;
+ if(nameLen != valueLen){
+ alert("Please enter same number of property name and property value")
+ }
+ else{
+ document.getElementById('vertexLabel').value='';
+ document.getElementById('vertexPropertyName').value='';
+ document.getElementById('vertexPropertyValue').value='';
+ var gremlin_query = "g.addV('"+vertexLabel+"')"
+ for(count =0; count 0; k--) {
+ var kp = k - 1;
+ _svg.selectAll(".old_edge" + kp).classed("old_edge" + k, true);
+ _svg.selectAll(".old_node" + kp).classed("old_node" + k, true);
+ _svg.selectAll(".old_edgepath" + kp).classed("old_edgepath" + k, true);
+ _svg.selectAll(".old_edgelabel" + kp).classed("old_edgelabel" + k, true);
+ };
+ }
+
+ function clear_old() {
+ old_Nodes = [];
+ old_Links = [];
+ }
+
+ function update_data(d) {
+ // Save the data
+ var previous_nodes = _svg.selectAll("g").filter(".active_node");
+ var previous_nodes_data = previous_nodes.data();
+ old_Nodes = updateAdd(old_Nodes, previous_nodes_data);
+ var previous_links = _svg.selectAll(".active_edge");
+ var previous_links_data = previous_links.data();
+ old_Links = updateAdd(old_Links, previous_links_data);
+
+ // handle the pinned nodes
+ var pinned_Nodes = _svg.selectAll("g").filter(".pinned");
+ var pinned_nodes_data = pinned_Nodes.data();
+ // get the node data and merge it with the pinned nodes
+ _Nodes = d.nodes;
+ _Nodes = updateAdd(_Nodes, pinned_nodes_data);
+ // add coordinates to the new active nodes that already existed in the previous step
+ _Nodes = transfer_coordinates(_Nodes, old_Nodes);
+ // retrieve the links between nodes and pinned nodes
+ _Links = d.links.concat(previous_links_data); // first gather the links
+ _Links = find_active_links(_Links, _Nodes); // then find the ones that are between active nodes
+
+ // Sort links by source, then target, then label
+ // This is used to set linknum
+ _Links.sort(function (a, b) {
+ if (a.source > b.source) { return 1; }
+ else if (a.source < b.source) { return -1; }
+ else {
+ if (a.target > b.target) { return 1; }
+ if (a.target < b.target) { return -1; }
+ else {
+ if (a.label > b.label) { return 1; }
+ if (a.label < b.label) { return -1; }
+ else { return 0; }
+ }
+ }
+ });
+
+ // Any links with duplicate source and target get an incremented 'linknum'
+ for (var i = 0; i < _Links.length; i++) {
+ if (i != 0 &&
+ _Links[i].source == _Links[i - 1].source &&
+ _Links[i].target == _Links[i - 1].target) {
+ _Links[i].linknum = _Links[i - 1].linknum + 1;
+ }
+ else { _Links[i].linknum = 1; };
+ };
+ }
+
+ function updateAdd(array1, array2) {
+ // Update lines of array1 with the ones of array2 when the elements' id match
+ // and add elements of array2 to array1 when they do not exist in array1
+ var arraytmp = array2.slice(0);
+ var removeValFromIndex = [];
+ array1.forEach(function (d, index, thearray) {
+ for (var i = 0; i < arraytmp.length; i++) {
+ if (d.id == arraytmp[i].id) {
+ thearray[index] = arraytmp[i];
+ removeValFromIndex.push(i);
+ }
+ }
+ });
+ // remove the already updated values (in reverse order, not to mess up the indices)
+ removeValFromIndex.sort();
+ for (var i = removeValFromIndex.length - 1; i >= 0; i--)
+ arraytmp.splice(removeValFromIndex[i], 1);
+ return array1.concat(arraytmp);
+ }
+
+ function find_active_links(list_of_links, active_nodes) {
+ // find the links in the list_of_links that are between the active nodes and discard the others
+ var active_links = [];
+ list_of_links.forEach(function (row) {
+ for (var i = 0; i < active_nodes.length; i++) {
+ for (var j = 0; j < active_nodes.length; j++) {
+ if (active_nodes[i].id == row.source.id && active_nodes[j].id == row.target.id) {
+ var L_data = { source: row.source.id, target: row.target.id, type: row.type, value: row.value, id: row.id };
+ var L_data = row;
+ L_data['source'] = row.source.id;
+ L_data['target'] = row.target.id;
+ active_links = active_links.concat(L_data);
+ }
+ else if (active_nodes[i].id == row.source && active_nodes[j].id == row.target) {
+ var L_data = row;
+ active_links = active_links.concat(L_data);
+ }
+ }
+ }
+ });
+ // the active links are in active_links but there can be some duplicates
+ // remove duplicates links
+ var dic = {};
+ for (var i = 0; i < active_links.length; i++)
+ dic[active_links[i].id] = active_links[i]; // this will remove the duplicate links (with same id)
+ var list_of_active_links = [];
+ for (var key in dic)
+ list_of_active_links.push(dic[key]);
+ return list_of_active_links;
+ }
+
+
+ function transfer_coordinates(Nodes, old_Nodes) {
+ // Transfer coordinates from old_nodes to the new nodes with the same id
+ for (var i = 0; i < old_Nodes.length; i++) {
+ var exists = 0;
+ for (var j = 0; j < Nodes.length; j++) {
+ if (Nodes[j].id == old_Nodes[i].id) {
+ Nodes[j].x = old_Nodes[i].x;
+ Nodes[j].y = old_Nodes[i].y;
+ Nodes[j].fx = old_Nodes[i].x;
+ Nodes[j].fy = old_Nodes[i].y;
+ Nodes[j].vx = old_Nodes[i].vx;
+ Nodes[j].vy = old_Nodes[i].vy;
+ }
+ }
+ }
+ return Nodes;
+ }
+
+ function remove_duplicates(elem_class, elem_class_old) {
+ // Remove all the duplicate nodes and edges among the old_nodes and old_edges.
+ // A node or an edge can not be on several layers at the same time.
+ d3.selectAll(elem_class).each(function (d) {
+ var ID = d.id;
+ for (var n = 0; n < nb_layers; n++) {
+ var list_old_elements = d3.selectAll(elem_class_old + n);
+ //list_old_nodes_data = list_old_nodes.data();
+ list_old_elements.each(function (d) {
+ if (d.id == ID) {
+ d3.select(this).remove();
+ //console.log('Removed!!')
+ }
+ })
+ }
+ });
+ }
+
+ return {
+ set_nb_layers: set_nb_layers,
+ depth: depth,
+ push_layers: push_layers,
+ clear_old: clear_old,
+ update_data: update_data,
+ remove_duplicates: remove_duplicates
+ }
+ })();
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ function simulation_start(center_f) {
+ // Define the force applied to the nodes
+ _simulation = d3.forceSimulation()
+ .force("charge", d3.forceManyBody().strength(force_strength))
+ .force("link", d3.forceLink().strength(link_strength).id(function (d) { return d.id; }));
+
+ if (center_f == 1) {
+ var force_y = force_x_strength;
+ var force_x = force_y_strength;
+ _simulation.force("center", d3.forceCenter(_svg_width / 2, _svg_height / 2));
+ }
+ else {
+ var force_y = 0;
+ var force_x = 0;
+ }
+ _simulation.force("y", d3.forceY().strength(function (d) {
+ return force_y;
+ }))
+ .force("x", d3.forceX().strength(function (d) {
+ return force_x;
+ }));
+ return _simulation;
+ }
+
+
+
+ //////////////////////////////////////
+ function refresh_data(d, center_f, with_active_node) {
+ // Main visualization function
+ var svg_graph = svg_handle();
+ layers.push_layers();
+ layers.update_data(d);
+
+ //////////////////////////////////////
+ // link handling
+
+ //attach the data
+ var all_links = svg_graph.selectAll(".active_edge")
+ .data(_Links, function (d) { return d.id; });
+ var all_edgepaths = svg_graph.selectAll(".active_edgepath")
+ .data(_Links, function (d) { return d.id; });
+ var all_edgelabels = svg_graph.selectAll(".active_edgelabel")
+ .data(_Links, function (d) { return d.id; });
+
+ // links not active anymore are classified old_links
+ all_links.exit().classed("old_edge0", true).classed("active_edge", false);
+ all_edgepaths.exit().classed("old_edgepath0", true).classed("active_edgepath", false);
+ all_edgelabels.exit().classed("old_edgelabel0", true).classed("active_edgelabel", false);
+
+
+ // handling active links associated to the data
+ var edgepaths_e = all_edgepaths.enter(),
+ edgelabels_e = all_edgelabels.enter(),
+ link_e = all_links.enter();
+ var decor_out = graphShapes.decorate_link(link_e, edgepaths_e, edgelabels_e);
+ _links = decor_out[0];
+
+ var edgepaths = decor_out[1],
+ edgelabels = decor_out[2];
+
+
+ // previous links plus new links are merged
+ _links = _links.merge(all_links);
+ edgepaths = edgepaths.merge(all_edgepaths);
+ edgelabels = edgelabels.merge(all_edgelabels);
+
+ ///////////////////////////////////
+ // node handling
+
+ var all_nodes = svg_graph.selectAll("g").filter(".active_node")
+ .data(_Nodes, function (d) { return d.id; });
+
+ //console.log(data_node);
+ // old nodes not active any more are tagged
+ all_nodes.exit().classed("old_node0", true).classed("active_node", false);//;attr("class","old_node0");
+
+
+ // nodes associated to the data are constructed
+ _nodes = all_nodes.enter();
+
+ // add node decoration
+ var node_deco = graphShapes.decorate_node(_nodes, with_active_node);
+
+ var _nodes = node_deco.merge(all_nodes);
+
+
+ var focus_node_data = d3.select(".focus_node").data();
+ if (focus_node_data.length > 0){
+ infobox.display_info(focus_node_data[0]);
+ }
+ //////////////////////////////////
+ // Additional clean up
+ graphShapes.decorate_old_elements(layers.depth());
+ svg_graph.selectAll("g").filter(".pinned").moveToFront();
+
+
+ layers.remove_duplicates(".active_node", ".old_node");
+ layers.remove_duplicates(".active_edge", ".old_edge");
+ layers.remove_duplicates(".active_edgepath", ".old_edgepath");
+ layers.remove_duplicates(".active_edgelabel", ".old_edgelabel");
+
+
+ ///////////////////////////////
+ // Force simulation
+ // simulation model and parameters
+
+
+ _simulation = simulation_start(center_f);
+ // Associate the simulation with the data
+ _simulation.nodes(_Nodes).on("tick", ticked);
+ _simulation.force("link").links(_Links);
+ _simulation.alphaTarget(0);
+
+ ////////////////////////
+ // handling simulation steps
+ // move the nodes and links at each simulation step, following this rule:
+ function ticked() {
+ _links.attr('d', function (d) {
+ if (use_curved_edges) {
+ var dx = d.target.x - d.source.x;
+ var dy = d.target.y - d.source.y;
+ var dr = Math.sqrt((dx * dx + dy * dy) / d.linknum);
+ return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
+ } else {
+ return "M" + d.source.x + "," + d.source.y + "L" + d.target.x + "," + d.target.y;
+ }
+ });
+ _nodes
+ .attr("transform", function (d) { return "translate(" + d.x + ", " + d.y + ")"; });
+
+ edgepaths.attr('d', function (d) {
+ if (use_curved_edges) {
+ var dx = d.target.x - d.source.x;
+ var dy = d.target.y - d.source.y;
+ var dr = Math.sqrt((dx * dx + dy * dy) / d.linknum);
+ return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
+ } else {
+ return "M" + d.source.x + "," + d.source.y + "L" + d.target.x + "," + d.target.y;
+ }
+ });
+
+ edgelabels.attr('transform', function (d) {
+ if (d.target.x < d.source.x) {
+ var bbox = this.getBBox();
+
+ var rx = bbox.x + bbox.width / 2;
+ var ry = bbox.y + bbox.height / 2;
+ return 'rotate(180 ' + rx + ' ' + ry + ')';
+ }
+ else {
+ return 'rotate(0)';
+ }
+ });
+ }
+
+ }
+
+
+ function get_node_edges(node_id) {
+ // Return the in and out edges of node with id 'node_id'
+ var connected_edges = d3.selectAll(".edge").filter(
+ function (item) {
+ if (item.source == node_id || item.source.id == node_id) {
+ return item;
+ }
+ else if (item.target == node_id || item.target.id == node_id) {
+ return item;
+ }
+ });
+ return connected_edges;
+ }
+
+
+ var graph_events = (function () {
+ //////////////////////////////////
+ // Handling mouse events
+
+ function dragstarted(d) {
+ if (!d3.event.active) _simulation.alphaTarget(0.3).restart();
+ d.fx = d.x;
+ d.fy = d.y;
+ }
+
+ function dragged(d) {
+ var connected_edges = get_node_edges(d.id);
+ var f_connected_edges = connected_edges.filter("*:not(.active_edge)")
+ if (f_connected_edges._groups[0].length == 0) {
+ d.fx = d3.event.x;
+ d.fy = d3.event.y;
+ }
+ else {
+ f_connected_edges
+ .style("stroke-width", function () { return parseInt(d3.select(this).attr("stroke-width")) + 2; })
+ .style("stroke-opacity", 1)
+ .classed("blocking", true)
+ }
+ }
+
+ function dragended(d) {
+ if (!d3.event.active) _simulation.alphaTarget(0);
+ d3.selectAll(".blocking")
+ .style("stroke-width", function () { return d3.select(this).attr("stroke-width"); })
+ .style("stroke-opacity", function () { return d3.select(this).attr("stroke-opacity"); })
+ .classed("blocking", false)
+ // d.fx = null;
+ // d.fy = null;
+ }
+
+ function clicked(d) {
+ d3.select(".focus_node").remove();
+ var input = document.getElementById("freeze-in");
+ var isChecked = input.checked;
+ if (isChecked) infobox.display_info(d);
+ else {
+ _simulation.stop();
+ // remove the oldest links and nodes
+ var stop_layer = layers.depth() - 1;
+ _svg.selectAll(".old_node" + stop_layer).remove();
+ _svg.selectAll(".old_edge" + stop_layer).remove();
+ _svg.selectAll(".old_edgepath" + stop_layer).remove();
+ _svg.selectAll(".old_edgelabel" + stop_layer).remove();
+ graphioGremlin.click_query(d);
+ //infobox.display_info(d);
+ console.log('event!!')
+ }
+ }
+
+
+ function pin_it(d) {
+ d3.event.stopPropagation();
+ var node_pin = d3.select(this);
+ var pinned_node = d3.select(this.parentNode);
+ //console.log('Pinned!')
+ //console.log(pinned_node.classed("node"));
+ if (pinned_node.classed("active_node")) {
+ if (!pinned_node.classed("pinned")) {
+ pinned_node.classed("pinned", true);
+ console.log('Pinned!');
+ node_pin.attr("fill", "#000");
+ pinned_node.moveToFront();
+ }
+ else {
+ pinned_node.classed("pinned", false);
+ console.log('Unpinned!');
+ node_pin.attr("fill", graphShapes.node_color);
+ }
+ }
+ }
+
+ return {
+ dragstarted: dragstarted,
+ dragged: dragged,
+ dragended: dragended,
+ clicked: clicked,
+ pin_it: pin_it
+ }
+
+ })();
+
+ return {
+ svg_handle: svg_handle,
+ nodes: nodes,
+ links: links,
+ nodes_data: nodes_data,
+ node_data: node_data,
+ links_data: links_data,
+ init: init,
+ create_arrows: create_arrows,
+ addzoom: addzoom,
+ clear: clear,
+ get_simulation_handle: get_simulation_handle,
+ simulation_start: simulation_start,
+ refresh_data: refresh_data,
+ layers: layers,
+ graph_events: graph_events
+ };
+
+})();
diff --git a/graph-runtime/src/main/resources/static/scripts/graphioGremlin.js b/graph-runtime/src/main/resources/static/scripts/graphioGremlin.js
new file mode 100644
index 0000000000000000000000000000000000000000..0da934516c87c7fb8c5bb510e9b2e0839e52d327
--- /dev/null
+++ b/graph-runtime/src/main/resources/static/scripts/graphioGremlin.js
@@ -0,0 +1,647 @@
+/*
+Copyright 2017 Benjamin RICAUD
+
+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.
+*/
+
+// Interface between the visualization and the Gremlin server.
+
+var traversal_source = getUrlParameter('ts');
+if (traversal_source == null) {
+ traversal_source = "g"
+}
+
+var graphioGremlin = (function(){
+ "use strict";
+
+ var _node_properties = [];
+ var _edge_properties = [];
+
+
+ function get_node_properties(){
+ return _node_properties;
+ }
+ function get_edge_properties(){
+ return _edge_properties;
+ }
+
+ function create_single_command(query){
+ var equalIndex = query.indexOf("=");
+ var semiColonIndex = query.indexOf(";");
+ if( equalIndex >= 0){
+ if(semiColonIndex < 0){
+ query = query.substring(equalIndex+1);
+ } else {
+ query = query.substring(equalIndex+1,semiColonIndex);
+ }
+ }
+ var returnQuery = query.trim();
+// if(returnQuery.endsWith(".toList();")){
+// returnQuery = returnQuery+".toList();";
+// }
+ return returnQuery;
+ }
+
+ function get_graph_info(){
+ var gremlin_query_nodes = "nodes = " + traversal_source + ".V().limit(" + limit_graphinfo_request + ").groupCount().by(label);"
+ var gremlin_query_edges = "edges = " + traversal_source + ".E().limit(" + limit_graphinfo_request + ").groupCount().by(label);"
+ var gremlin_query_nodes_prop = "nodesprop = " + traversal_source + ".V().limit(" + limit_graphinfo_request + ").valueMap().select(keys).groupCount();"
+ var gremlin_query_edges_prop = "edgesprop = " + traversal_source + ".E().limit(" + limit_graphinfo_request + ").valueMap().select(keys).groupCount();"
+
+ var gremlin_query = gremlin_query_nodes+gremlin_query_nodes_prop
+ +gremlin_query_edges+gremlin_query_edges_prop
+ + "[nodes.toList(),nodesprop.toList(),edges.toList(),edgesprop.toList()]"
+ // while busy, show we're doing something in the messageArea.
+ $('#messageArea').html('(loading) ');
+ var message = ""
+ if(SINGLE_COMMANDS_AND_NO_VARS){
+ var node_label_query = create_single_command(gremlin_query_nodes);
+ var edge_label_query = create_single_command(gremlin_query_edges);
+ var node_prop_query = create_single_command(gremlin_query_nodes_prop);
+ var edge_prop_query = create_single_command(gremlin_query_edges_prop);
+ send_to_server(node_label_query, null, null, null, function(nodeLabels){
+ send_to_server(edge_label_query, null, null, null, function(edgeLabels){
+ send_to_server(node_prop_query, null, null, null, function(nodeProps){
+ send_to_server(edge_prop_query, null, null, null, function(edgeProps){
+ var combinedData = [nodeLabels, nodeProps, edgeLabels, edgeProps];
+ console.log("Combined data", combinedData);
+ handle_server_answer(combinedData,'graphInfo',null,message);
+ });
+ });
+ });
+ });
+ } else {
+ send_to_server(gremlin_query,'graphInfo',null,message)
+ }
+ }
+
+
+
+ function search_query() {
+ // Query sent to the server when clicking the search button
+ //
+ // Preprocess query
+ let input_string = $('#search_value').val();
+ let input_field = $('#search_field').val();
+ let label_field = $('#label_field').val();
+ let limit_field = $('#limit_field').val();
+ let search_type = $('#search_type').val();
+ let communication_method = $('#communication_method').val();
+ //console.log(input_field)
+ var filtered_string = input_string;//You may add .replace(/\W+/g, ''); to refuse any character not in the alphabet
+ if (filtered_string.length>50) filtered_string = filtered_string.substring(0,50); // limit string length
+ // Translate to Gremlin query
+ let has_str = "";
+ if (label_field !== "") {
+ has_str = ".hasLabel('" + label_field + "')";
+ }
+ if (input_field !== "" && input_string !== "") {
+ has_str += ".has('" + input_field + "',";
+ switch (search_type) {
+ case "eq":
+ if (isInt(input_string)){
+ has_str += filtered_string + ")"
+ } else {
+ has_str += "'" + filtered_string + "')"
+ }
+ break;
+ case "contains":
+ has_str += "textContains('" + filtered_string + "'))";
+ break;
+ }
+ } else if (limit_field === "" || limit_field < 0) {
+ limit_field = node_limit_per_request;
+ }
+
+ let gremlin_query_nodes = "nodes = " + traversal_source + ".V()" + has_str;
+ // Query limit
+ if (limit_field !== "" && isInt(limit_field) && limit_field > 0) {
+ gremlin_query_nodes += ".limit(" + limit_field + ")";
+ } else {
+ console.log('Warning: no node limit set for the query. The query may fail if the graph is too big.')
+ }
+ gremlin_query_nodes += ".toList();";
+
+ let gremlin_query_edges = "edges = " + traversal_source + ".V(nodes).aggregate('node').outE().as('edge').inV().where(within('node')).select('edge').toList();";
+ let gremlin_query_edges_no_vars = "edges = " + traversal_source + ".V()"+has_str+".aggregate('node').outE().as('edge').inV().where(within('node')).select('edge').toList();";
+ //let gremlin_query_edges_no_vars = "edges = " + traversal_source + ".V()"+has_str+".bothE();";
+ let gremlin_query = gremlin_query_nodes + gremlin_query_edges + "[nodes,edges]";
+ console.log(gremlin_query);
+
+ // while busy, show we're doing something in the messageArea.
+ $('#messageArea').html('(loading) ');
+ // To display the queries in the message area:
+ //var message_nodes = "Node query: '"+gremlin_query_nodes+"'
";
+ //var message_edges = "Edge query: '"+gremlin_query_edges+"'
";
+ //var message = message_nodes + message_edges;
+ var message = "";
+ if (SINGLE_COMMANDS_AND_NO_VARS) {
+ var nodeQuery = create_single_command(gremlin_query_nodes);
+ var edgeQuery = create_single_command(gremlin_query_edges_no_vars);
+ console.log("Node query: "+nodeQuery);
+ console.log("Edge query: "+edgeQuery);
+ send_to_server(nodeQuery, null, null, null, function(nodeData){
+ send_to_server(edgeQuery, null, null, null, function(edgeData){
+ var combinedData = [nodeData,edgeData];
+ handle_server_answer(combinedData, 'search', null, message);
+ });
+ });
+ } else {
+ send_to_server(gremlin_query,'search',null,message);
+ }
+ }
+
+ function isInt(value) {
+ return !isNaN(value) &&
+ parseInt(Number(value)) == value &&
+ !isNaN(parseInt(value, 10));
+ }
+ function click_query(d) {
+ // Query sent to the server when a node is clicked
+ //
+ var edge_filter = $('#edge_filter').val();
+ var communication_method = $('#communication_method').val();
+ var id = d.id;
+ if (typeof id === 'string' || id instanceof String) { // Add quotes if id is a string (not a number).
+ id = '"'+id+'"';
+ }
+ // Gremlin query
+ var gremlin_query_nodes = 'nodes = ' + traversal_source + '.V('+id+').as("node").both('+(edge_filter?'"'+edge_filter+'"':'')+').as("node").select(all,"node").unfold()'
+ // Variant depending on the Gremlin version
+ if (communication_method == "GraphSON3_4") {
+ // Version 3.4
+ gremlin_query_nodes += ".valueMap().with(WithOptions.tokens)";
+ gremlin_query_nodes += '.fold().inject(' + traversal_source + '.V(' + id + ').valueMap().with(WithOptions.tokens)).unfold()';
+ } else {
+ gremlin_query_nodes += '.fold().inject(' + traversal_source + '.V(' + id + ')).unfold()';
+ }
+ //var gremlin_query_nodes = 'nodes = ' + traversal_source + '.V('+id+').as("node").both('+(edge_filter?'"'+edge_filter+'"':'')+').as("node").select(all,"node").unfold().valueMap()'
+ //gremlin_query_nodes += 'fold().inject(' + traversal_source + '.V('+id+').valueMap()).unfold()'
+
+ // 'inject' is necessary in case of an isolated node ('both' would lead to an empty answer)
+ console.log('Query for the node and its neigbhors')
+ console.log(gremlin_query_nodes)
+ var gremlin_query_edges = "edges = " + traversal_source + ".V("+id+").bothE("+(edge_filter?"'"+edge_filter+"'":"")+")";
+ var gremlin_query = gremlin_query_nodes+'\n'+gremlin_query_edges+'\n'+'[nodes.toList(),edges.toList()]'
+ // while busy, show we're doing something in the messageArea.
+ $('#messageArea').html('(loading) ');
+ var message = "Query ID: "+ d.id +"
"
+ if(SINGLE_COMMANDS_AND_NO_VARS){
+ var nodeQuery = create_single_command(gremlin_query_nodes);
+ var edgeQuery = create_single_command(gremlin_query_edges);
+ send_to_server(nodeQuery, null, null, null, function(nodeData){
+ send_to_server(edgeQuery, null, null, null, function(edgeData){
+ var combinedData = [nodeData,edgeData];
+ handle_server_answer(combinedData, 'click', d.id, message);
+ });
+ });
+ } else {
+ send_to_server(gremlin_query,'click',d.id,message);
+ }
+ }
+
+ function send_to_server(gremlin_query,query_type,active_node,message, callback){
+
+ let server_address = $('#server_address').val();
+ let server_port = $('#server_port').val();
+ let COMMUNICATION_PROTOCOL = $('#server_protocol').val();
+ if (COMMUNICATION_PROTOCOL == 'REST'){
+ let server_url = ""
+ if(REST_USE_HTTPS){
+ server_url = "https://"+server_address+":"+server_port;
+ } else{
+ server_url = "http://"+server_address+":"+server_port;
+ }
+ run_ajax_request(gremlin_query,server_url,query_type,active_node,message,callback);
+ }
+ else if (COMMUNICATION_PROTOCOL == 'websocket'){
+ let server_url = "ws://"+server_address+":"+server_port+"/gremlin"
+ run_websocket_request(gremlin_query,server_url,query_type,active_node,message,callback);
+ }
+ else if (COMMUNICATION_PROTOCOL == 'websockets'){
+ let server_url = "wss://"+server_address+":"+server_port+"/gremlin"
+ run_websocket_request(gremlin_query,server_url,query_type,active_node,message,callback);
+ }
+ else {
+ console.log('Bad communication protocol. Check configuration file. Accept "REST" or "websocket" .')
+ }
+
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ // AJAX request for the REST API
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ function run_ajax_request(gremlin_query,server_url,query_type,active_node,message, callback){
+ // while busy, show we're doing something in the messageArea.
+ $('#messageArea').html('(loading) ');
+
+ // Get the data from the server
+ $.ajax({
+ type: "POST",
+ accept: "application/json",
+ //contentType:"application/json; charset=utf-8",
+ url: server_url,
+ //headers: GRAPH_DATABASE_AUTH,
+ timeout: REST_TIMEOUT,
+ data: JSON.stringify({"gremlin" : gremlin_query}),
+ success: function(data, textStatus, jqXHR){
+ var Data = data.result.data;
+ //console.log(Data)
+ //console.log("Results received")
+ if(callback){
+ callback(Data);
+ } else {
+ handle_server_answer(Data,query_type,active_node,message);
+ }
+ },
+ error: function(result, status, error){
+ console.log("Connection failed. "+status);
+
+ // This will hold all error messages, to be printed in the
+ // output area.
+ let msgs = [];
+
+ if (query_type == 'editGraph'){
+ msgs.push('Problem accessing the database using REST at ' + server_url);
+ msgs.push('Message: ' + status + ', ' + error);
+ msgs.push('Possible cause: creating an edge with bad node ids ' +
+ '(linking nodes not existing in the DB).');
+ } else {
+ msgs.push('Can\'t access database using REST at ' + server_url);
+ msgs.push('Message: ' + status + ', ' + error);
+ msgs.push('Check the server configuration ' +
+ 'or try increasing the REST_TIMEOUT value in the config file.');
+ }
+
+ // If a MalformedQueryException is received, user might be
+ // trying to reach an Amazon Neptune DB. Point them to the
+ // config file as a probable cause.
+ if (result.status === 400
+ && SINGLE_COMMANDS_AND_NO_VARS === false
+ && result.hasOwnProperty('responseJSON')
+ && result.responseJSON.code === 'MalformedQueryException') {
+ msgs.push('If connecting to an Amazon Neptune databse, ensure that ' +
+ 'SINGLE_COMMANDS_AND_NO_VARS is set to true in the config file.');
+ }
+
+ $('#outputArea').html(msgs.map(function (i) {return '' + i + '
'}).join(''));
+ $('#messageArea').html('');
+ }
+ });
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Websocket connection
+ /////////////////////////////////////////////////////////////////////////////////////////////////////
+ function run_websocket_request(gremlin_query,server_url,query_type,active_node,message,callback){
+ $('#messageArea').html('(loading) ');
+
+ var msg = { "requestId": uuidv4(),
+ "op":"eval",
+ "processor":"",
+ "args":{"gremlin": gremlin_query,
+ "bindings":{},
+ "language":"gremlin-groovy"}}
+
+ var data = JSON.stringify(msg);
+
+ var ws = new WebSocket(server_url);
+ ws.onopen = function (event){
+ ws.send(data,{ mask: true});
+ };
+ ws.onerror = function (err){
+ console.log('Connection error using websocket');
+ console.log(err);
+ if (query_type == 'editGraph'){
+ $('#outputArea').html(" Connection error using websocket
"
+ +" Problem accessing "+server_url+ "
"+
+ " Possible cause: creating a edge with bad node ids "+
+ "(linking nodes not existing in the DB).
");
+ $('#messageArea').html('');
+ } else {$('#outputArea').html(" Connection error using websocket
"
+ +" Cannot connect to "+server_url+ "
");
+ $('#messageArea').html('');
+ }
+
+ };
+ ws.onmessage = function (event){
+ var response = JSON.parse(event.data);
+ var code=Number(response.status.code)
+ if(!isInt(code) || code<200 || code>299) {
+ $('#outputArea').html(response.status.message);
+ $('#messageArea').html("Error retrieving data");
+ return 1;
+ }
+ var data = response.result.data;
+ if (data == null){
+ // No response data expected for flush query, so just validate status code.
+ if (query_type == 'flushGraph' && response.status.code == 204) {
+ $('#outputArea').html(" Successfully flushed existing DB data.
");
+ $('#messageArea').html('');
+ return
+ }
+
+ if (query_type == 'editGraph'){
+ $('#outputArea').html(response.status.message);
+ $('#messageArea').html('Could not write data to DB.' +
+ " Possible cause: creating a edge with bad node ids "+
+ "(linking nodes not existing in the DB).
");
+ return 1;
+ } else {
+ //$('#outputArea').html(response.status.message);
+ //$('#messageArea').html('Server error. No data.');
+ //return 1;
+ }
+ }
+ //console.log(data)
+ //console.log("Results received")
+ if(callback){
+ callback(data);
+ } else {
+ handle_server_answer(data,query_type,active_node,message);
+ }
+ };
+ }
+
+ // Generate uuid for websocket requestId. Code found here:
+ // https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
+ function uuidv4() {
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+ var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
+ return v.toString(16);
+ });
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+ function handle_server_answer(data,query_type,active_node,message){
+ let COMMUNICATION_METHOD = $('#communication_method').val();
+ if (query_type == 'editGraph'){
+ //console.log(data)
+ $('#outputArea').html(" Data successfully written to the DB.
");
+ $('#messageArea').html('');
+ return // TODO handle answer to check if data has been written
+ }
+ //console.log(COMMUNICATION_METHOD)
+ if (COMMUNICATION_METHOD == 'GraphSON3' || COMMUNICATION_METHOD == 'GraphSON3_4'){
+ //console.log(data)
+ data = graphson3to1(data);
+ var arrange_data = arrange_datav3;
+ } else if (COMMUNICATION_METHOD == 'GraphSON2'){
+ var arrange_data = arrange_datav2;
+ } else {
+ console.log('Bad communication protocol. Accept "GraphSON2" or "GraphSON3".'
+ +' Using default GraphSON3.')
+ data = graphson3to1(data);
+ var arrange_data = arrange_datav3;
+ }
+ if (!(0 in data)) {
+ message = 'No data. Check the communication protocol. (Try changing Gremlin version to 3.3.*).'
+ console.log(message)
+ $('#outputArea').html(message);
+ $('#messageArea').html('');
+
+ }
+ if (query_type=='graphInfo'){
+ infobox.display_graph_info(data);
+ _node_properties = make_properties_list(data[1][0]);
+ _edge_properties = make_properties_list(data[3][0]);
+ change_nav_bar(_node_properties,_edge_properties);
+ display_properties_bar(_node_properties,'nodes','Node properties:');
+ display_properties_bar(_edge_properties,'edges','Edge properties:');
+ display_color_choice(_node_properties,'nodes','Node color by:');
+ } else {
+ //console.log(data);
+ var graph = arrange_data(data);
+ //console.log(graph)
+ if (query_type=='click') var center_f = 0; //center_f=0 mean no attraction to the center for the nodes
+ else if (query_type=='search') var center_f = 1;
+ else return;
+ graph_viz.refresh_data(graph,center_f,active_node);
+ }
+
+ $('#outputArea').html(message);
+ $('#messageArea').html('');
+ }
+
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+ function make_properties_list(data){
+ var prop_dic = {};
+ for (var prop_str in data){
+ prop_str = prop_str.replace(/[\[\ \"\'\]]/g,''); // get rid of symbols [,",',] and spaces
+ var prop_list = prop_str.split(',');
+ //prop_list = prop_list.map(function (e){e=e.slice(1); return e;});
+ for (var prop_idx in prop_list){
+ prop_dic[prop_list[prop_idx]] = 0;
+ }
+ }
+ var properties_list = [];
+ for (var key in prop_dic){
+ properties_list.push(key);
+ }
+ return properties_list;
+ }
+
+ ///////////////////////////////////////////////////
+ function idIndex(list,elem) {
+ // find the element in list with id equal to elem
+ // return its index or null if there is no
+ for (var i=0;i response =
+ testRestTemplate.getForEntity(
+ base.toString() + "/studiox/api/graph/runtime/v1/lineage/version?version={1}",
+ String.class,
+ paramTestValue);
+ Assertions.assertEquals("Graph Runtime Server Version: " + paramTestValue, response.getBody());
+ }
+}
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ca66a7f4ab9e9c01f63965f648d9c3ca2bca30d1
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,331 @@
+
+
+ 4.0.0
+ org.studiox
+ graph
+ 1.0.5-SNAPSHOT
+ pom
+
+
+ The Apache Software License, Version 2.0
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+ UTF-8
+ UTF-8
+ UTF-8
+ 1.8
+ 1.8
+ 1.8
+ 2.5.5
+ 5.3.10
+
+
+
+ ${releaseStagingId}
+ ${releaseRepoName}
+
+ ${releaseRepoUrl}
+
+
+ ${snapStagingId}
+ ${snapRepoName}
+
+ ${snapRepoUrl}
+
+
+
+ graph-common
+ graph-janusgraph
+ graph-nebulagraph
+ graph-neo4j
+ graph-persistence
+ graph-runtime
+
+
+
+
+ junit
+ junit
+ 4.13.2
+
+
+ commons-configuration
+ commons-configuration
+ 1.10
+
+
+ com.h2database
+ h2
+ 1.4.200
+
+
+
+ ch.vorburger.mariaDB4j
+ mariaDB4j
+ 2.4.0
+
+
+ mysql
+ mysql-connector-java
+ 5.1.49
+
+
+ org.mybatis
+ mybatis
+ 3.5.7
+
+
+ com.baomidou
+ mybatis-plus
+ 3.4.3.4
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ 3.4.3.4
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 2.2.0
+
+
+ tk.mybatis
+ mapper-spring-boot-starter
+ 2.1.5
+
+
+ org.springframework
+ spring-framework-bom
+ ${spring.framework.version}
+ pom
+ import
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring.boot.version}
+ pom
+ import
+
+
+ org.springdoc
+ springdoc-openapi-ui
+ 1.5.11
+
+
+ org.studiox.graph
+ graph-common
+ ${project.version}
+
+
+ org.studiox.graph.janusgraph
+ janusgraph-common
+ ${project.version}
+
+
+ org.studiox.graph.janusgraph
+ janusgraph-v0.2.0
+ ${project.version}
+
+
+ org.studiox.graph.janusgraph
+ janusgraph-latest
+ ${project.version}
+
+
+ org.studiox.graph.persistence
+ persistence-model
+ ${project.version}
+
+
+ org.studiox.graph.persistence
+ persistence-mybatis-tk
+ ${project.version}
+
+
+ com.google.guava
+ guava
+ 31.0.1-jre
+
+
+
+
+ src/main/java
+ target/classes
+ src/test/java
+ target/test-classes
+
+
+ src/main/resources
+
+ **/*
+
+ false
+
+
+
+
+ src/test/resources
+
+ **/*
+
+ false
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 2.5.5
+
+ ZIP
+
+
+
+
+ repackage
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ true
+ true
+ UTF-8
+ true
+ ${jdk.version}
+ ${jdk.version}
+ ${jdk.version}
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.22.2
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 3.2.0
+
+ test
+ compile
+ runtime
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.2.1
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.3.1
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 3.2.0
+
+
+ org.apache.maven.plugins
+ maven-clean-plugin
+ 3.1.0
+
+
+ org.apache.maven.plugins
+ maven-install-plugin
+ 2.5.2
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.2.4
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 3.3.0
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+ 2.8.2
+
+
+ org.apache.maven.plugins
+ maven-project-info-reports-plugin
+ 3.1.2
+
+
+ com.spotify
+ docker-maven-plugin
+ 1.2.2
+
+
+ pl.project13.maven
+ git-commit-id-plugin
+ 4.9.10
+
+
+ generate
+
+ revision
+
+
+
+
+ true
+ yyyy.MM.dd HH:mm:ss
+ true
+ true
+ false
+
+ false
+ false
+ 40
+
+
+
+
+ org.owasp
+ dependency-check-maven
+ 6.4.1
+
+
+
+ check
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ compile
+
+ jar-no-fork
+
+
+
+
+
+
+
diff --git a/scripts/build/build.sh b/scripts/build/build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9389d933e579f35a53297b057c276225d4dcc172
--- /dev/null
+++ b/scripts/build/build.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -ex
+
+export PROJECT_DIR=$(cd $(dirname $0);cd ..;cd ..;pwd)
+
+cd ${PROJECT_DIR}
+
+mvn clean install -DskipTests
diff --git a/scripts/build/dependency-check.sh b/scripts/build/dependency-check.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7aa13879b7a5a3a4b247ba9f2601d37d3f04d94e
--- /dev/null
+++ b/scripts/build/dependency-check.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -ex
+
+export PROJECT_DIR=$(cd $(dirname $0);cd ..;cd ..;pwd)
+
+cd ${PROJECT_DIR}
+
+mvn clean org.owasp:dependency-check-maven:check -DskipTests
diff --git a/scripts/build/dependency-tree.sh b/scripts/build/dependency-tree.sh
new file mode 100755
index 0000000000000000000000000000000000000000..1ce06c910dbe14a75c1bbdc810f28d9b241f8da3
--- /dev/null
+++ b/scripts/build/dependency-tree.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -ex
+
+export PROJECT_DIR=$(cd $(dirname $0);cd ..;cd ..;pwd)
+
+cd ${PROJECT_DIR}
+
+mvn verify dependency:tree dependency:analyze -DskipTests
diff --git a/scripts/build/deploy.sh b/scripts/build/deploy.sh
new file mode 100755
index 0000000000000000000000000000000000000000..1b11d90f527ca518b6de1edc77ef32b408bd04e3
--- /dev/null
+++ b/scripts/build/deploy.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -ex
+
+export PROJECT_DIR=$(cd $(dirname $0);cd ..;cd ..;pwd)
+
+cd ${PROJECT_DIR}
+
+mvn clean deploy -DskipTests -Dassembly.skipAssembly=true
diff --git a/scripts/build/license.sh b/scripts/build/license.sh
new file mode 100755
index 0000000000000000000000000000000000000000..698b5fcff905a0d529f382732bf8e7f6ef47e1f4
--- /dev/null
+++ b/scripts/build/license.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -ex
+
+export PROJECT_DIR=$(cd $(dirname $0);cd ..;cd ..;pwd)
+
+cd ${PROJECT_DIR}
+
+mvn clean project-info-reports:dependencies
diff --git a/scripts/build/test.sh b/scripts/build/test.sh
new file mode 100755
index 0000000000000000000000000000000000000000..35b298cd3658d0d23fd17f7ef72ff7a4badd9680
--- /dev/null
+++ b/scripts/build/test.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -ex
+
+export PROJECT_DIR=$(cd $(dirname $0);cd ..;cd ..;pwd)
+
+cd ${PROJECT_DIR}
+
+mvn clean test -Dmaven.test.failure.ignore=true
diff --git a/scripts/build/version.sh b/scripts/build/version.sh
new file mode 100755
index 0000000000000000000000000000000000000000..0d0886ad73b61b26b50ab87a5096c111a546f751
--- /dev/null
+++ b/scripts/build/version.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -ex
+
+export PROJECT_DIR=$(cd $(dirname $0);cd ..;cd ..;pwd)
+
+cd ${PROJECT_DIR}
+
+mvn versions:set -DnewVersion=$1
diff --git a/scripts/database/mysql_ddl.sql b/scripts/database/mysql_ddl.sql
new file mode 100644
index 0000000000000000000000000000000000000000..48cc95eeb62d757e9fe145bcf22fb758fd4eb86c
--- /dev/null
+++ b/scripts/database/mysql_ddl.sql
@@ -0,0 +1,53 @@
+create table if not exists `graph_vertex` (
+ `id` bigint(20) unsigned not null auto_increment comment '主键',
+ `uniq` varchar(255) not null default '' comment '顶点的唯一标识',
+ `type` varchar(20) not null default '' comment '顶点的类型',
+ `owner` varchar(50) not null default '' comment '所有者',
+ `janus_vertex_id` bigint(20) not null default 0 comment '顶点存储 JanusGraph Vertex Id',
+ `neo4j_vertex_id` bigint(20) not null default 0 comment '顶点存储 Neo4j Vertex Id',
+ `nebula_vertex_id` bigint(20) not null default 0 comment '顶点存储 NebulaGraph Vertex Id',
+ `temp` tinyint(1) not null default 0 comment '是否临时点(0:否 1:是),只存在数据库,不存在图中',
+ `deleted` tinyint(1) not null default 0 comment '是否删除(0:否 1:是)',
+ `create_time` timestamp not null default current_timestamp comment '顶点的创建时间',
+ `update_time` timestamp not null default current_timestamp comment '顶点的修改时间',
+ primary key (`id`),
+ unique key (`uniq`),
+ index (`janus_vertex_id`),
+ index (`neo4j_vertex_id`),
+ index (`nebula_vertex_id`)
+) engine=innodb auto_increment=1 default charset=utf8 comment='图中顶点集合';
+
+create table if not exists `graph_edge` (
+ `id` bigint(20) unsigned not null auto_increment comment '主键',
+ `content` mediumtext not null comment '边的记录内容',
+ `content_md5` char(32) not null default '' comment '边的记录内容MD5值',
+ `type` varchar(20) not null default '' comment '边的类型',
+ `owner` varchar(50) not null default '' comment '所有者',
+ `source_vertex_uniq` varchar(255) not null default '' comment '边的输入顶点的唯一标识',
+ `target_vertex_uniq` varchar(255) not null default '' comment '边的输出顶点的唯一标识',
+ `janus_edge_id` varchar(50) not null default '' comment '边存储 JanusGraph Edge Id',
+ `neo4j_edge_id` bigint(20) not null default 0 comment '边存储 Neo4j Edge Id',
+ `nebula_edge_id` varchar(50) not null default '' comment '边存储 NebulaGraph Edge Id',
+ `source_janus_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 JanusGraph Vertex Id',
+ `target_janus_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 JanusGraph Vertex Id',
+ `source_neo4j_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 Neo4j Vertex Id',
+ `target_neo4j_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 Neo4j Vertex Id',
+ `source_nebula_vertex_id` bigint(20) not null default 0 comment '边的输入顶点 NebulaGraph Vertex Id',
+ `target_nebula_vertex_id` bigint(20) not null default 0 comment '边的输出顶点 NebulaGraph Vertex Id',
+ `deleted` tinyint(1) not null default 0 comment '是否删除(0:否 1:是)',
+ `create_time` timestamp not null default current_timestamp comment '边的创建时间',
+ `update_time` timestamp not null default current_timestamp comment '边的修改时间',
+ primary key (`id`),
+ index (`content_md5`),
+ index (`source_vertex_uniq`),
+ index (`target_vertex_uniq`),
+ index (`janus_edge_id`),
+ index (`neo4j_edge_id`),
+ index (`nebula_edge_id`),
+ index (`source_janus_vertex_id`),
+ index (`target_janus_vertex_id`),
+ index (`source_neo4j_vertex_id`),
+ index (`target_neo4j_vertex_id`),
+ index (`source_nebula_vertex_id`),
+ index (`target_nebula_vertex_id`)
+) engine=innodb auto_increment=1 default charset=utf8 comment='图中边集合';