Skip to content
This repository has been archived by the owner on Mar 12, 2020. It is now read-only.

Commit

Permalink
Bolt support and more documentation #28
Browse files Browse the repository at this point in the history
  • Loading branch information
tdauth committed Apr 10, 2019
1 parent 0b85ba2 commit a0d14d4
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 16 deletions.
23 changes: 20 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,29 @@ There can be different backends which manage the state machine.

### Neo4J

This backend uses the GraphDB [Neo4J](https://neo4j.com/) (community edition) with an embedded database.
This backend uses the GraphDB [Neo4J](https://neo4j.com/) (community edition).
It uses [Neo4J-OGM](https://neo4j.com/docs/ogm-manual/current/) to map our types to the graph database.

Each state machine is represented by a separate graph database stored in a separate directory.
The relationship types correspond to actions.
Each relation has the property "counter" which contains the execution counter of the action.

Visualization: <https://neo4j.com/developer/tools-graph-visualization/>
Desktop application: <https://neo4j.com/developer/neo4j-desktop/>
We have to use a Bolt driver since the corresponding software does not support to visualize embedded databases etc.

Useful software:

* Visualization: <https://neo4j.com/developer/tools-graph-visualization/>
* Gephi: <https://gephi.org/>
* Desktop application: <https://neo4j.com/developer/neo4j-desktop/>
* IntelliJ IDEA plugin: <https://plugins.jetbrains.com/plugin/8087-graph-database-support>

Run neo4j with Docker:
```bash
docker run \
--publish=7474:7474 --publish=7687:7687 \
--volume=$HOME/neo4j/data:/data \
--volume=$HOME/neo4j/logs:/logs \
neo4j:3.5
```
The user has to be part of the group `docker`.
See <https://neo4j.com/docs/operations-manual/current/docker/>.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ resolvers += "sonatype-snapshots" at "https://oss.sonatype.org/content/repositor
libraryDependencies += "org.neo4j" % "neo4j" % "3.5.4"
libraryDependencies += "org.neo4j" % "neo4j-ogm-core" % "3.1.8"
libraryDependencies += "org.neo4j" % "neo4j-ogm-embedded-driver" % "3.1.8"
libraryDependencies += "org.neo4j" % "neo4j-ogm-bolt-driver" % "3.1.8"
libraryDependencies += "org.neo4j" % "neo4j-bolt" % "3.5.4"

// Dependencies to represent states and actions:
Expand Down
32 changes: 24 additions & 8 deletions src/main/scala/de/retest/guistatemachine/api/example/Example.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,38 @@ object Example extends App {
private val rootElementB = getRootElement("b", 0)
private val rootElementC = getRootElement("c", 0)
private val action0 = new NavigateToAction("http://google.com")
private val action1 = new NavigateToAction("http://wikipedia.org")

val stateMachine = GuiStateMachineApi.neo4j.createStateMachine("tmp")
stateMachine.clear()
val startState = new SutState(Arrays.asList(rootElementA, rootElementB, rootElementC))
val endState = new SutState(Arrays.asList(rootElementA))

stateMachine.getState(startState)
stateMachine.getState(endState)
println(s"All states after clearing: ${stateMachine.getAllStates.size}")

// TODO #19 The states do not exist after this although saved. Concurrent transactions?
val startSutState = new SutState(Arrays.asList(rootElementA, rootElementB, rootElementC))
val endSutState = new SutState(Arrays.asList(rootElementA))

println(s"All states ${stateMachine.getAllStates.size}")
stateMachine.getState(startSutState)

stateMachine.executeAction(startState, action0, endState)
println(s"All states after adding start state: ${stateMachine.getAllStates.size}")

println(s"All states ${stateMachine.getAllStates.size}")
stateMachine.getState(endSutState)

println(s"All states after adding end state: ${stateMachine.getAllStates.size}")

val startStateTmp = stateMachine.getState(startSutState)

stateMachine.executeAction(startSutState, action0, endSutState)
stateMachine.executeAction(startSutState, action1, endSutState)

val startState = stateMachine.getState(startSutState)
val numberOfOutgoingActionTransitions = startState.getOutgoingActionTransitions.size
println(s"Number of outgoing action transitions: $numberOfOutgoingActionTransitions") // TODO #19 No outgoing actions.

val endState = stateMachine.getState(endSutState)
val numberOfIncomingActionTransitions = endState.getIncomingActionTransitions.size
println(s"Number of incoming action transitions: $numberOfOutgoingActionTransitions") // TODO #19 No incoming actions.

println(s"All states after executing action0: ${stateMachine.getAllStates.size}")

/**
* Creates a new identifying attributes collection which should only match other identifying attributes with the same ID.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import scala.collection.concurrent.TrieMap
class GuiStateMachineApiNeo4J extends GuiStateMachineApi {
private val logger = Logger[GuiStateMachineApiNeo4J]
private val stateMachines = TrieMap[String, GuiStateMachineNeo4J]()
// TODO #19 Load existing state machines from the disk.
// TODO #19 Load existing state machines based on Neo4J graph databases.

override def createStateMachine(name: String): GuiStateMachine = {
val uri = getUri(name)
Neo4jSessionFactory.getSessionFactory(uri)
Neo4jSessionFactory.getSessionFactoryEmbedded(uri)
logger.info("Created new graph DB in {}.", uri)

val guiStateMachine = new GuiStateMachineNeo4J(uri)
Expand All @@ -26,7 +26,7 @@ class GuiStateMachineApiNeo4J extends GuiStateMachineApi {
case Some(stateMachine) =>
stateMachine.clear()
val uri = getUri(name)
Neo4jSessionFactory.getSessionFactory(uri).close()
Neo4jSessionFactory.getSessionFactoryEmbedded(uri).close()
true
case None => false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import scala.collection.concurrent.TrieMap
object Neo4jSessionFactory {
private val sessionFactories = TrieMap[String, SessionFactory]()

def getSessionFactory(uri: String): SessionFactory = sessionFactories.get(uri) match {
def getSessionFactoryEmbedded(uri: String): SessionFactory = sessionFactories.get(uri) match {
case Some(sessionFactory) => sessionFactory
case None =>
val conf = new Configuration.Builder().uri(uri).build
Expand All @@ -18,9 +18,22 @@ object Neo4jSessionFactory {
sessionFactory
}

def getSessionFactoryBolt(uri: String): SessionFactory = sessionFactories.get(uri) match {
case Some(sessionFactory) => sessionFactory
case None =>
// TODO #19 Retrieve server and login information from some user-defined config.
val conf = new Configuration.Builder()
.uri("bolt://localhost:7687")
.credentials("neo4j", "bla")
.build()
val sessionFactory = new SessionFactory(conf, this.getClass.getPackage.getName)
sessionFactories += (uri -> sessionFactory)
sessionFactory
}

def transaction[A](f: Session => A)(implicit uri: String): A = {
// We have to create a session for every transaction since sessions are not thread-safe.
val session = Neo4jSessionFactory.getSessionFactory(uri).openSession() // TODO #19 Close the session at some point?
val session = sessionFactories(uri).openSession()
var txn: Option[Transaction] = None
try {
val transaction = session.beginTransaction()
Expand Down

0 comments on commit a0d14d4

Please sign in to comment.