From a4d195727605ff9afff3b2f9e82749aa48763985 Mon Sep 17 00:00:00 2001 From: danthe1st Date: Tue, 3 Sep 2024 11:02:34 +0200 Subject: [PATCH] JFR module --- .gitignore | 1 + arebac-jfr/pom.xml | 19 +++++ .../arebac/jfr/JFRRecordedGraphEdge.java | 70 ++++++++++++++++++ .../arebac/jfr/JFRRecordedGraphNode.java | 63 ++++++++++++++++ .../arebac/jfr/JFRRecordedGraphWrapper.java | 72 +++++++++++++++++++ .../arebac/jfr/events/FindEdgesEvent.java | 43 +++++++++++ .../arebac/jfr/events/FindNodeEvent.java | 21 ++++++ .../arebac/jfr/events/GetAttributeEvent.java | 42 +++++++++++ .../arebac/jfr/events/JFREventConstants.java | 8 +++ .../github/danthe1st/arebac/jfr/JFRTest.java | 31 ++++++++ pom.xml | 1 + 11 files changed, 371 insertions(+) create mode 100644 arebac-jfr/pom.xml create mode 100644 arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/JFRRecordedGraphEdge.java create mode 100644 arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/JFRRecordedGraphNode.java create mode 100644 arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/JFRRecordedGraphWrapper.java create mode 100644 arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/FindEdgesEvent.java create mode 100644 arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/FindNodeEvent.java create mode 100644 arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/GetAttributeEvent.java create mode 100644 arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/JFREventConstants.java create mode 100644 arebac-jfr/src/test/java/io/github/danthe1st/arebac/jfr/JFRTest.java diff --git a/.gitignore b/.gitignore index 8002552..fcc45fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ arebac-neo4j/testdb +*.jfr # Created by https://www.toptal.com/developers/gitignore/api/eclipse,java,maven # Edit at https://www.toptal.com/developers/gitignore?templates=eclipse,java,maven diff --git a/arebac-jfr/pom.xml b/arebac-jfr/pom.xml new file mode 100644 index 0000000..023248a --- /dev/null +++ b/arebac-jfr/pom.xml @@ -0,0 +1,19 @@ + + 4.0.0 + + io.github.danthe1st + AReBAC + 0.0.1-SNAPSHOT + + io.github.danthe1st + arebac-jfr + + + io.github.danthe1st + arebac-core + ${project.version} + + + \ No newline at end of file diff --git a/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/JFRRecordedGraphEdge.java b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/JFRRecordedGraphEdge.java new file mode 100644 index 0000000..46c7471 --- /dev/null +++ b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/JFRRecordedGraphEdge.java @@ -0,0 +1,70 @@ +package io.github.danthe1st.arebac.jfr; + +import java.util.Objects; + +import io.github.danthe1st.arebac.data.commongraph.attributed.AttributeValue; +import io.github.danthe1st.arebac.data.commongraph.attributed.AttributedGraphEdge; +import io.github.danthe1st.arebac.data.commongraph.attributed.AttributedNode; +import io.github.danthe1st.arebac.jfr.events.GetAttributeEvent; +import io.github.danthe1st.arebac.jfr.events.GetAttributeEvent.ElementType; + +public class JFRRecordedGraphEdge> implements AttributedGraphEdge> { + + private final E edge; + + public JFRRecordedGraphEdge(E edge) { + this.edge = edge; + } + + @Override + public JFRRecordedGraphNode source() { + return new JFRRecordedGraphNode<>(edge.source()); + } + + @Override + public JFRRecordedGraphNode target() { + return new JFRRecordedGraphNode<>(edge.target()); + } + + @Override + public String id() { + return edge.id(); + } + + @Override + public boolean hasEdgeType(String edgeType) { + return edge.hasEdgeType(edgeType); + } + + @Override + public AttributeValue getAttribute(String key) { + GetAttributeEvent event = new GetAttributeEvent(edge.id(), key, ElementType.EDGE); + event.begin(); + AttributeValue attribute = edge.getAttribute(key); + event.commit(); + return attribute; + } + + @Override + public String toString() { + return "JFRRecordedGraphEdge [edge=" + edge + "]"; + } + + @Override + public int hashCode() { + return Objects.hash(edge); + } + + @Override + public boolean equals(Object obj) { + if(this == obj){ + return true; + } + if((obj == null) || (getClass() != obj.getClass())){ + return false; + } + JFRRecordedGraphEdge other = (JFRRecordedGraphEdge) obj; + return Objects.equals(edge, other.edge); + } + +} diff --git a/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/JFRRecordedGraphNode.java b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/JFRRecordedGraphNode.java new file mode 100644 index 0000000..a05e0ab --- /dev/null +++ b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/JFRRecordedGraphNode.java @@ -0,0 +1,63 @@ +package io.github.danthe1st.arebac.jfr; + +import java.util.Objects; + +import io.github.danthe1st.arebac.data.commongraph.attributed.AttributeValue; +import io.github.danthe1st.arebac.data.commongraph.attributed.AttributedNode; +import io.github.danthe1st.arebac.jfr.events.GetAttributeEvent; +import io.github.danthe1st.arebac.jfr.events.GetAttributeEvent.ElementType; + +public class JFRRecordedGraphNode implements AttributedNode { + + private final N node; + + public JFRRecordedGraphNode(N node) { + this.node = node; + } + + @Override + public String id() { + return node.id(); + } + + @Override + public boolean hasNodeType(String nodeType) { + return node.hasNodeType(nodeType); + } + + @Override + public AttributeValue getAttribute(String key) { + GetAttributeEvent event = new GetAttributeEvent(node.id(), key, ElementType.NODE); + event.begin(); + AttributeValue attribute = node.getAttribute(key); + event.commit(); + return attribute; + } + + N getInternalNode() { + return node; + } + + @Override + public String toString() { + return "JFRRecordedGraphNode [node=" + node + "]"; + } + + @Override + public int hashCode() { + return Objects.hash(node); + } + + @Override + public boolean equals(Object obj) { + if(this == obj){ + return true; + } + if((obj == null) || (getClass() != obj.getClass())){ + return false; + } + JFRRecordedGraphNode other = (JFRRecordedGraphNode) obj; + return Objects.equals(node, other.node); + } + +} diff --git a/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/JFRRecordedGraphWrapper.java b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/JFRRecordedGraphWrapper.java new file mode 100644 index 0000000..cf95ebe --- /dev/null +++ b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/JFRRecordedGraphWrapper.java @@ -0,0 +1,72 @@ +package io.github.danthe1st.arebac.jfr; + +import java.util.Collection; +import java.util.Objects; + +import io.github.danthe1st.arebac.data.commongraph.attributed.AttributedGraph; +import io.github.danthe1st.arebac.data.commongraph.attributed.AttributedGraphEdge; +import io.github.danthe1st.arebac.data.commongraph.attributed.AttributedNode; +import io.github.danthe1st.arebac.jfr.events.FindEdgesEvent; +import io.github.danthe1st.arebac.jfr.events.FindEdgesEvent.Direction; +import io.github.danthe1st.arebac.jfr.events.FindNodeEvent; + +public class JFRRecordedGraphWrapper> implements AttributedGraph, JFRRecordedGraphEdge> { + + private final AttributedGraph graph; + + public JFRRecordedGraphWrapper(AttributedGraph graph) { + this.graph = graph; + } + + @Override + public JFRRecordedGraphNode findNodeById(String id) { + FindNodeEvent event = new FindNodeEvent(id); + event.begin(); + N node = graph.findNodeById(id); + event.commit(); + return new JFRRecordedGraphNode<>(node); + } + + @Override + public Collection> findOutgoingEdges(JFRRecordedGraphNode node) { + FindEdgesEvent event = new FindEdgesEvent(node.id(), Direction.OUTGOING); + event.begin(); + Collection outgoingEdges = graph.findOutgoingEdges(node.getInternalNode()); + event.setFoundEdgesCount(outgoingEdges.size()); + event.commit(); + return outgoingEdges.stream().map(JFRRecordedGraphEdge::new).toList(); + } + + @Override + public Collection> findIncomingEdges(JFRRecordedGraphNode node) { + FindEdgesEvent event = new FindEdgesEvent(node.id(), Direction.INCOMING); + event.begin(); + Collection incomingEdges = graph.findIncomingEdges(node.getInternalNode()); + event.setFoundEdgesCount(incomingEdges.size()); + event.commit(); + return incomingEdges.stream().map(JFRRecordedGraphEdge::new).toList(); + } + + @Override + public String toString() { + return "JFRRecordedGraphWrapper [graph=" + graph + "]"; + } + + @Override + public int hashCode() { + return Objects.hash(graph); + } + + @Override + public boolean equals(Object obj) { + if(this == obj){ + return true; + } + if((obj == null) || (getClass() != obj.getClass())){ + return false; + } + JFRRecordedGraphWrapper other = (JFRRecordedGraphWrapper) obj; + return Objects.equals(graph, other.graph); + } + +} diff --git a/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/FindEdgesEvent.java b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/FindEdgesEvent.java new file mode 100644 index 0000000..b14a282 --- /dev/null +++ b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/FindEdgesEvent.java @@ -0,0 +1,43 @@ +package io.github.danthe1st.arebac.jfr.events; + +import java.util.Objects; + +import jdk.jfr.Category; +import jdk.jfr.Description; +import jdk.jfr.Event; +import jdk.jfr.Label; +import jdk.jfr.Name; + +@Name(FindEdgesEvent.NAME) +@Category(JFREventConstants.CATEGORY) +@Description("find edges of a specified node") +public class FindEdgesEvent extends Event { + static final String NAME = "io.github.danthe1st.arebac.jfr.events.FindEdgesEvent"; + + @Label("node ID") + String nodeId; + + @Label("outgoing") + boolean outgoing; + + @Label("incoming") + boolean incoming; + + @Label("foundEdgesCount") + int foundEdgesCount; + + public FindEdgesEvent(String nodeId, Direction direction) { + this.nodeId = nodeId; + Objects.requireNonNull(direction); + this.outgoing = direction == Direction.OUTGOING; + this.incoming = direction == Direction.INCOMING; + } + + public void setFoundEdgesCount(int foundEdgesCount) { + this.foundEdgesCount = foundEdgesCount; + } + + public enum Direction { + INCOMING, OUTGOING + } +} diff --git a/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/FindNodeEvent.java b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/FindNodeEvent.java new file mode 100644 index 0000000..9d218e8 --- /dev/null +++ b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/FindNodeEvent.java @@ -0,0 +1,21 @@ +package io.github.danthe1st.arebac.jfr.events; + +import jdk.jfr.Category; +import jdk.jfr.Description; +import jdk.jfr.Event; +import jdk.jfr.Label; +import jdk.jfr.Name; + +@Name(FindNodeEvent.NAME) +@Category(JFREventConstants.CATEGORY) +@Description("find a node by its ID") +public class FindNodeEvent extends Event { + static final String NAME = "io.github.danthe1st.arebac.jfr.events.FindNodeEvent"; + + @Label("node ID") + String nodeId; + + public FindNodeEvent(String nodeId) { + this.nodeId = nodeId; + } +} diff --git a/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/GetAttributeEvent.java b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/GetAttributeEvent.java new file mode 100644 index 0000000..68ab16e --- /dev/null +++ b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/GetAttributeEvent.java @@ -0,0 +1,42 @@ +package io.github.danthe1st.arebac.jfr.events; + +import java.util.Objects; + +import jdk.jfr.Category; +import jdk.jfr.Description; +import jdk.jfr.Event; +import jdk.jfr.Label; +import jdk.jfr.Name; + +@Name(GetAttributeEvent.NAME) +@Category(JFREventConstants.CATEGORY) +@Description("get an attribute of a node or edge") +public class GetAttributeEvent extends Event { + static final String NAME = "io.github.danthe1st.arebac.jfr.events.GetAttributeEvent"; + + @Label("element ID") + @Description("ID of the node or edge") + String elementId; + + @Label("attribute name") + String attributeName; + + @Label("element is node") + @Description("true iff this event represents getting the attribute of a node") + boolean isNode; + @Label("element is edge") + @Description("true iff this event represents getting the attribute of a edge") + boolean isEdge; + + public GetAttributeEvent(String elementId, String attributeName, ElementType type) { + this.elementId = elementId; + this.attributeName = attributeName; + Objects.requireNonNull(type); + isNode = type == ElementType.NODE; + isEdge = type == ElementType.EDGE; + } + + public enum ElementType { + NODE, EDGE; + } +} diff --git a/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/JFREventConstants.java b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/JFREventConstants.java new file mode 100644 index 0000000..77d8fa2 --- /dev/null +++ b/arebac-jfr/src/main/java/io/github/danthe1st/arebac/jfr/events/JFREventConstants.java @@ -0,0 +1,8 @@ +package io.github.danthe1st.arebac.jfr.events; + +public class JFREventConstants { + static final String CATEGORY = "AReBAC-jfr"; + private JFREventConstants() { + // prevent instantiation + } +} diff --git a/arebac-jfr/src/test/java/io/github/danthe1st/arebac/jfr/JFRTest.java b/arebac-jfr/src/test/java/io/github/danthe1st/arebac/jfr/JFRTest.java new file mode 100644 index 0000000..c50f5eb --- /dev/null +++ b/arebac-jfr/src/test/java/io/github/danthe1st/arebac/jfr/JFRTest.java @@ -0,0 +1,31 @@ +package io.github.danthe1st.arebac.jfr; + +import static io.github.danthe1st.arebac.data.commongraph.attributed.AttributeValue.attribute; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import io.github.danthe1st.arebac.data.memory.InMemoryGraph; +import io.github.danthe1st.arebac.data.memory.InMemoryGraphEdge; +import io.github.danthe1st.arebac.data.memory.InMemoryGraphNode; + +public class JFRTest { + // run with -XX:StartFlightRecording:filename=test.jfr + public static void main(String[] args) { + InMemoryGraphNode internalNode = new InMemoryGraphNode("someId", "type", Map.of("attr", attribute("some attribute value"))); + InMemoryGraphNode otherInternalNode = new InMemoryGraphNode("otherId", "type", Map.of("attr", attribute("some attribute value"))); + InMemoryGraphEdge internalEdge = new InMemoryGraphEdge(internalNode, otherInternalNode, "someEdge", "eType", Map.of()); + InMemoryGraph internalGraph = new InMemoryGraph(List.of(internalNode), List.of(internalEdge)); + JFRRecordedGraphWrapper jfrGraph = new JFRRecordedGraphWrapper<>(internalGraph); + JFRRecordedGraphNode foundNode = jfrGraph.findNodeById("someId"); + System.out.println(foundNode); + System.out.println(jfrGraph.findIncomingEdges(foundNode)); + Collection> outgoingEdges = jfrGraph.findOutgoingEdges(foundNode); + System.out.println(outgoingEdges); + for(JFRRecordedGraphEdge jfrRecordedGraphEdge : outgoingEdges){ + System.err.println(jfrRecordedGraphEdge.getAttribute("attr")); + } + System.out.println(foundNode.getAttribute("attr")); + } +} diff --git a/pom.xml b/pom.xml index 5ad9e59..5c9eb51 100644 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,7 @@ arebac-core arebac-neo4j + arebac-jfr