From 4588aa594d65351550dfc4899fd887495e6f277f Mon Sep 17 00:00:00 2001 From: Mahesh Kumar Gangula Date: Wed, 31 Mar 2021 21:59:51 +0530 Subject: [PATCH] Issue #SC-2263 refactor: neo4j-kernel-extension for transaction event generation. --- .gitignore | 2 + neo4j-extensions/.gitignore | 5 + neo4j-extensions/custom-procedures/.gitignore | 1 + neo4j-extensions/custom-procedures/pom.xml | 62 ++ .../neo4j/procedures/TraversalProc.java | 333 ++++++++++ .../learning-graph-extension/.gitignore | 1 + .../dependency-reduced-pom.xml | 46 ++ .../learning-graph-extension/pom.xml | 58 ++ .../src/main/resources/log4j2.xml | 37 ++ neo4j-extensions/pom.xml | 74 +++ .../transaction-event-handler/.gitignore | 1 + .../transaction-event-handler/README.md | 20 + .../transaction-event-handler/pom.xml | 98 +++ .../EkStepTransactionEventHandler.java | 41 ++ .../extension/ProcessTransactionData.java | 621 ++++++++++++++++++ ...ansactionEventHandlerExtensionFactory.java | 50 ++ .../extension/enums/AuditProperties.java | 5 + .../extension/enums/GraphDACParams.java | 17 + .../kernel/extension/enums/HeaderParam.java | 12 + .../extension/enums/SystemProperties.java | 17 + .../extension/utils/LogAsyncGraphEvent.java | 29 + ...4j.kernel.extension.KernelExtensionFactory | 1 + .../kernel/extension/RelationEnums.java | 8 + .../kernel/extension/TestNeo4JCluster.java | 269 ++++++++ .../extension/TestTransactionEvents.java | 261 ++++++++ .../src/test/resources/log4j2.xml | 39 ++ 26 files changed, 2108 insertions(+) create mode 100644 .gitignore create mode 100644 neo4j-extensions/.gitignore create mode 100644 neo4j-extensions/custom-procedures/.gitignore create mode 100644 neo4j-extensions/custom-procedures/pom.xml create mode 100644 neo4j-extensions/custom-procedures/src/main/java/org/sunbird/neo4j/procedures/TraversalProc.java create mode 100644 neo4j-extensions/learning-graph-extension/.gitignore create mode 100644 neo4j-extensions/learning-graph-extension/dependency-reduced-pom.xml create mode 100644 neo4j-extensions/learning-graph-extension/pom.xml create mode 100644 neo4j-extensions/learning-graph-extension/src/main/resources/log4j2.xml create mode 100644 neo4j-extensions/pom.xml create mode 100644 neo4j-extensions/transaction-event-handler/.gitignore create mode 100755 neo4j-extensions/transaction-event-handler/README.md create mode 100755 neo4j-extensions/transaction-event-handler/pom.xml create mode 100755 neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/EkStepTransactionEventHandler.java create mode 100644 neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/ProcessTransactionData.java create mode 100755 neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/RegisterTransactionEventHandlerExtensionFactory.java create mode 100644 neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/AuditProperties.java create mode 100644 neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/GraphDACParams.java create mode 100644 neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/HeaderParam.java create mode 100644 neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/SystemProperties.java create mode 100644 neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/utils/LogAsyncGraphEvent.java create mode 100755 neo4j-extensions/transaction-event-handler/src/main/resources/META-INF/services/org.neo4j.kernel.extension.KernelExtensionFactory create mode 100644 neo4j-extensions/transaction-event-handler/src/test/java/org/sunbird/kernel/extension/RelationEnums.java create mode 100644 neo4j-extensions/transaction-event-handler/src/test/java/org/sunbird/kernel/extension/TestNeo4JCluster.java create mode 100644 neo4j-extensions/transaction-event-handler/src/test/java/org/sunbird/kernel/extension/TestTransactionEvents.java create mode 100644 neo4j-extensions/transaction-event-handler/src/test/resources/log4j2.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9bea433 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +.DS_Store diff --git a/neo4j-extensions/.gitignore b/neo4j-extensions/.gitignore new file mode 100644 index 0000000..f39b555 --- /dev/null +++ b/neo4j-extensions/.gitignore @@ -0,0 +1,5 @@ +/target/ +.DS_Store +/.idea/ +*.iml +*.log diff --git a/neo4j-extensions/custom-procedures/.gitignore b/neo4j-extensions/custom-procedures/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/neo4j-extensions/custom-procedures/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/neo4j-extensions/custom-procedures/pom.xml b/neo4j-extensions/custom-procedures/pom.xml new file mode 100644 index 0000000..826613c --- /dev/null +++ b/neo4j-extensions/custom-procedures/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + + org.sunbird + custom-procedures + 1.1 + + + 3.0.4 + + + + + org.neo4j + neo4j + ${neo4j.version} + provided + + + + + + + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.3 + + + package + + shade + + + + + org.neo4j:* + org.apache.lucene:* + org.scala-lang:* + org.ow2.asm:* + org.parboiled:* + net.sf.opencsv:* + com.googlecode.concurrentlinkedhashmap:* + io.netty:* + + + + + + + + + \ No newline at end of file diff --git a/neo4j-extensions/custom-procedures/src/main/java/org/sunbird/neo4j/procedures/TraversalProc.java b/neo4j-extensions/custom-procedures/src/main/java/org/sunbird/neo4j/procedures/TraversalProc.java new file mode 100644 index 0000000..f4c45db --- /dev/null +++ b/neo4j-extensions/custom-procedures/src/main/java/org/sunbird/neo4j/procedures/TraversalProc.java @@ -0,0 +1,333 @@ +package org.sunbird.neo4j.procedures; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Stream; +import java.util.stream.Stream.Builder; + +import org.neo4j.graphdb.Direction; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.Label; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Path; +import org.neo4j.graphdb.PathExpander; +import org.neo4j.graphdb.Relationship; +import org.neo4j.graphdb.RelationshipType; +import org.neo4j.graphdb.ResourceIterator; +import org.neo4j.graphdb.traversal.BranchState; +import org.neo4j.graphdb.traversal.Evaluation; +import org.neo4j.graphdb.traversal.Evaluator; +import org.neo4j.graphdb.traversal.Evaluators; +import org.neo4j.graphdb.traversal.TraversalDescription; +import org.neo4j.graphdb.traversal.Uniqueness; +import org.neo4j.logging.Log; +import org.neo4j.procedure.Context; +import org.neo4j.procedure.Name; +import org.neo4j.procedure.Procedure; + +public class TraversalProc { + + public static final long BREADTH_FIRST_TRAVERSAL = 0; + public static final long DEPTH_FIRST_TRAVERSAL = 1; + + // This field declares that we need a GraphDatabaseService + // as context when any procedure in this class is invoked + @Context + public GraphDatabaseService db; + + // This gives us a log instance that outputs messages to the + // standard log, `neo4j.log` + @Context + public Log log; + + /** + * @param graphId + * @param startNodeIds + * @param traversal + * @param fromDepth + * @param toDepth + * @param endNodeIds + * @param endRelations + * @param uniqueness + * @param wordIds + * @param relationMap + * @param pathExpander + * + * @return + */ + @Procedure(value = "ekstep.procs.traverse") + public Stream traverse(@Name("graphId") String graphId, @Name("startNodeIds") List startNodeIds, + @Name("traversal") Long traversal, @Name("fromDepth") Long fromDepth, @Name("toDepth") Long toDepth, + @Name("endNodeIds") List endNodeIds, @Name("endRelations") List endRelations, + @Name("uniqueness") List uniqueness, @Name("wordIds") List wordIds, + @Name("relationMap") Map relationMap, + @Name("pathExpander") Map pathExpander) { + + System.out.println("traversal procedure begin"); + try { + TraversalDescription td = db.traversalDescription(); + if (null != traversal && traversal == DEPTH_FIRST_TRAVERSAL) + td = td.depthFirst(); + else + td = td.breadthFirst(); + if (null != fromDepth && fromDepth > 0) + td = td.evaluator(Evaluators.fromDepth(fromDepth.intValue())); + if (null != toDepth && toDepth > 0) + td = td.evaluator(Evaluators.toDepth(toDepth.intValue())); + + if (null != endNodeIds && endNodeIds.size() > 0) { + Node[] nodeArray = new Node[endNodeIds.size()]; + for (int i = 0; i < endNodeIds.size(); i++) { + Node node = db.findNode(Label.label(graphId), "IL_UNIQUE_ID", endNodeIds.get(i)); + nodeArray[i] = node; + } + td = td.evaluator(Evaluators.pruneWhereEndNodeIs(nodeArray)); + } + + if (null != endRelations && endRelations.size() > 0) { + RelationshipType type = RelationshipType.withName(endRelations.get(0)); + if (endRelations.size() > 1) { + RelationshipType[] relationTypes = new RelationshipType[endRelations.size() - 1]; + for (int i = 1; i < endRelations.size(); i++) { + relationTypes[i - 1] = RelationshipType.withName(endRelations.get(i)); + } + td = td.evaluator(Evaluators.pruneWhereLastRelationshipTypeIs(type, relationTypes)); + } else { + td = td.evaluator(Evaluators.pruneWhereLastRelationshipTypeIs(type)); + } + } + + if(null == uniqueness || uniqueness.isEmpty()){ + td = td.uniqueness(Uniqueness.NONE); + } else if (null != uniqueness) { + for(String u: uniqueness){ + td = td.uniqueness(getUniqueness(u)); + } + } + + if (null != wordIds && !wordIds.isEmpty()) + td = td.evaluator(new WordIdEvaluator(wordIds)); + + if (null != relationMap && !relationMap.isEmpty()) { + for (Entry entry : relationMap.entrySet()) { + Direction direction = getDirection(entry.getValue()); + td = td.relationships(RelationshipType.withName(entry.getKey()), direction); + } + } + + if (null != pathExpander && !pathExpander.isEmpty()) { + ArrayExpander expander = new ArrayExpander(pathExpander); + td = td.expand(expander); + } + + Node[] startNodes = new Node[startNodeIds.size()]; + if (null != startNodeIds && startNodeIds.size() > 0) { + for (int i = 0; i < startNodeIds.size(); i++) { + Node node = db.findNode(Label.label(graphId), "IL_UNIQUE_ID", startNodeIds.get(i)); + System.out.println(startNodeIds.get(i) + " - " + node.getId()); + startNodes[i] = node; + } + } + + ResourceIterator pathsIterator = td.traverse(startNodes).iterator(); + System.out.println("got pahts... "); + Builder builder = Stream.builder(); + if (null != pathsIterator) { + List finalPaths = removeSubPaths(pathsIterator); + System.out.println("final paths: " + finalPaths.size()); + for (Path path : finalPaths) { + builder.add(new PathResult(path)); + } + } + return builder.build(); + } catch (Exception e) { + e.printStackTrace(); + log.error("Error in traversal", e); + } + return null; + } + + public List removeSubPaths(ResourceIterator pathsIterator) { + List finalPaths = new ArrayList(); + try { + Path previousPath = null; + int previousPathLength = 0; + while (pathsIterator.hasNext()) { + Path traversedPath = pathsIterator.next(); + System.out.println(traversedPath.startNode().getId() + " - " + traversedPath.endNode().getId() + " : " + traversedPath.length()); + if (traversedPath.length() > previousPathLength) { + previousPath = traversedPath; + previousPathLength = traversedPath.length(); + } else if (traversedPath.length() == previousPathLength) { + if (previousPath != null) { + finalPaths.add(previousPath); + } + previousPath = traversedPath; + previousPathLength = traversedPath.length(); + } else { + if (previousPath != null) { + finalPaths.add(previousPath); + previousPath = null; + } + } + } + + if (previousPath != null) { + finalPaths.add(previousPath); + previousPath = null; + } + + } catch (Exception e) { + e.printStackTrace(); + } + return finalPaths; + } + + private Direction getDirection(String direction) throws Exception { + switch (direction.toUpperCase()) { + case "INCOMING": { + return Direction.INCOMING; + } + case "OUTGOING": { + return Direction.OUTGOING; + } + case "BOTH": { + return Direction.BOTH; + } + default: { + throw new Exception("Invalid direction"); + } + } + } + + private Uniqueness getUniqueness(String uniqueness) { + return Uniqueness.valueOf(uniqueness); + } + + public static class PathResult { + public Node startNode; + public Node endNode; + public List nodes; + public List relations; + + public PathResult(Path path) { + this.startNode = path.startNode(); + this.endNode = path.endNode(); + this.nodes = new ArrayList(); + if (null != path.nodes()) + for (Node pathNode : path.nodes()) + this.nodes.add(pathNode); + this.relations = new ArrayList(); + if (null != path.relationships()) + for (Relationship rel : path.relationships()) + this.relations.add(rel); + } + } + + public class WordIdEvaluator implements Evaluator { + + private List ids = new ArrayList(); + + public WordIdEvaluator(List ids) { + super(); + this.ids = ids; + } + + @Override + public Evaluation evaluate(Path path) { + Node endNode = path.endNode(); + if (endNode.hasProperty("IL_FUNC_OBJECT_TYPE")) { + String objectType = (String) endNode.getProperty("IL_FUNC_OBJECT_TYPE"); + if (objectType.equalsIgnoreCase("Word")) { + if (endNode.hasProperty("IL_UNIQUE_ID")) { + String identifier = (String) endNode.getProperty("IL_UNIQUE_ID"); + if (ids.contains(identifier)) { + return Evaluation.INCLUDE_AND_CONTINUE; + } + } + } else { + return Evaluation.INCLUDE_AND_CONTINUE; + } + } + return Evaluation.EXCLUDE_AND_PRUNE; + } + } + + @SuppressWarnings("rawtypes") + public class ArrayExpander implements PathExpander { + + private Direction[] directions; + private RelationshipType[] types; + private int nodeCount; + + public ArrayExpander(Direction[] directions, RelationshipType[] types, int nodeCount) { + this.types = types; + this.directions = directions; + this.nodeCount = nodeCount; + } + + @SuppressWarnings("unchecked") + public ArrayExpander(Map pathExpander) throws Exception { + if (pathExpander != null && !pathExpander.isEmpty()) { + ArrayList relationTypes = (ArrayList) pathExpander.get("relationTypes"); + if (relationTypes == null) { + throw new Exception("RelationTypes is mandatory for path expander"); + } + ArrayList directionsList = (ArrayList) pathExpander.get("directions"); + if (directionsList == null) { + throw new Exception("Directions field is mandatory for path expander"); + } + Integer nodeCount = Integer.parseInt((String) pathExpander.get("nodeCount")); + + RelationshipType[] types = new RelationshipType[relationTypes.size()]; + Direction[] directions = new Direction[directionsList.size()]; + int count = 0; + for (String relationType : relationTypes) { + types[count] = getRelations(relationType); + count++; + } + count = 0; + for (String direction : directionsList) { + directions[count] = getDirectionObject(direction); + count++; + } + this.directions = directions; + this.types = types; + this.nodeCount = nodeCount; + } + } + + private RelationshipType getRelations(String relation) throws Exception { + return RelationshipType.withName(relation); + } + + private Direction getDirectionObject(String direction) throws Exception { + switch (direction) { + case "INCOMING": { + return Direction.INCOMING; + } + case "OUTGOING": { + return Direction.OUTGOING; + } + case "BOTH": { + return Direction.BOTH; + } + default: { + throw new Exception("Invalid direction"); + } + } + } + + public Iterable expand(Path path, BranchState state) { + return path.endNode().getRelationships(directions[path.length() % nodeCount], + types[path.length() % nodeCount]); + } + + public ArrayExpander reverse() { + return new ArrayExpander(directions, types, nodeCount); + } + } + +} diff --git a/neo4j-extensions/learning-graph-extension/.gitignore b/neo4j-extensions/learning-graph-extension/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/neo4j-extensions/learning-graph-extension/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/neo4j-extensions/learning-graph-extension/dependency-reduced-pom.xml b/neo4j-extensions/learning-graph-extension/dependency-reduced-pom.xml new file mode 100644 index 0000000..fcd2587 --- /dev/null +++ b/neo4j-extensions/learning-graph-extension/dependency-reduced-pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + org.sunbird + learning-graph-extension + 1.1 + + + + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + maven-shade-plugin + 2.4.3 + + + package + + shade + + + + + org.neo4j:* + org.apache.lucene:* + org.scala-lang:* + org.ow2.asm:* + org.parboiled:* + net.sf.opencsv:* + com.googlecode.concurrentlinkedhashmap:* + io.netty:* + + + + + + + + + + diff --git a/neo4j-extensions/learning-graph-extension/pom.xml b/neo4j-extensions/learning-graph-extension/pom.xml new file mode 100644 index 0000000..ff851c1 --- /dev/null +++ b/neo4j-extensions/learning-graph-extension/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + + org.sunbird + learning-graph-extension + 1.1 + + + + org.sunbird + transaction-event-handler + 1.1 + jar + + + + + + + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.3 + + + package + + shade + + + + + org.neo4j:* + org.apache.lucene:* + org.scala-lang:* + org.ow2.asm:* + org.parboiled:* + net.sf.opencsv:* + com.googlecode.concurrentlinkedhashmap:* + io.netty:* + + + + + + + + + \ No newline at end of file diff --git a/neo4j-extensions/learning-graph-extension/src/main/resources/log4j2.xml b/neo4j-extensions/learning-graph-extension/src/main/resources/log4j2.xml new file mode 100644 index 0000000..8bc07dd --- /dev/null +++ b/neo4j-extensions/learning-graph-extension/src/main/resources/log4j2.xml @@ -0,0 +1,37 @@ + + + + + + + + + %d [%t] %-5level %logger{36} - %msg%n + + + + + + + + + + %d %msg%n + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/neo4j-extensions/pom.xml b/neo4j-extensions/pom.xml new file mode 100644 index 0000000..b0a304b --- /dev/null +++ b/neo4j-extensions/pom.xml @@ -0,0 +1,74 @@ + + + 4.0.0 + + org.sunbird + neo4j-extensions + 1.1 + pom + Sunbird Neo4j Kernel Extensions + + + transaction-event-handler + learning-graph-extension + custom-procedures + + + + + + + + + + + maven-assembly-plugin + 2.3 + + + src/assembly/bin.xml + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + org.jacoco + jacoco-maven-plugin + + + default-prepare-agent + + prepare-agent + + + + default-report + prepare-package + + report + + + + + + + + diff --git a/neo4j-extensions/transaction-event-handler/.gitignore b/neo4j-extensions/transaction-event-handler/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/neo4j-extensions/transaction-event-handler/README.md b/neo4j-extensions/transaction-event-handler/README.md new file mode 100755 index 0000000..5f9da76 --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/README.md @@ -0,0 +1,20 @@ +EkStep Transaction Event Handler + +1. Build it: + + mvn clean package + +2. Copy target/transaction-event-handler-1.1.jar to the plugins/ directory of your Neo4j server. + +3. Start your Neo4j Server + +4. Run these queries, And check the Logs should be updated: + + CREATE (n:User {name:"Test User"}) RETURN n; + +5. You should see: + + Updated Logs. + + + diff --git a/neo4j-extensions/transaction-event-handler/pom.xml b/neo4j-extensions/transaction-event-handler/pom.xml new file mode 100755 index 0000000..a7dd749 --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/pom.xml @@ -0,0 +1,98 @@ + + + 4.0.0 + + org.sunbird + transaction-event-handler + 1.1 + + + 3.0.4 + + + + + org.apache.logging.log4j + log4j-1.2-api + 2.14.1 + + + org.apache.logging.log4j + log4j-api + 2.14.1 + + + org.apache.logging.log4j + log4j-core + 2.14.1 + + + com.fasterxml.jackson.core + jackson-core + 2.7.4 + + + com.fasterxml.jackson.core + jackson-databind + 2.7.4 + + + org.neo4j + neo4j + ${neo4j.version} + + + org.neo4j + neo4j-kernel + test-jar + ${neo4j.version} + + + org.neo4j + neo4j-ha + ${neo4j.version} + + + org.neo4j + neo4j-management + ${neo4j.version} + test + + + junit + junit + 4.12 + test + + + + + + + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.codehaus.mojo + cobertura-maven-plugin + 2.7 + + true + coverageReport + + html + xml + + + false + + + + + + \ No newline at end of file diff --git a/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/EkStepTransactionEventHandler.java b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/EkStepTransactionEventHandler.java new file mode 100755 index 0000000..749bc3e --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/EkStepTransactionEventHandler.java @@ -0,0 +1,41 @@ +package org.sunbird.kernel.extension; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.event.TransactionData; +import org.neo4j.graphdb.event.TransactionEventHandler; + + +@SuppressWarnings("rawtypes") +public class EkStepTransactionEventHandler implements TransactionEventHandler { + + public static GraphDatabaseService db; + private Logger logger = LogManager.getLogger("org.sunbird.kernel.extension.EkStepTransactionEventHandler"); + + public EkStepTransactionEventHandler(GraphDatabaseService graphDatabaseService) { + db = graphDatabaseService; + } + + @Override + public Void beforeCommit(TransactionData transactionData) throws Exception { + try { + ProcessTransactionData processTransactionData = new ProcessTransactionData( + "domain", db); + processTransactionData.processTxnData(transactionData); + } catch (Exception e) { + throw e; + } + return null; + } + + @Override + public void afterCommit(TransactionData transactionData, Object o) { + logger.info("After Commit Executed."); + } + + @Override + public void afterRollback(TransactionData transactionData, Object o) { + logger.info("After Rollback Executed."); + } +} diff --git a/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/ProcessTransactionData.java b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/ProcessTransactionData.java new file mode 100644 index 0000000..f420f5b --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/ProcessTransactionData.java @@ -0,0 +1,621 @@ +package org.sunbird.kernel.extension; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.sunbird.kernel.extension.enums.AuditProperties; +import org.sunbird.kernel.extension.enums.GraphDACParams; +import org.sunbird.kernel.extension.enums.SystemProperties; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Relationship; +import org.neo4j.graphdb.event.LabelEntry; +import org.neo4j.graphdb.event.TransactionData; +import org.sunbird.kernel.extension.utils.LogAsyncGraphEvent; + +public class ProcessTransactionData { + + protected String graphId; + protected GraphDatabaseService graphDb; + private String nodeLabel = "NODE"; + private Logger logger = LogManager.getLogger("org.sunbird.kernel.extension.ProcessTransactionData"); + + public ProcessTransactionData(String graphId, GraphDatabaseService graphDb) { + this.graphId = graphId; + this.graphDb = graphDb; + } + + public void processTxnData(TransactionData data) { + try { + List> kafkaMessages = getMessageObj(data); + if (kafkaMessages != null && !kafkaMessages.isEmpty()) { + LogAsyncGraphEvent.pushMessageToLogger(kafkaMessages); + } + } catch (Exception e) { + logger.error("Exception while processing transaction data: " + e.getMessage(), e); + } + } + + private String getGraphId(Node node) { + for (org.neo4j.graphdb.Label lable : node.getLabels()) { + if (!lable.name().equals(nodeLabel)) { + return lable.name(); + } + } + return this.graphId; + } + + private String getGraphId(Iterable labels) { + for (org.neo4j.graphdb.event.LabelEntry lable : labels) { + if (!lable.label().name().equals(nodeLabel)) { + return lable.label().name(); + } + } + return this.graphId; + } + + private List> getMessageObj(TransactionData data) { + String userId = null; + String requestId = null; + List> messageMap = new ArrayList>(); + messageMap.addAll(getCreatedNodeMessages(data, graphDb, userId, requestId)); + messageMap.addAll(getUpdatedNodeMessages(data, graphDb, userId, requestId)); + messageMap.addAll(getDeletedNodeMessages(data, graphDb, userId, requestId)); + messageMap.addAll(getAddedTagsMessage(data, graphDb, userId, requestId)); + messageMap.addAll(getRemovedTagsMessage(data, graphDb, userId, requestId)); + messageMap.addAll(getRemovedRelationShipMessages(data, userId, requestId)); + messageMap.addAll(getAddedRelationShipMessages(data, userId, requestId)); + return messageMap; + } + + private List> getCreatedNodeMessages(TransactionData data, GraphDatabaseService graphDb, + String userId, String requestId) { + List> lstMessageMap = new ArrayList>(); + try { + List createdNodeIds = getCreatedNodeIds(data); + for (Long nodeId : createdNodeIds) { + // Map map = new HashMap(); + Map transactionData = new HashMap(); + Map propertiesMap = getAssignedNodePropertyEntry(nodeId, data); + if (null != propertiesMap && !propertiesMap.isEmpty()) { + transactionData.put(GraphDACParams.properties.name(), propertiesMap); + Map map = setMessageData(graphDb, nodeId, userId, requestId, + GraphDACParams.CREATE.name(), transactionData); + lstMessageMap.add(map); + } + } + } catch (Exception e) { + logger.error("Error building created nodes message: " + e.getMessage(), e); + } + return lstMessageMap; + } + + private List> getUpdatedNodeMessages(TransactionData data, GraphDatabaseService graphDb, + String userId, String requestId) { + List> lstMessageMap = new ArrayList>(); + try { + List updatedNodeIds = getUpdatedNodeIds(data); + for (Long nodeId : updatedNodeIds) { + Map transactionData = new HashMap(); + Map propertiesMap = getAllPropertyEntry(nodeId, data); + if (null != propertiesMap && !propertiesMap.isEmpty()) { + String lastUpdatedBy = getLastUpdatedByValue(nodeId, data); + transactionData.put(GraphDACParams.properties.name(), propertiesMap); + if (StringUtils.isNotBlank(lastUpdatedBy)) { + userId = lastUpdatedBy; + } else { + userId = "ANONYMOUS"; + } + Map map = setMessageData(graphDb, nodeId, userId, requestId, + GraphDACParams.UPDATE.name(), transactionData); + lstMessageMap.add(map); + } + } + } catch (Exception e) { + logger.error("Error building updated nodes message: " + e.getMessage()); + } + return lstMessageMap; + } + + @SuppressWarnings("rawtypes") + private List> getDeletedNodeMessages(TransactionData data, GraphDatabaseService graphDb, + String userId, String requestId) { + List> lstMessageMap = new ArrayList>(); + try { + List deletedNodeIds = getDeletedNodeIds(data); + for (Long nodeId : deletedNodeIds) { + Map map = new HashMap(); + Map transactionData = new HashMap(); + Map removedNodeProp = getRemovedNodePropertyEntry(nodeId, data); + if (null != removedNodeProp && !removedNodeProp.isEmpty()) { + transactionData.put(GraphDACParams.properties.name(), removedNodeProp); + map.put(GraphDACParams.requestId.name(), requestId); + if (StringUtils.isEmpty(userId)) { + if (removedNodeProp.containsKey("lastUpdatedBy")) + // oldvalue of lastUpdatedBy from the transaction + // data as node is deleted + userId = (String) ((Map) removedNodeProp.get("lastUpdatedBy")).get("ov"); + else + userId = "ANONYMOUS"; + } + map.put(GraphDACParams.userId.name(), userId); + map.put(GraphDACParams.operationType.name(), GraphDACParams.DELETE.name()); + map.put(GraphDACParams.label.name(), getLabel(removedNodeProp)); + map.put(GraphDACParams.graphId.name(), getGraphId(data.removedLabels())); + map.put(GraphDACParams.nodeGraphId.name(), nodeId); + map.put(GraphDACParams.createdOn.name(), formatCurrentDate()); + map.put(GraphDACParams.ets.name(), System.currentTimeMillis()); + map.put(GraphDACParams.nodeUniqueId.name(), + ((Map) removedNodeProp.get(SystemProperties.IL_UNIQUE_ID.name())).get("ov")); + map.put(GraphDACParams.objectType.name(), + ((Map) removedNodeProp.get(SystemProperties.IL_FUNC_OBJECT_TYPE.name())).get("ov")); + map.put(GraphDACParams.nodeType.name(), + ((Map) removedNodeProp.get(SystemProperties.IL_SYS_NODE_TYPE.name())).get("ov")); + map.put(GraphDACParams.channel.name(), + ((Map) removedNodeProp.get(GraphDACParams.channel.name())).get("ov")); + map.put(GraphDACParams.transactionData.name(), transactionData); + map.put(GraphDACParams.mid.name(), getUUID()); + lstMessageMap.add(map); + } + } + } catch (Exception e) { + e.printStackTrace(); + logger.error("Error building deleted nodes message: " + e.getMessage(), e); + } + return lstMessageMap; + } + + private Map getAllPropertyEntry(Long nodeId, TransactionData data) { + Map map = getAssignedNodePropertyEntry(nodeId, data); + map.putAll(getRemovedNodePropertyEntry(nodeId, data)); + return map; + } + + private Map getAssignedNodePropertyEntry(Long nodeId, TransactionData data) { + Iterable> assignedNodeProp = data.assignedNodeProperties(); + return getNodePropertyEntry(nodeId, assignedNodeProp); + } + + private String getLastUpdatedByValue(Long nodeId, TransactionData data) { + Iterable> assignedNodeProp = data.assignedNodeProperties(); + for (org.neo4j.graphdb.event.PropertyEntry pe : assignedNodeProp) { + if (nodeId == pe.entity().getId()) { + if (StringUtils.equalsIgnoreCase("lastUpdatedBy", (String) pe.key())) { + String lastUpdatedBy = (String) pe.value(); + return lastUpdatedBy; + } + } + } + return null; + } + + private Map getRemovedNodePropertyEntry(Long nodeId, TransactionData data) { + Iterable> removedNodeProp = data.removedNodeProperties(); + return getNodeRemovedPropertyEntry(nodeId, removedNodeProp); + } + + private Map getNodePropertyEntry(Long nodeId, + Iterable> nodeProp) { + Map map = new HashMap(); + for (org.neo4j.graphdb.event.PropertyEntry pe : nodeProp) { + if (nodeId == pe.entity().getId()) { + if (!compareValues(pe.previouslyCommitedValue(), pe.value())) { + Map valueMap = new HashMap(); + valueMap.put("ov", pe.previouslyCommitedValue()); // old + // value + valueMap.put("nv", pe.value()); // new value + map.put((String) pe.key(), valueMap); + } + } + } + if (map.size() == 1 && null != map.get(AuditProperties.lastUpdatedOn.name())) + map = new HashMap(); + return map; + } + + private Map getNodeRemovedPropertyEntry(Long nodeId, + Iterable> nodeProp) { + Map map = new HashMap(); + for (org.neo4j.graphdb.event.PropertyEntry pe : nodeProp) { + if (nodeId == pe.entity().getId()) { + Map valueMap = new HashMap(); + valueMap.put("ov", pe.previouslyCommitedValue()); // old value + valueMap.put("nv", null); // new value + map.put((String) pe.key(), valueMap); + } + } + if (map.size() == 1 && null != map.get(AuditProperties.lastUpdatedOn.name())) + map = new HashMap(); + return map; + } + + @SuppressWarnings("rawtypes") + private boolean compareValues(Object o1, Object o2) { + if (null == o1) + o1 = ""; + if (null == o2) + o2 = ""; + if (o1.equals(o2)) + return true; + else { + if (o1 instanceof List) { + if (!(o2 instanceof List)) + return false; + else + return compareLists((List) o1, (List) o2); + } else if (o1 instanceof Object[]) { + if (!(o2 instanceof Object[])) + return false; + else + return compareArrays((Object[]) o1, (Object[]) o2); + } + } + return false; + } + + @SuppressWarnings("rawtypes") + private boolean compareLists(List l1, List l2) { + if (l1.size() != l2.size()) + return false; + for (int i = 0; i < l1.size(); i++) { + Object v1 = l1.get(i); + Object v2 = l2.get(i); + if ((null == v1 && null != v2) || (null != v1 && null == v2)) + return false; + if (null != v1 && null != v2 && !v1.equals(v2)) + return false; + } + return true; + } + + private boolean compareArrays(Object[] l1, Object[] l2) { + if (l1.length != l2.length) + return false; + for (int i = 0; i < l1.length; i++) { + Object v1 = l1[i]; + Object v2 = l2[i]; + if ((null == v1 && null != v2) || (null != v1 && null == v2)) + return false; + if (null != v1 && null != v2 && !v1.equals(v2)) + return false; + } + return true; + } + + private List> getAddedTagsMessage(TransactionData data, GraphDatabaseService graphDb, + String userId, String requestId) { + List> lstMessageMap = new ArrayList>(); + try { + Iterable createdRelations = data.createdRelationships(); + if (null != createdRelations) { + for (Relationship rel : createdRelations) { + if (StringUtils.equalsIgnoreCase( + rel.getStartNode().getProperty(SystemProperties.IL_SYS_NODE_TYPE.name()).toString(), + GraphDACParams.TAG.name())) { + if (rel.getStartNode().hasProperty(SystemProperties.IL_TAG_NAME.name())) { + Map transactionData = new HashMap(); + List tags = new ArrayList(); + transactionData.put(GraphDACParams.properties.name(), new HashMap()); + transactionData.put(GraphDACParams.removedTags.name(), new ArrayList()); + tags.add(rel.getStartNode().getProperty(SystemProperties.IL_TAG_NAME.name()).toString()); + transactionData.put(GraphDACParams.addedTags.name(), tags); + Map map = setMessageData(graphDb, rel.getEndNode().getId(), userId, + requestId, GraphDACParams.UPDATE.name(), transactionData); + lstMessageMap.add(map); + } + } + } + } + } catch (Exception e) { + logger.error("Error building added tags message", e); + } + return lstMessageMap; + } + + private List> getRemovedTagsMessage(TransactionData data, GraphDatabaseService graphDb, + String userId, String requestId) { + List> lstMessageMap = new ArrayList>(); + try { + Iterable createdRelations = data.deletedRelationships(); + if (null != createdRelations) { + for (Relationship rel : createdRelations) { + if (rel.getStartNode().hasProperty(SystemProperties.IL_SYS_NODE_TYPE.name()) + && StringUtils.equalsIgnoreCase( + rel.getStartNode().getProperty(SystemProperties.IL_SYS_NODE_TYPE.name()).toString(), + GraphDACParams.TAG.name())) { + if (rel.getStartNode().hasProperty(SystemProperties.IL_TAG_NAME.name())) { + Map transactionData = new HashMap(); + List tags = new ArrayList(); + transactionData.put(GraphDACParams.properties.name(), new HashMap()); + transactionData.put(GraphDACParams.addedTags.name(), new ArrayList()); + tags.add(rel.getStartNode().getProperty(SystemProperties.IL_TAG_NAME.name()).toString()); + transactionData.put(GraphDACParams.removedTags.name(), tags); + + Map map = setMessageData(graphDb, rel.getEndNode().getId(), userId, + requestId, GraphDACParams.UPDATE.name(), transactionData); + lstMessageMap.add(map); + } + } + } + } + } catch (Exception e) { + logger.error("Error building removed tags message" + e.getMessage(), e); + } + return lstMessageMap; + } + + private List> getAddedRelationShipMessages(TransactionData data, String userId, + String requestId) { + Iterable createdRelations = data.createdRelationships(); + return getRelationShipMessages(createdRelations, GraphDACParams.UPDATE.name(), false, userId, requestId, null); + } + + private List> getRemovedRelationShipMessages(TransactionData data, String userId, + String requestId) { + Iterable deletedRelations = data.deletedRelationships(); + Iterable> removedRelationshipProp = data + .removedRelationshipProperties(); + return getRelationShipMessages(deletedRelations, GraphDACParams.UPDATE.name(), true, userId, requestId, + removedRelationshipProp); + } + + private List> getRelationShipMessages(Iterable relations, String operationType, + boolean delete, String userId, String requestId, + Iterable> removedRelationshipProp) { + List> lstMessageMap = new ArrayList>(); + try { + if (null != relations) { + for (Relationship rel : relations) { + Node startNode = rel.getStartNode(); + Node endNode = rel.getEndNode(); + Map relMetadata = null; + if (delete) + relMetadata = getRelationShipPropertyEntry(rel.getId(), removedRelationshipProp); + else + relMetadata = rel.getAllProperties(); + String relationTypeName = rel.getType().name(); + if (StringUtils.equalsIgnoreCase( + startNode.getProperty(SystemProperties.IL_SYS_NODE_TYPE.name()).toString(), + GraphDACParams.TAG.name())) + continue; + + // start_node message + Map map = null; + Map transactionData = new HashMap(); + Map startRelation = new HashMap<>(); + + startRelation.put("rel", relationTypeName); + startRelation.put("id", endNode.getProperty(SystemProperties.IL_UNIQUE_ID.name())); + startRelation.put("dir", "OUT"); + if (endNode.hasProperty(SystemProperties.IL_FUNC_OBJECT_TYPE.name())) + startRelation.put("type", endNode.getProperty(SystemProperties.IL_FUNC_OBJECT_TYPE.name())); + startRelation.put("label", getLabel(endNode)); + startRelation.put("relMetadata", relMetadata); + + if (StringUtils.isEmpty(userId)) { + String startNodeLastUpdate = (String) getPropertyValue(startNode, "lastUpdatedOn"); + String endNodeLastUpdate = (String) getPropertyValue(endNode, "lastUpdatedOn"); + + if (startNodeLastUpdate != null && endNodeLastUpdate != null) { + if (startNodeLastUpdate.compareTo(endNodeLastUpdate) > 0) { + userId = (String) getPropertyValue(startNode, "lastUpdatedBy"); + } else { + userId = (String) getPropertyValue(endNode, "lastUpdatedBy"); + } + } + if (StringUtils.isBlank(userId)) + userId = "ANONYMOUS"; + } + List> startRelations = new ArrayList>(); + startRelations.add(startRelation); + transactionData.put(GraphDACParams.properties.name(), new HashMap()); + transactionData.put(GraphDACParams.removedTags.name(), new ArrayList()); + transactionData.put(GraphDACParams.addedTags.name(), new ArrayList()); + if (delete) { + transactionData.put(GraphDACParams.removedRelations.name(), startRelations); + transactionData.put(GraphDACParams.addedRelations.name(), new ArrayList>()); + } else { + transactionData.put(GraphDACParams.addedRelations.name(), startRelations); + transactionData.put(GraphDACParams.removedRelations.name(), + new ArrayList>()); + } + + map = setMessageData(graphDb, startNode.getId(), userId, requestId, operationType, transactionData); + lstMessageMap.add(map); + + // end_node message + map = null; + transactionData = new HashMap(); + Map endRelation = new HashMap<>(); + + endRelation.put("rel", relationTypeName); + endRelation.put("id", startNode.getProperty(SystemProperties.IL_UNIQUE_ID.name())); + endRelation.put("dir", "IN"); + if (startNode.hasProperty(SystemProperties.IL_FUNC_OBJECT_TYPE.name())) + endRelation.put("type", startNode.getProperty(SystemProperties.IL_FUNC_OBJECT_TYPE.name())); + endRelation.put("label", getLabel(startNode)); + endRelation.put("relMetadata", relMetadata); + List> endRelations = new ArrayList>(); + endRelations.add(endRelation); + transactionData.put(GraphDACParams.properties.name(), new HashMap()); + transactionData.put(GraphDACParams.removedTags.name(), new ArrayList()); + transactionData.put(GraphDACParams.addedTags.name(), new ArrayList()); + if (delete) { + transactionData.put(GraphDACParams.removedRelations.name(), endRelations); + transactionData.put(GraphDACParams.addedRelations.name(), new ArrayList>()); + } else { + transactionData.put(GraphDACParams.addedRelations.name(), endRelations); + transactionData.put(GraphDACParams.removedRelations.name(), + new ArrayList>()); + } + + map = setMessageData(graphDb, endNode.getId(), userId, requestId, operationType, transactionData); + lstMessageMap.add(map); + } + } + } catch (Exception e) { + logger.error("Error building updated relations message" + e.getMessage(), e); + } + return lstMessageMap; + } + + private Map getRelationShipPropertyEntry(Long relId, + Iterable> relProp) { + Map map = new HashMap(); + for (org.neo4j.graphdb.event.PropertyEntry pe : relProp) { + if (relId == pe.entity().getId()) { + if (pe.previouslyCommitedValue() != null) { + map.put((String) pe.key(), pe.previouslyCommitedValue()); + } + } + } + return map; + } + + private String getLabel(Node node) { + if (node.hasProperty("name")) { + return (String) node.getProperty("name"); + } else if (node.hasProperty("lemma")) { + return (String) node.getProperty("lemma"); + } else if (node.hasProperty("title")) { + return (String) node.getProperty("title"); + } else if (node.hasProperty("gloss")) { + return (String) node.getProperty("gloss"); + } + return ""; + } + + @SuppressWarnings("rawtypes") + private String getLabel(Map nodeMap) { + if (nodeMap.containsKey("name")) { + return (String) ((Map) nodeMap.get("name")).get("ov"); + } else if (nodeMap.containsKey("lemma")) { + return (String) ((Map) nodeMap.get("lemma")).get("ov"); + } else if (nodeMap.containsKey("title")) { + return (String) ((Map) nodeMap.get("title")).get("ov"); + } else if (nodeMap.containsKey("gloss")) { + return (String) ((Map) nodeMap.get("gloss")).get("ov"); + } + + return ""; + } + + private Object getPropertyValue(Node node, String propertyName) { + if (node.hasProperty(propertyName)) + return node.getProperty(propertyName); + return null; + } + + private List getUpdatedNodeIds(TransactionData data) { + List lstNodeIds = new ArrayList(); + List lstCreatedNodeIds = getCreatedNodeIds(data); + List lstDeletedNodeIds = getDeletedNodeIds(data); + Iterable> assignedNodeProp = data.assignedNodeProperties(); + for (org.neo4j.graphdb.event.PropertyEntry pe : assignedNodeProp) { + if (!lstCreatedNodeIds.contains(pe.entity().getId()) && !lstDeletedNodeIds.contains(pe.entity().getId())) { + lstNodeIds.add(pe.entity().getId()); + } + } + Iterable> removedNodeProp = data.removedNodeProperties(); + for (org.neo4j.graphdb.event.PropertyEntry pe : removedNodeProp) { + if (!lstCreatedNodeIds.contains(pe.entity().getId()) && !lstDeletedNodeIds.contains(pe.entity().getId())) { + lstNodeIds.add(pe.entity().getId()); + } + } + return new ArrayList(new HashSet(lstNodeIds)); + } + + private List getCreatedNodeIds(TransactionData data) { + List lstNodeIds = new ArrayList(); + if (null != data.createdNodes()) { + Iterator nodes = data.createdNodes().iterator(); + while (nodes.hasNext()) { + lstNodeIds.add(nodes.next().getId()); + } + } + + return new ArrayList(new HashSet(lstNodeIds)); + } + + private List getDeletedNodeIds(TransactionData data) { + List lstNodeIds = new ArrayList(); + if (null != data.deletedNodes()) { + Iterator nodes = data.deletedNodes().iterator(); + while (nodes.hasNext()) { + lstNodeIds.add(nodes.next().getId()); + } + } + + return new ArrayList(new HashSet(lstNodeIds)); + } + + private Map setMessageData(GraphDatabaseService graphDb, Long nodeId, String userId, + String requestId, String operationType, Map transactionData) { + Map map = new HashMap(); + Node node = graphDb.getNodeById(nodeId); + map.put(GraphDACParams.requestId.name(), requestId); + if (StringUtils.isEmpty(userId)) { + if (node.hasProperty("lastUpdatedBy")) + userId = (String) node.getProperty("lastUpdatedBy"); + else if(node.hasProperty("createdBy")) + userId = (String) node.getProperty("createdBy"); + else + userId = "ANONYMOUS"; + } + String channelId = null; + if (node.hasProperty(GraphDACParams.channel.name())) { + channelId = node.getProperty(GraphDACParams.channel.name()).toString(); + } + map.put(GraphDACParams.userId.name(), userId); + map.put(GraphDACParams.operationType.name(), operationType); + map.put(GraphDACParams.label.name(), getLabel(node)); + map.put(GraphDACParams.createdOn.name(), formatCurrentDate()); + map.put(GraphDACParams.ets.name(), System.currentTimeMillis()); + map.put(GraphDACParams.graphId.name(), getGraphId(node)); + map.put(GraphDACParams.nodeGraphId.name(), nodeId); + map.put(GraphDACParams.nodeUniqueId.name(), node.getProperty(SystemProperties.IL_UNIQUE_ID.name())); + if (node.hasProperty(SystemProperties.IL_FUNC_OBJECT_TYPE.name())) + map.put(GraphDACParams.objectType.name(), node.getProperty(SystemProperties.IL_FUNC_OBJECT_TYPE.name())); + if (node.hasProperty(SystemProperties.IL_SYS_NODE_TYPE.name())) + map.put(GraphDACParams.nodeType.name(), node.getProperty(SystemProperties.IL_SYS_NODE_TYPE.name())); + map.put(GraphDACParams.channel.name(), channelId); + map.put(GraphDACParams.transactionData.name(), transactionData); + map.put(GraphDACParams.mid.name(), getUUID()); + return map; + + } + + private String getUUID() { + UUID uid = UUID.randomUUID(); + return uid.toString(); + } + + public static String format(Date date) { + SimpleDateFormat sdf = getDateFormat(); + if (null != date) { + try { + return sdf.format(date); + } catch (Exception e) { + } + } + return null; + } + + public static SimpleDateFormat getDateFormat() { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + return sdf; + } + public static String formatCurrentDate() { + return format(new Date()); + } +} \ No newline at end of file diff --git a/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/RegisterTransactionEventHandlerExtensionFactory.java b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/RegisterTransactionEventHandlerExtensionFactory.java new file mode 100755 index 0000000..e91fd1d --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/RegisterTransactionEventHandlerExtensionFactory.java @@ -0,0 +1,50 @@ +package org.sunbird.kernel.extension; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.kernel.extension.KernelExtensionFactory; +import org.neo4j.kernel.impl.spi.KernelContext; +import org.neo4j.kernel.lifecycle.Lifecycle; +import org.neo4j.kernel.lifecycle.LifecycleAdapter; + + +public class RegisterTransactionEventHandlerExtensionFactory extends KernelExtensionFactory { + + public interface Dependencies { + GraphDatabaseService getGraphDatabaseService(); + } + + public RegisterTransactionEventHandlerExtensionFactory() { + super("registerTransactionEventHandler"); + } + + @SuppressWarnings("unchecked") + @Override + public Lifecycle newInstance(KernelContext context, final Dependencies dependencies) throws Throwable { + return new LifecycleAdapter() { + + private EkStepTransactionEventHandler handler; + + @Override + public void start() throws Throwable { + try { + handler = new EkStepTransactionEventHandler(dependencies.getGraphDatabaseService()); + dependencies.getGraphDatabaseService().registerTransactionEventHandler(handler); + System.out.println("Registering the kernel ext for transaction-event-handler - complete."); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + @Override + public void shutdown() throws Throwable { + try { + dependencies.getGraphDatabaseService().unregisterTransactionEventHandler(handler); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + } + +} diff --git a/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/AuditProperties.java b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/AuditProperties.java new file mode 100644 index 0000000..2415f8a --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/AuditProperties.java @@ -0,0 +1,5 @@ +package org.sunbird.kernel.extension.enums; + +public enum AuditProperties { + createdOn, lastUpdatedOn, lastStatusChangedOn, prevStatus; +} diff --git a/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/GraphDACParams.java b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/GraphDACParams.java new file mode 100644 index 0000000..8028a86 --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/GraphDACParams.java @@ -0,0 +1,17 @@ +package org.sunbird.kernel.extension.enums; + +public enum GraphDACParams { + graph_id, start_node_id, end_node_id, relation_type, metadata, property_key, node, node_id, node_ids, property_keys, count, skip_validations, + node_list, relations, relation, property, loop, message, messages, object_type, member_type, required_metadata_key, indexable_metadata_key, + non_indexable_metadata_key, in_relations_key, out_relations_key, system_tags_key, sequence_id, members, collection_id, collection_type, member_id, + index, cardinality, import_input_object, search_criteria, traversal_description, sub_graph, path, depth, is_member, set_id, criteria, + in_relations, out_relations, tags, tag_id, tag_name, attribute_name, definition_node, definition_nodes, get_tags, metadata_definitions, query, + params, results, start_node_filter, related_node_filter, start_node_fields, related_node_fields, direction, operationType, CREATE, DELETE, UPDATE, + nodeGraphId, nodeUniqueId, objectType, nodeType, transactionData, addedProperties, propertyName, value, removedProperties, addedTags, removedTags, + graphId, identifier, key, ets, newValue, status, adedTags, RETIRED, task_id, TAG, TAG_NAME, isoSymbol, type, unicode, properties, userId, requestId, + addedRelations, removedRelations, label, altIsoSymbol, member, proxyNode, translationSet, versionKey, versionCheckMode, STALE_DATA_UPDATED, NODE_UPDATE_STATUS, + lastUpdatedOn, ON, MATCH, SET, request, MERGE, nodes, RETURN, keys, nodesCount, relationsCount, rootNode, nodeId, WHERE, indexProperties, startNodeId, endNodeId, + relationType, startNodeIds, endNodeIds, collectionId, collection, indexProperty, taskId, input, getTags, searchCriteria, paramMap, traverser, cypherQuery, createdOn, + lastUpdatedBy, paramValueMap, QUERY_TEMPLATES, queryStatementMap, SYS_INTERNAL_LAST_UPDATED_ON, CONSUMER_ID, consumerId, CHANNEL_ID, channel, newNodes, + modifiedNodes, addedOutRelations, removedOutRelations, addedInRelations, removedInRelations, APP_ID, appId, createdBy, publish_type, Live, Unlisted, mid; +} diff --git a/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/HeaderParam.java b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/HeaderParam.java new file mode 100644 index 0000000..1d9aaba --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/HeaderParam.java @@ -0,0 +1,12 @@ +package org.sunbird.kernel.extension.enums; + +public enum HeaderParam { + + REQUEST_ID, REQUEST_PATH, REQUEST_ST_ED_PATH, CURRENT_INVOCATION_PATH, USER_DATA, USER_LOCALE, SYSTEM_LOCALE, USER_ID, PROXY_USER_ID, + USER_NAME, PROXY_USER_NAME, SCOPE_ID, CONSUMER_ID, CHANNEL_ID, APP_ID, DEVICE_ID; + + public String getParamName() { + return this.name(); + } + +} diff --git a/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/SystemProperties.java b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/SystemProperties.java new file mode 100644 index 0000000..eb3353f --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/enums/SystemProperties.java @@ -0,0 +1,17 @@ +package org.sunbird.kernel.extension.enums; + +public enum SystemProperties { + IL_SYS_NODE_TYPE, IL_FUNC_OBJECT_TYPE, IL_UNIQUE_ID, IL_TAG_NAME, IL_ATTRIBUTE_NAME, IL_INDEXABLE_METADATA_KEY, IL_NON_INDEXABLE_METADATA_KEY, + IL_IN_RELATIONS_KEY, IL_OUT_RELATIONS_KEY, IL_REQUIRED_PROPERTIES, IL_SYSTEM_TAGS_KEY, IL_SEQUENCE_INDEX; + + public static boolean isSystemProperty(String str) { + SystemProperties val = null; + try { + val = SystemProperties.valueOf(str); + } catch (Exception e) { + } + if (null == val) + return false; + return true; + } +} diff --git a/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/utils/LogAsyncGraphEvent.java b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/utils/LogAsyncGraphEvent.java new file mode 100644 index 0000000..1f0b910 --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/src/main/java/org/sunbird/kernel/extension/utils/LogAsyncGraphEvent.java @@ -0,0 +1,29 @@ +package org.sunbird.kernel.extension.utils; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class LogAsyncGraphEvent { + private static final Logger graphEventLogger = LogManager.getLogger("GraphEventLogger"); + private static ObjectMapper mapper = new ObjectMapper(); + + + public static void pushMessageToLogger(List> messages) { + if (null == messages || messages.size() <= 0) return; + for (Map message : messages) { + try{ + String jsonMessage = mapper.writeValueAsString(message); + if (StringUtils.isNotBlank(jsonMessage)) + graphEventLogger.info(jsonMessage); + }catch(Exception e){ + e.printStackTrace(); + } + } + } +} diff --git a/neo4j-extensions/transaction-event-handler/src/main/resources/META-INF/services/org.neo4j.kernel.extension.KernelExtensionFactory b/neo4j-extensions/transaction-event-handler/src/main/resources/META-INF/services/org.neo4j.kernel.extension.KernelExtensionFactory new file mode 100755 index 0000000..73ca9d1 --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/src/main/resources/META-INF/services/org.neo4j.kernel.extension.KernelExtensionFactory @@ -0,0 +1 @@ +org.sunbird.kernel.extension.RegisterTransactionEventHandlerExtensionFactory \ No newline at end of file diff --git a/neo4j-extensions/transaction-event-handler/src/test/java/org/sunbird/kernel/extension/RelationEnums.java b/neo4j-extensions/transaction-event-handler/src/test/java/org/sunbird/kernel/extension/RelationEnums.java new file mode 100644 index 0000000..83c8347 --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/src/test/java/org/sunbird/kernel/extension/RelationEnums.java @@ -0,0 +1,8 @@ +package org.sunbird.kernel.extension; + +import org.neo4j.graphdb.RelationshipType; + +public enum RelationEnums implements RelationshipType{ + associatedTo, isParentOf, + hasSequenceMember; +} diff --git a/neo4j-extensions/transaction-event-handler/src/test/java/org/sunbird/kernel/extension/TestNeo4JCluster.java b/neo4j-extensions/transaction-event-handler/src/test/java/org/sunbird/kernel/extension/TestNeo4JCluster.java new file mode 100644 index 0000000..14c167d --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/src/test/java/org/sunbird/kernel/extension/TestNeo4JCluster.java @@ -0,0 +1,269 @@ +package org.sunbird.kernel.extension; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.HashSet; +import java.util.Set; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.neo4j.cluster.ClusterSettings; +import org.neo4j.graphdb.Direction; +import org.neo4j.graphdb.Label; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Relationship; +import org.neo4j.graphdb.Transaction; +import org.neo4j.graphdb.factory.GraphDatabaseBuilder; +import org.neo4j.graphdb.factory.HighlyAvailableGraphDatabaseFactory; +import org.neo4j.kernel.ha.HaSettings; +import org.neo4j.kernel.ha.HighlyAvailableGraphDatabase; + +public class TestNeo4JCluster { + protected final static String DB_LOCATION = "target/graph-master"; + protected final static String SERVER_ID = "1"; + private static HighlyAvailableGraphDatabase graphDb; + private Label name = Label.label("domain"); + private static Set tmp = new HashSet(); + private static String ch=""; + private static String logsBasePath = "/data/logs/"; + + @BeforeClass + public static void beforeTest() throws InterruptedException, FileNotFoundException { + deleteFileContents(); + GraphDatabaseBuilder builder = new HighlyAvailableGraphDatabaseFactory().newEmbeddedDatabaseBuilder(new File(DB_LOCATION)); + builder.setConfig(ClusterSettings.server_id, SERVER_ID); + builder.setConfig(HaSettings.ha_server, "localhost:4001"); + builder.setConfig(HaSettings.slave_only, "false"); + builder.setConfig(ClusterSettings.cluster_server, "localhost:3001"); + builder.setConfig(ClusterSettings.initial_hosts, "localhost:3001"); + graphDb = (HighlyAvailableGraphDatabase) builder.newGraphDatabase(); + Thread.sleep(10000); + + } + + @org.junit.AfterClass + public static void afterTest() throws FileNotFoundException { + deleteFileContents(); + } + + @Test + public void createNodeTest() { + try { + try(Transaction tx = graphDb.beginTx()){ + Node node = graphDb.createNode(name); + String uniqueId = "id_" + Math.random(); + node.setProperty("channel", "in.ekstep"); + node.setProperty("IL_UNIQUE_ID", uniqueId); + node.setProperty("IL_SYS_NODE_TYPE", "DATA_NODE"); + node.setProperty("IL_FUNC_OBJECT_TYPE", "Content"); + node.setProperty("name", "Name_" + uniqueId); + tx.success(); + File file = new File(logsBasePath + "test_graph_event_neo4j.log"); + Assert.assertTrue(file.exists()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void addProperty() { + try { + String uniqueId = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId); + nodeData.setProperty("channel", "in.ekstep"); + nodeData.setProperty("IL_SYS_NODE_TYPE", "DATA_NODE"); + tx1.success(); + File file = new File(logsBasePath + "test_graph_event_neo4j.log"); + Assert.assertTrue(file.exists()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void updateProperty() { + try { + String uniqueId = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId); + nodeData.setProperty("description", "update description property"); + tx1.success(); + File file = new File(logsBasePath + "test_graph_event_neo4j.log"); + Assert.assertTrue(file.exists()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void removeProperty() { + try { + String uniqueId = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId); + nodeData.removeProperty("channel"); + tx1.success(); + File file = new File(logsBasePath + "test_graph_event_neo4j.log"); + Assert.assertTrue(file.exists()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void deleteNode() { + try { + String uniqueId = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId); + nodeData.delete(); + tx1.success(); + File file = new File(logsBasePath + "test_graph_event_neo4j.log"); + Assert.assertTrue(file.exists()); + } + }catch(Exception e) { + e.printStackTrace(); + } + } + + @Test + public void addRelation() { + try { + String uniqueId1 = createNode(graphDb); + String uniqueId2 = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData1 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId1); + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + nodeData2.createRelationshipTo(nodeData1, RelationEnums.associatedTo); + tx1.success(); + File file = new File(logsBasePath + "test_graph_event_neo4j.log"); + Assert.assertTrue(file.exists()); + } + }catch(Exception e) { + e.printStackTrace(); + } + } + + + @Test + public void addRelationProperty() { + try { + String uniqueId1 = createNode(graphDb); + String uniqueId2 = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData1 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId1); + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + nodeData2.createRelationshipTo(nodeData1, RelationEnums.isParentOf); + tx1.success(); + } + try( Transaction tx2 = graphDb.beginTx()){ + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + Relationship res = nodeData2.getSingleRelationship(RelationEnums.isParentOf, Direction.OUTGOING); + res.setProperty("description", "isParentOf"); + tx2.success(); + } + File file = new File(logsBasePath + "test_graph_event_neo4j.log"); + Assert.assertTrue(file.exists()); + }catch(Exception e) { + e.printStackTrace(); + } + } + + @Test + public void removeRelationProperty() { + try { + String uniqueId1 = createNode(graphDb); + String uniqueId2 = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData1 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId1); + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + Relationship res = nodeData2.createRelationshipTo(nodeData1, RelationEnums.hasSequenceMember); + res.setProperty("description", "hasSequenceMember"); + res.setProperty("relatioName","has sequence member"); + tx1.success(); + } + try(Transaction tx = graphDb.beginTx()){ + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + Relationship res = nodeData2.getSingleRelationship(RelationEnums.hasSequenceMember, Direction.OUTGOING); + res.removeProperty("description"); + tx.success(); + } + File file = new File(logsBasePath + "test_graph_event_neo4j.log"); + Assert.assertTrue(file.exists()); + }catch(Exception e) { + e.printStackTrace(); + } + } + + @Test + public void removedRelation() { + try { + String uniqueId1 = createNode(graphDb); + String uniqueId2 = createNode(graphDb); + try( Transaction tx = graphDb.beginTx()){ + Node nodeData1 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId1); + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + nodeData2.createRelationshipTo(nodeData1, RelationEnums.associatedTo); + tx.success(); + } + try(Transaction tx = graphDb.beginTx()){ + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + Relationship res = nodeData2.getSingleRelationship(RelationEnums.associatedTo, Direction.OUTGOING); + res.delete(); + tx.success(); + } + File file = new File(logsBasePath + "test_graph_event_neo4j.log"); + Assert.assertTrue(file.exists()); + }catch(Exception e) { + e.printStackTrace(); + } + } + + @SuppressWarnings("resource") + public static String readFromFile() throws Exception { + BufferedReader in = new BufferedReader(new FileReader(logsBasePath + "test_graph_event_neo4j.log")); + do { + ch = in.readLine(); + tmp.add(ch); + } while (ch != null); + for(String s : tmp) { + if(null != s) + ch = s; + } + return ch; + } + + public static void deleteFileContents() throws FileNotFoundException { + File file = new File(logsBasePath + "test_graph_event_neo4j.log"); + if(file.exists()) + file.delete(); + } + + public String createNode(HighlyAvailableGraphDatabase graphDb2) { + String uniqueId = ""; + try { + try(Transaction tx = graphDb.beginTx()){ + Node node = graphDb.createNode(name); + uniqueId = "id_" + Math.random(); + node.setProperty("IL_UNIQUE_ID", uniqueId); + node.setProperty("name", "Name_" + uniqueId); + node.setProperty("IL_SYS_NODE_TYPE", "DATA_NODE"); + node.setProperty("IL_FUNC_OBJECT_TYPE", "Content"); + node.setProperty("channel", "test_channel"); + node.setProperty("description", "test description"); + tx.success(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return uniqueId; + } +} diff --git a/neo4j-extensions/transaction-event-handler/src/test/java/org/sunbird/kernel/extension/TestTransactionEvents.java b/neo4j-extensions/transaction-event-handler/src/test/java/org/sunbird/kernel/extension/TestTransactionEvents.java new file mode 100644 index 0000000..d401d1d --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/src/test/java/org/sunbird/kernel/extension/TestTransactionEvents.java @@ -0,0 +1,261 @@ +package org.sunbird.kernel.extension; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.neo4j.graphdb.Direction; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.Label; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Relationship; +import org.neo4j.graphdb.Transaction; +import org.neo4j.graphdb.factory.GraphDatabaseBuilder; +import org.neo4j.graphdb.factory.GraphDatabaseFactory; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.HashSet; +import java.util.Set; + +@Ignore +public class TestTransactionEvents { + protected final static String DB_LOCATION = "target/graph-master1"; + protected final static String SERVER_ID = "1"; + private static GraphDatabaseService graphDb; + private Label name = Label.label("domain"); + private static Set tmp = new HashSet(); + private static String ch=""; + private static String logsBasePath = "/data/logs/"; + + @BeforeClass + public static void beforeTest() throws InterruptedException, FileNotFoundException { + GraphDatabaseBuilder builder = new GraphDatabaseFactory() + .newEmbeddedDatabaseBuilder + (new File + (DB_LOCATION)); + graphDb = builder.newGraphDatabase(); + deleteFileContents(); + } + + @org.junit.AfterClass + public static void afterTest() throws FileNotFoundException { + deleteFileContents(); + } + + @Test + public void createNodeTest() { + try { + try(Transaction tx = graphDb.beginTx()){ + Node node = graphDb.createNode(name); + String uniqueId = "id_" + Math.random(); + node.setProperty("IL_UNIQUE_ID", uniqueId); + node.setProperty("name", "Name_" + uniqueId); + tx.success(); + File file = new File(logsBasePath + "test_event_neo4j.log"); + Assert.assertTrue(file.exists()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void addProperty() { + try { + String uniqueId = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId); + nodeData.setProperty("channel", "in.ekstep"); + nodeData.setProperty("IL_SYS_NODE_TYPE", "DATA_NODE"); + tx1.success(); + File file = new File(logsBasePath + "test_event_neo4j.log"); + Assert.assertTrue(file.exists()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void updateProperty() { + try { + String uniqueId = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId); + nodeData.setProperty("description", "update description property"); + tx1.success(); + File file = new File(logsBasePath + "test_event_neo4j.log"); + Assert.assertTrue(file.exists()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void removeProperty() { + try { + String uniqueId = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId); + nodeData.removeProperty("channel"); + tx1.success(); + File file = new File(logsBasePath + "test_event_neo4j.log"); + Assert.assertTrue(file.exists()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void deleteNode() { + try { + String uniqueId = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId); + nodeData.delete(); + tx1.success(); + File file = new File(logsBasePath + "test_event_neo4j.log"); + Assert.assertTrue(file.exists()); + } + }catch(Exception e) { + e.printStackTrace(); + } + } + + @Test + public void addRelation() { + try { + String uniqueId1 = createNode(graphDb); + String uniqueId2 = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData1 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId1); + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + nodeData2.createRelationshipTo(nodeData1, RelationEnums.associatedTo); + tx1.success(); + File file = new File(logsBasePath + "test_event_neo4j.log"); + Assert.assertTrue(file.exists()); + } + }catch(Exception e) { + e.printStackTrace(); + } + } + + + @Test + public void addRelationProperty() { + try { + String uniqueId1 = createNode(graphDb); + String uniqueId2 = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData1 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId1); + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + nodeData2.createRelationshipTo(nodeData1, RelationEnums.isParentOf); + tx1.success(); + } + try( Transaction tx2 = graphDb.beginTx()){ + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + Relationship res = nodeData2.getSingleRelationship(RelationEnums.isParentOf, Direction.OUTGOING); + res.setProperty("description", "isParentOf"); + tx2.success(); + } + File file = new File(logsBasePath + "test_event_neo4j.log"); + Assert.assertTrue(file.exists()); + }catch(Exception e) { + e.printStackTrace(); + } + } + + @Test + public void removeRelationProperty() { + try { + String uniqueId1 = createNode(graphDb); + String uniqueId2 = createNode(graphDb); + try( Transaction tx1 = graphDb.beginTx()){ + Node nodeData1 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId1); + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + Relationship res = nodeData2.createRelationshipTo(nodeData1, RelationEnums.hasSequenceMember); + res.setProperty("description", "hasSequenceMember"); + res.setProperty("relatioName","has sequence member"); + tx1.success(); + } + try(Transaction tx = graphDb.beginTx()){ + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + Relationship res = nodeData2.getSingleRelationship(RelationEnums.hasSequenceMember, Direction.OUTGOING); + res.removeProperty("description"); + tx.success(); + } + File file = new File(logsBasePath + "test_event_neo4j.log"); + Assert.assertTrue(file.exists()); + }catch(Exception e) { + e.printStackTrace(); + } + } + + @Test + public void removedRelation() { + try { + String uniqueId1 = createNode(graphDb); + String uniqueId2 = createNode(graphDb); + try( Transaction tx = graphDb.beginTx()){ + Node nodeData1 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId1); + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + nodeData2.createRelationshipTo(nodeData1, RelationEnums.associatedTo); + tx.success(); + } + try(Transaction tx = graphDb.beginTx()){ + Node nodeData2 = graphDb.findNode(name, "IL_UNIQUE_ID", uniqueId2); + Relationship res = nodeData2.getSingleRelationship(RelationEnums.associatedTo, Direction.OUTGOING); + res.delete(); + tx.success(); + } + File file = new File(logsBasePath + "test_event_neo4j.log"); + Assert.assertTrue(file.exists()); + }catch(Exception e) { + e.printStackTrace(); + } + } + + @SuppressWarnings("resource") + public static String readFromFile() throws Exception { + BufferedReader in = new BufferedReader(new FileReader(logsBasePath + "test_event_neo4j.log")); + do { + ch = in.readLine(); + tmp.add(ch); + } while (ch != null); + for(String s : tmp) { + if(null != s) + ch = s; + } + return ch; + } + + public static void deleteFileContents() throws FileNotFoundException { + File file = new File(logsBasePath + "test_event_neo4j.log"); + if(file.exists()) + file.delete(); + } + + public String createNode(GraphDatabaseService graphDb2) { + String uniqueId = ""; + try { + try(Transaction tx = graphDb.beginTx()){ + Node node = graphDb.createNode(name); + uniqueId = "id_" + Math.random(); + node.setProperty("IL_UNIQUE_ID", uniqueId); + node.setProperty("name", "Name_" + uniqueId); + node.setProperty("IL_SYS_NODE_TYPE", "DATA_NODE"); + node.setProperty("description", "test description"); + tx.success(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return uniqueId; + } + +} diff --git a/neo4j-extensions/transaction-event-handler/src/test/resources/log4j2.xml b/neo4j-extensions/transaction-event-handler/src/test/resources/log4j2.xml new file mode 100644 index 0000000..0fcfc5b --- /dev/null +++ b/neo4j-extensions/transaction-event-handler/src/test/resources/log4j2.xml @@ -0,0 +1,39 @@ + + + + + + + + + %d [%t] %-5level %logger{36} - %msg%n + + + + + + + + + + + %msg%n + + + + + + + + + + + + + + + + + \ No newline at end of file