axonframework / scynapse   0.6.0

Apache License 2.0 GitHub

Scynapse - the Scala API for Axon Framework

Scala versions: 2.12 2.11 2.10

Welcome to the Scynapse

Scynapse enables the use of Axon with Scala

This version (0.6.0) works with Axon version 3.4

Axon 3 Upgrade notes

This version is compatible with Axon 3 and has some API changes in Akka system extension for the event bus (AxonEventBusExtension) The API for subscribing and unsubscribing now use Futures as return value instead of the Try[_]. Have a look at the AxonExtensionSpec for usage details and samples.

Note that 0.6.0 is the first version that supports Axon 3 and needs testing. Please give your feedback in the github ticketing system.

A quick start in using scynapse (core)

  1. Setup a structure with an event store that makes use of the XStreamSerializer found in scynapse-core

  2. Create your aggregate root as

    class MyAggregateRoot extends AbstractAnnotatedAggregateRoot[MyIdentifier]

    @AggregateIdentifier private var id : MyIdentifier = _

  3. Create your Commands and Events

Note that Commands need an annotation in order to route them to the proper AggregateRoot instance using the @aggregateId annotation

case class MyCommand(@aggregateId myId: MyIdentifier, otherParam: String)
  1. Have the Aggregate Root handle the commands that results in events

    @CommandHandler def handle(cmd: MyCommand) { apply(MyCommandHappened(id)) }

Creation of a new aggregate root works with a command and event handler like this:

 @CommandHandler
  def this(cmd: CreateMyAggregate) = {
    this()
    apply(MyAggregateCreated(cmd.myId, more values))
  }

  @EventHandler
  def on(e: MyAggregateCreated) = {
    id = e.myId 
  }
  1. Update the state (if required) in the aggregate root

    @EventHandler def on(e: MyCommandHappened) { someState = Some(e.otherParam) }

  2. Have event handlers in views build up specific state.

Integrate with Akka

scynapse-akka module provides facilities that make it easier to integrate Axon components with Akka.

Subscribing actors to events

AxonEventBusExtension allows to subscribe Akka actors to events published on Axon event bus. It is implemented as an Akka extension that manages event bus subscriptions.

In order to subscribe an ActorRef to the event bus you should first initialize an AxonAkkaBridge. Here is an example(using Spring):

import org.axonframework.eventhandling.EventBus
import com.thenewmotion.scynapse.akka.AxonEventBusExtension

val eventBus = getBean("eventBus", classOf[EventBus])
val axonAkkaBridge = AxonEventBusExtension(actorSystem) forEventBus eventBus

Then axonAkkaBridge can be used to subscribe actors to the Event bus:

val eventListener: ActorRef = context.actorOf(...)
axonAkkaBridge subscribe eventListener

After that eventListener actor will receive all events published to the event bus as simple messages.

To unsubscribe actor from the event bus:

axonAkkaBridge unsubscribe eventListener

If actor is terminated unsubscription occurs automatically.

Sending commands from actors

In order to make sending domain commands from Akka components easier a CommandGatewayActor was introduced. It is just a simple actor interface for the Axon CommandBus that dispatches all messages it receives to a command bus. A result returned by the command handler (if any) is sent back to the original command sender.

Example usage (again, we're using Spring context here):

import org.axonframework.commandhandling.CommandBus
import com.thenewmotion.scynapse.akka.CommandGatewayActor

val commandBus = getBean("commandBus", classOf[CommandBus])
val cmdGateway = actorSystem.actorOf(CommandGatewayActor.props(commandBus))

...

cmdGateway ! CreateOrder(...)

Make use of scalatest to test your domain logic

It's possible to make use of the Axon given -> when -> then test logic in scalatest and have matchers that work in scala style. The test in the scynapse-test package shows best in what way this works.

Dependencies

In order to make use of the the scynapse framework, you need to include in your build.sbt

For Scynapse core:

libraryDependencies ++= Seq(
    "org.axonframework.scynapse"        %% "scynapse-core"           % 0.6.0
)

For Scynapse akka:

libraryDependencies ++= Seq(
    "org.axonframework.scynapse"        %% "scynapse-akka"           % 0.6.0
)

For Scynapse test:

libraryDependencies ++= Seq(
    "org.axonframework.scynapse"        %% "scynapse-test"           % 0.6.0 % "test"
)

Development of Scynapse

For the development of scynapse, you need SBT The build is setup in the project folder and with

sbt publishLocal

You will build and publish the packages to your local machine.