Coder Social home page Coder Social logo

axonframework / axonframework Goto Github PK

View Code? Open in Web Editor NEW
3.2K 189.0 775.0 43.51 MB

Framework for Evolutionary Message-Driven Microservices on the JVM

Home Page: https://axoniq.io/

License: Apache License 2.0

Java 100.00%
java cqrs performance scalability event-sourcing domain-driven-design message-driven

axonframework's Introduction

Axon Framework

Maven Central Build Status SonarCloud Status

Axon Framework is a framework for building evolutionary, event-driven microservice systems based on the principles of Domain-Driven Design (DDD), Command-Query Responsibility Separation (CQRS), and Event Sourcing.

Axon Framework provides you with the necessary building blocks to follow these principles. Examples of building blocks are aggregate design handles, aggregate repositories, command buses, saga design handles, event stores, query buses, and more. The framework provides sensible defaults for all of these components out of the box.

The messaging support for commands, events, and queries is at the core of these building blocks. It is the messaging basics that enable an evolutionary approach towards microservices through the location transparency they provide.

Axon will also assist in distributing applications to support scalability or fault tolerance, for example. The most accessible and quick road forward would be to use Axon Server to seamlessly adjust message buses to distributed implementations. Axon Server provides a distributed command bus, event bus, query bus, and an efficient event store implementation for scalable event sourcing. Additionally, the Axon Framework organization has several extensions that can help in this space.

All this helps to create a well-structured application without worrying about the infrastructure. Hence, your focus can shift from non-functional requirements to your business functionality.

For more information on anything Axon, please visit our website, http://axoniq.io.

Getting started

Numerous resources can help you on your journey in using Axon Framework. A good starting point is AxonIQ Developer Portal, which provides links to resources like blogs, videos, and descriptions.

Furthermore, below are several other helpful resources:

  • The quickstart page of the documentation provides a simplified entry point into the framework with the quickstart project.
  • We have our very own academy! The introductory courses are free, followed by more in-depth (paid) courses.
  • When ready, you can quickly and easily start your very own Axon Framework based application at https://start.axoniq.io/. Note that this solution is only feasible if you want to stick to the Spring ecosphere.
  • The reference guide explains all of the components maintained within Axon Framework's products.
  • If the guide doesn't help, our forum provides a place to ask questions you have during development.
  • The hotel demo shows a fleshed-out example of using Axon Framework.
  • The code samples repository contains more in-depth samples you can benefit from.

Receiving help

Are you having trouble using any of our libraries or products? Know that we want to help you out the best we can! There are a couple of things to consider when you're traversing anything Axon:

  • Checking the reference guide should be your first stop.
  • When the reference guide does not cover your predicament, we would greatly appreciate it if you could file an issue for it.
  • Our forum provides a space to communicate with the Axon community to help you out. AxonIQ developers will help you out on a best-effort basis. And if you know how to help someone else, we greatly appreciate your contributions!
  • We also monitor Stack Overflow for any question tagged with axon. Similarly to the forum, AxonIQ developers help out on a best-effort basis.

Feature requests and issue reporting

We use GitHub's issue tracking system) for new feature requests, framework enhancements, and bugs. Before filing an issue, please verify that it's not already reported by someone else. Furthermore, make sure you are adding the issue to the correct repository!

When filing bugs:

  • A description of your setup and what's happening helps us figure out what the issue might be.
  • Do not forget to provide the versions of the Axon products you're using, as well as the language and version.
  • If possible, share a stack trace. Please use Markdown semantics by starting and ending the trace with three backticks (```).

When filing a feature or enhancement:

  • Please provide a description of the feature or enhancement at hand. Adding why you think this would be beneficial is also a great help to us.
  • (Pseudo-)Code snippets showing what it might look like will help us understand your suggestion better. Similarly as with bugs, please use Markdown semantics for code snippets, starting and ending with three backticks (```).
  • If you have any thoughts on where to plug this into the framework, that would be very helpful too.
  • Lastly, we value contributions to the framework highly. So please provide a Pull Request as well!

axonframework's People

Contributors

abuijze avatar alexelin avatar bliessens avatar codedrivenmitch avatar corradom avatar dependabot[bot] avatar github-actions[bot] avatar gklijs avatar hovenko avatar idugalic avatar jettro avatar jkuipers avatar joht avatar lfgcampos avatar m1l4n54v1c avatar mgathier avatar nklmish avatar premanandc avatar reda-alaoui avatar renedewaele avatar robvdlv avatar sandjelkovic avatar saratry avatar schananas avatar sgrimm avatar smcvb avatar snowe2010 avatar srmppn avatar timtebeek avatar vermorkentech avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

axonframework's Issues

Create connector to remotely connect event busses

Currently, an Event Bus is a JVM-local mechanism. There should be a series of connectors to bridge the gap between Event Bus implementations on different machines.
Remoting could be done:

  • point-to-point (useful with 2 connected jvm's)
  • using AMQP

Support for aggregate without extending an Axon class

During one of my presentations, someone came up with the idea/request to create a mechanism for event sourced aggregates that doesn't require extending an Axon-provided abstract class.

Events could be applied using a static method on another class. Uncommitted state could be kept in a "buddy" of each aggregate, which is located by the repository.

Needs further investigation to discover the advantages of such a mechanism.


Migrated from: http://code.google.com/p/axonframework/issues/detail?id=138

AnnotationCommandHandlerAdapter does not work with proxied objects

When an annotated handler is proxied with a Java proxy, the bean is not correctly inspected and wrapped as a [Command|Event]Handler. The reason being that Java proxies, unlike CGLib proxies, are not subclasses of the actual class being proxied.

Therefore, the AnnotationCommandHandlerAdapter should detect whether the given Object is a Proxy, and if so, inspect the Proxy's target instead of the Proxy itself.

See http://code.google.com/p/axonframework/issues/detail?id=172 for full history on this issue.

fresh clone of master branch does not compile tests: package org.apache.commons.collections.set does not exist

Using:

  • jdk1.6
    java version "1.6.0_29"
    Java(TM) SE Runtime Environment (build 1.6.0_29-b11)
    Java HotSpot(TM) 64-Bit Server VM (build 20.4-b02, mixed mode)
  • maven 3
    Apache Maven 3.0.3 (r1075438; 2011-02-28 18:31:09+0100)
    Maven home: /opt/maven
    Java version: 1.6.0_29, vendor: Sun Microsystems Inc.
    Java home: /opt/java/jdk1.6.0_29/jre
    Default locale: en_US, platform encoding: UTF-8
    OS name: "linux", version: "3.0.0-16-generic", arch: "amd64", family: "unix"
  • ubuntu linux 11.10

Console output:

chris@chris:~/dev/axon/AxonFramework$ mvn clean install
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] Axon Framework
[INFO] Axon Framework core
[INFO] Axon Framework Spring Integration Support
[INFO] Axon Framework Test Fixtures
[INFO] Axon Framework Distributed CommandBus
[INFO] Axon Integration tests
[INFO] Axon - MongoDB integration
[INFO] Axon - Google App Engine integration
[INFO] Spring Insight Plugin for the Axon Framework
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Axon Framework 2.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ axon ---
[INFO] 
[INFO] --- maven-install-plugin:2.3.1:install (default-install) @ axon ---
[INFO] Installing /home/chris/dev/axon/AxonFramework/pom.xml to /home/chris/.m2/repository/org/axonframework/axon/2.0-SNAPSHOT/axon-2.0-SNAPSHOT.pom
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Axon Framework core 2.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ axon-core ---
[INFO] Deleting /home/chris/dev/axon/AxonFramework/core/target
[INFO] 
[INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ axon-core ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 6 resources
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ axon-core ---
[INFO] Compiling 321 source files to /home/chris/dev/axon/AxonFramework/core/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ axon-core ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 22 resources
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ axon-core ---
[INFO] Compiling 143 source files to /home/chris/dev/axon/AxonFramework/core/target/test-classes
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] /home/chris/dev/axon/AxonFramework/core/src/test/java/org/axonframework/common/TestUtils.java:[19,41] package org.apache.commons.collections.set does not exist
[ERROR] /home/chris/dev/axon/AxonFramework/core/src/test/java/org/axonframework/saga/SagaManagerTest.java:[19,41] package org.apache.commons.collections.set does not exist
[ERROR] /home/chris/dev/axon/AxonFramework/core/src/test/java/org/axonframework/common/TestUtils.java:[31,15] cannot find symbol
symbol  : variable ListOrderedSet
location: class org.axonframework.common.TestUtils
[ERROR] /home/chris/dev/axon/AxonFramework/core/src/test/java/org/axonframework/saga/SagaManagerTest.java:[115,15] cannot find symbol
symbol  : variable ListOrderedSet
location: class org.axonframework.saga.SagaManagerTest
[INFO] 4 errors 
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] Axon Framework .................................... SUCCESS [0.497s]
[INFO] Axon Framework core ............................... FAILURE [10.111s]
[INFO] Axon Framework Spring Integration Support ......... SKIPPED
[INFO] Axon Framework Test Fixtures ...................... SKIPPED
[INFO] Axon Framework Distributed CommandBus ............. SKIPPED
[INFO] Axon Integration tests ............................ SKIPPED
[INFO] Axon - MongoDB integration ........................ SKIPPED
[INFO] Axon - Google App Engine integration .............. SKIPPED
[INFO] Spring Insight Plugin for the Axon Framework ...... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 10.956s
[INFO] Finished at: Mon Feb 20 11:18:39 CET 2012
[INFO] Final Memory: 19M/157M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:testCompile (default-testCompile) on project axon-core: Compilation failure: Compilation failure:
[ERROR] /home/chris/dev/axon/AxonFramework/core/src/test/java/org/axonframework/common/TestUtils.java:[19,41] package org.apache.commons.collections.set does not exist
[ERROR] /home/chris/dev/axon/AxonFramework/core/src/test/java/org/axonframework/saga/SagaManagerTest.java:[19,41] package org.apache.commons.collections.set does not exist
[ERROR] /home/chris/dev/axon/AxonFramework/core/src/test/java/org/axonframework/common/TestUtils.java:[31,15] cannot find symbol
[ERROR] symbol  : variable ListOrderedSet
[ERROR] location: class org.axonframework.common.TestUtils
[ERROR] /home/chris/dev/axon/AxonFramework/core/src/test/java/org/axonframework/saga/SagaManagerTest.java:[115,15] cannot find symbol
[ERROR] symbol  : variable ListOrderedSet
[ERROR] location: class org.axonframework.saga.SagaManagerTest
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
[ERROR] 
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <goals> -rf :axon-core

Spring namespace support for GenericJpaRepository

Configuring a GenericJpaRepository in Spring involves creating two beans and constructor injection. While, by default, a single XML element could suffice.

It should be as simple as <axon:jpa-repository aggregate="some.reference.to.MyAggregate" /> and perhaps an optional reference to the entityManagerFactory or persistence context name.

SimpleScheduleToken prevents serialization of Saga

When using the SimpleEventScheduler, it is not possible to store the sagas in the JpaSagaRepository (or any other persistent store). This is due to the SimpleScheduleToken, which contains a Future.

Instead, the Scheduler should keep a Map of ID to Future of all the tasks. The ID can be a randomly generated string, and is serializable. The future would allow the scheduler to cancel a schedule.

Add support of authentication to MongoTemplates

Fast solution is:

import org.axonframework.eventstore.mongo.DefaultMongoTemplate;
import com.mongodb.Mongo;
public class AuthenticatedEventStoreMongoTemplate extends DefaultMongoTemplate {
public AuthenticatedEventStoreMongoTemplate(Mongo mongoDb, String databaseName, String domainEventsCollectionName, String snapshotEventsCollectionName, String username, String passwd) {
super(mongoDb, databaseName, domainEventsCollectionName, snapshotEventsCollectionName);
mongoDb.getDB(databaseName).authenticate(username, passwd.toCharArray());
}
}

and

import org.axonframework.saga.repository.mongo.DefaultMongoTemplate;
import com.mongodb.Mongo;
public class AuthenticatedSagaMongoTemplate extends DefaultMongoTemplate {
public AuthenticatedSagaMongoTemplate(Mongo mongoDb, String databaseName,
String username, String passwd) {
super(mongoDb);
this.setDatabaseName(databaseName);
database().authenticate(username, passwd.toCharArray());
}
}

Update the AnnotatedSagaTestFixture so it calls the CommandCallback

For one of our Saga tests we needed the AnnotatedSagaTestFixture to call the CommandCallback. Currently this is missing in Axon (we are using version 1.3.3).

To solve our problem we made ore own implementation of AnnotatedSagaTestFixture that uses a "DelegatingCommandBus" where you can add multiple CommandBus instances to. We add the RecordingCommandBus and from the test our mock.

        fixture.getCommandBus().addDelegate(commandBus);
        doAnswer(new Answer<Object>() {

            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                ((CommandCallback) invocation.getArguments()[1]).onSuccess(null);
                return null;
            }
        }).when(commandBus).dispatch(anyObject(), any(CommandCallback.class));

Documentation Inconsistency: ctx with UUID not in AbstractAnnotatedAggregateRoot

http://www.axonframework.org/docs/1.2/domain-modeling.html#d4e392
public class MyAggregateRoot extends AbstractAnnotatedAggregateRoot {
private String someProperty;

public MyAggregateRoot() {
    apply(new MyAggregateCreatedEvent());
}

public MyAggregateRoot(UUID identifier) {
    super(identifier);
}

...

But only this is true:

protected AbstractAnnotatedAggregateRoot(AggregateIdentifier identifier) {
super(identifier);
eventHandlerInvoker = new AnnotationEventHandlerInvoker(this);
}

Update the file system event store

Due to the changes to the JpaEventStore that is responsible for using an UpcasterChain, (previously this was the responsiliby of the serializer) and the introduction of the EventMessageReader and EventMessageWriter the file system event store needs to be revised.

Aggregate test fixture doesn't handle server generated identifiers very well

If an aggregate generates his own identifier (especially if it is not a String), the aggregate test fixtures tries to compare that identifier to the one auto-generated by the fixture. If an ID is client generated, it is possible to use setAggregateIdentifier() on the fixture to tell it which ID to use.

Instead, the fixture should look at the events stored to find out which identifier is used. If there are "given" events, an identifier MUST be explicitly configured on the test fixture.

CommandTemplate

Many applications make use of similar structures of sending commands and waiting for processing to complete. Although the SimpleCommandBus will always return when processing is done, this is not guaranteed by the interface.

Therefore, a CommandTemplate class can provide commonly used features. The CommandTemplate is constructed with a CommandBus and should be thread safe.
The operations it should provide, are:

  • Object sendAndWait(Object command) throws ExecutionException, InterruptedException
  • Object sendAndWait(Object command, int timeOut, TimeUnit timeUnit) throws ExecutionException, InterruptedException, TimeOutException
  • Future<?> send(Object command)

all methods will check for the type of Object provided. If the given command implements CommandMessage, it is sent as-is, otherwise, the parameter will automatically be wrapped as payload in a new CommandMessage.

Need code examples

The reference guide is good if you know the jargon and patterns. But code examples of the parts of the framework would be essential to grow this project. For example, I am interested in implementing the Event Bus but I feel like I'm getting half the story from the guide. Code definitely speaks louder.

Make message MetaData immutable

What are the limitations you encounter in the current version? Please provide a simple use-case.
Messages are often passed along between multiple threads. Some components (especially the Auditing interceptor) depend on the ability to change en Event's MetaData. Immutable objects, however, as much safer to share between threads.

Please describe the enhancement you would like to have.
Make MetaData immutable and provide a way to construct a new EventMessage based on an old one, while passing in additional MetaData.

Do you have any ideas on how to implement the enhancement? If so, any suggestions are welcome.
A MessageBuilder or copy constructor should do the trick.

Add generic types for aggregate identifier

The aggregate identifier is now referred to using the Object type. Instead, the Aggregate interface could have a generic type to identify the type of identifier used to that aggregate. Repositories can use that identifier type to add type safety to the load method.

EventScheduler should always create new Message instance at scheduled time

The EventScheduler implementations provided in Axon all create a message at schedule creation time and store that for publication. This sets the timestamp of that message to the time it was added to the schedule.
Instead, the timestamp of the message should be set to the time at which the message is actually dispatched.

The API of the scheduler allows any object to be passed. If the object is a Message, it should extract payload and meta data and store that in the scheduler. Any other object will be interpreted as the payload for a message without meta data.

PessimisticLockManager concurrency related NullPointerException

The PessimisticLockManager generates occasional NullPointerExceptions when attempting to obtain a lock for an AggregateRoot. This seems to be triggered when there are multiple threads attempting to obtain the same lock concurrently, although it is sporadic enough to look garbage collection related.

Will attach a test case.

Improve Jpa (and FS) Event Stores so that only payload (and headers) need to be serialized

What are the limitations you encounter in the current version? Please provide a simple use-case.
Currently, the DomainEvent is serialized as a whole. All information Axon adds to the domain event is already stored separately from the payload (application specific potion) of the message. Therefore, only the payload needs to be serialized.

Please describe the enhancement you would like to have.
Put Axon-specific metadata in explicit table columns. Construct the DomainEventMessage using this data and pass the payload as byte[]. The payload only needs to be deserialized when getPayload() is invoked.

Generic test to verify that Aggregate state is only manipulated through event handlers

Having seen bits of code from multiple Axon projects, I notice that one of the major pitfalls in Axon is that internal aggregate state (counters, lists, etc) is inadvertently manipulated while handling commands, instead of through the event handlers. This can easily introduce bugs since it will cause the aggregate in memory to differ from the same aggregate when it is recreated by replaying the events from scratch (f.i. after restarting application).

It would be nice it there was a generic test to verify that aggregate state is only manipulated through event handlers. One way to verify this would be to

  • Create an aggregate with internal state by firing a batch of commands (might be random commands, or user-defined list).
  • Store the current aggregate internal state, and store any events caused by these commands
  • Create a new instance of the aggregate and apply each of the events
  • Compare the internal state of the new aggregate with the internal state of the stored aggregate.

If state was manipulated outside of the event handlers, then the 2 aggregates will differ and the test should fail. The test can indicate which aggregate fields contain the differences.

Alternatively, static code analysis can be used to detect field assignments in non-eventhandler methods

Allow commands as "given" in test fixtures

In some cases, it is very verbose to supply a list of "given" events. It is often easier to provide a set of commands as the "given". The fixture should then use the events generated by those commands as the input for the "when" command.

High performance snapshotter

What are the limitations you encounter in the current version? Please provide a simple use-case.
Creating an aggregate snapshot requires the application to read events from the event store. Even though this is (possibly) a parallel process, reading from the event store distracts it from its main purpose: writing to it.

Please describe the enhancement you would like to have.
A high-performance snapshotter could maintain a weak hashmap with the known aggregate root instances as key and a copy of that aggregate as value. When an event comes in from a known aggregate, it applies that event to the copy. When a request for a snapshot comes in, it is able to produce a snapshot from the aggregate copy without a read operation on the event store or a lock on the original aggregate.

By maintaining a weak reference, an aggregate is removed automatically when all other references to it are removed. After all, an unreferenced aggregate will not generate any events.

Do you have any ideas on how to implement the enhancement? If so, any suggestions are welcome.
The 'RunningCopyAggregateSnapshotter' (name may change during implementation) could attach a listener to the repository's aggregate cache. When an element is put there that implements the Clonable interface, it can create a copy straight away. If that interface is not implemented, it must read the aggregate from the event store once.
An eviction of the aggregate from the cache may trigger (configuration option) a snapshot too.

Check for availability of zero-arg constructor in aggregate entities

When a user uses entities to track the state of an aggregate Axon (or maybe only some serializers) a zero-arg constructor is required in order to rebuild that entity's state from a snapshot.

Currently rebuilding from snapshot will fail for entities not containing a zero-arg constructor. Solution is to somehow require these classes to have a zero-arg constructor.

NPE in SagaAnnotationInspector when associationValue is null

Scenario:

Create an Event that will be picked up by a saga. When you apply the event with a null value for the associationValue then you will get a null pointer in the SagaAnnotationInspector in the following code:

if (!deprecatedWarningGiven && !String.class.isInstance(associationValue) && !AggregateIdentifier.class.isInstance(associationValue) && !Number.class.isInstance(associationValue) && !associationValue.getClass().isPrimitive()) { logger.warn("****************************************************"); logger.warn("WARNING! Use of deprecated feature: In future versions of Axon only numbers (Integer, Long), " + "Strings, primitive types and AggregateIdentifier instances " + "are accepted as association value."); logger.warn("****************************************************"); deprecatedWarningGiven = true; }
(I'm using Axon 1.3.2)

Allow configuration of persistence unit in JPA-specific components

What are the limitations you encounter in the current version? Please provide a simple use-case.
Some of the components (e.g. JpaEventStore) use an EntityManager to retrieve entities from the persistent storage. This only works if it is a container managed EntityManager and there is only a single persistence unit.

Please describe the enhancement you would like to have.
If an application has multiple persistence units, it should be possible to configure the one to use.

Do you have any ideas on how to implement the enhancement? If so, any suggestions are welcome.
JPA uses annotations, which cannot be configured at runtime. Therefore, the EntityManager to use should be extracted in a "provider" class. In such case, an application developer could create a custom implementation that has the correct annotations.

See also: http://groups.google.com/group/axonframework/browse_thread/thread/d8a99c47a87f36e6

Distributed command bus

Currently, the command bus is limited to a single JVM. In larger systems, the command bus should be a mechanism that dispatches commands to different VM's.

The distributed command bus should distrubute the commands consistently over the VMs. That means that (as long as the hardware configuration does not change), commands for the same aggregate should be routed to the same machine. If the hardware configuration does change, routing should remain as consistent as possible, minimizing the need to transfer a lot of processing between machines.

The CommandBus implementation could use JGroups to manage membership, detect dropped instances and transfer data between the members. The consistent hashing algorithm can be used to consistently distribute commands between the members.

Create annotation based cluster selector

Create a ClusterSelector implementation that checks class-level annotations and assign listeners to a cluster based on the annotation type and parameters.
@AsynchronousEventListener annotated classes should be assigned to an asynchronous cluster.
In Spring XML config, a sub-element (<async .../> will be created to add async-specific configuration, similar to the new saga-manager style.

This feature deprecates the AsynchornousEventHandlerWrapper class.

Implement a disruptor-based high-performance commandbus

A command bus could use this mechanism and try to do as much "preprocessing" as possible, while leaving the actual command processing on aggregates to a single thread. Event storage and event publishing can be done by other threads, with ordering guarantees managed by the Disruptor's RingBuffer.

The current API for command handler interceptors and command handlers requires that the whole chain is executed in the same thread. This doesn't need to be a problem, if the aggregate is pre-loaded and attached to the UnitOfWork. The UoW would need to serve as a first-level cache for the repositories.

Migrated from http://code.google.com/p/axonframework/issues/detail?id=178

MongoEventStore should store "commit" as Document

MongoDB support transactions exclusively over a single document. To make sure either all events or none at all are stored when calling MongoEventStore#append(...), all events in the provided stream should be stored as a single document.

The commit will contain the same fields as the current "eventEntry", with the following differences:

  • the commit document contains the sequence numbers of the first and last event in the commit
  • the commit document contains a list of serialized events which are contained in a single commit

One commit only contains events from a single aggregate. If events from multiple aggregates are contained in the stream, a separate document (and thus commit) is created for each of the aggregates.

Provide infrastructure for replaying events

Event Listeners should be able to reconstruct themselves using events stored in the Event Store.

To accomplish this, event listeners can implement an interface, which is given a DomainEventStream from which events can be pulled. Alternatively, annotation support can be provided using @BeforeReplay and @AfterReplay (or similar) annotations to express the functionality needed before replaying starts and when it is completed. These methods allow the listener to clear tables and commit a transaction.

Allow configuration of automatic command retry

In some cases, a command fails with a Transient Exception. The CommandBus implementations provided by Axon should provide the capability to automatically retry a command when it fails with such an exception.
In case of the distributed command bus, if a machine drops while a command was being processed on that machine, the application developer must be able to indicate which commands can be resent to another machine, and which commands must be "dropped".

Automated creation of wiring diagram.

Reported by jatwill, Aug 3, 2010
We have Commands which speak to a CommandHandler which likely request an AR from a Repository and call a method on it. This method fires an Event which is handled by multiple EventHandlers.

It'd be amazingly handy to use something like JDT to parse the Java code and build a simple diagram (using Graphviz notation even) of the flow of commands and events in a system.

Comment 1 by project member buijze, Aug 3, 2010
James,

Thanks for you input! A very nice feature indeed. I have to admit my JDT / plugin development experience for Eclipse is about... ehm.. zero. I will need to rely on other people to help me with this. And since I am an IntelliJ user myself, there should be plugin for that as well :-)

An idea I had myself, closely related to this, is to allow to navigate to command and event handlers through shortcuts in their respective command/event. For example through an icon in the gutter next to the command or event declaration.

I have ideas to do similar things on the runtime environment as well, so you can see (for example) percentages and amounts of specific types of events.

For now, I am giving priority to getting the missing building blocks in Axon. I will put these features on the roadmap for after the 1.0 version.

Comment 2 by jatwill, Aug 4, 2010
Allard,

JDT is only the Java-language-parsing portion of Eclipse, it's usable separately outside of Eclipse (it's what GWT uses to do it's Java->JavaScript conversion for example); it should make it easier to query Java source and ask "Which methods call apply()?" and such.

Looking forward to 1.0; keep up the great work!

Comment 3 by project member buijze, Nov 5, 2011
The same code analysis mechanism as in issue #212 can be used here. By doing static bytecode analysis using ASM, we could detect all events and their aggregates and event handlers.


Migrated from http://code.google.com/p/axonframework/issues/detail?id=78

Remoting CommandBus

Provide a command bus implementation that support remoting. It consists of two components: a client (sender) and a server (receiver).

The protocol should support a command-context to be passed along with it. The server component could use that context to set and verify pre- and post handling conditions (such as setting a security context).

Race condition with garbage collector causing old Saga state to be produced

When a Saga runs for a while and the garbage collector kicks in in the meantime, the Saga state is reconstructed from an old SagaEntry.

To reproduce:
Start a saga that does multiple actions, some of which may cause the Saga to be invoked again. If, in the meantime, the garbage collector kicks in, one of these actions could be executed on old (illegal) saga state.

Asynchronous saga manager releases lock before committing transaction

The problem lies in the fact that the Asynchronous Saga Manager (and most other asynchronous processes as well) can use a transaction manager around the async process. Any locks to Aggregates may be released before changes to the aggregate are committed by the outer transaction.
The TransactionManager implementations (by Axon) should always check for the availability of a UnitOfWork. If there is none, it should create one. The delegated transaction should be attached to the unit of work (either the created one or the existing one).

Repository doesn't throw exception when storing wrong type of aggregate

From an email conversation:
The symptoms were the following :

  1. I instantiate a Foo object (Foo is an AR type). I add it to a
    repository, and then load it back later --> ok, it works
  2. I instantiate a Bar object (Bar is another AR type). I add it to a
    repository, and then load it back later --> fails, I get a "Cannot
    cast class Foo to Bar" !

When looking to Hibernate logs, I saw that the DomainEventEntry
corresponding to the creation of Bar actually had the aggregateType
"Foo" when being inserted in the db.

Ok, so one big headache later, I came to realize that I hadn't
declared the event sourcing repository for Bar in my Spring app
context.
So, instead of telling right to my face that I'm stupid, it looks like
Axon just tried to use another repository to store the event... which
worked. But, deserializing is another story :)

Expected behavior
Repositories should throw an exception when the type of aggregate is not assignable to the type they are configured to store.

Implementation details
The AbstractRepository should get a Class in its constructor that corresponds with the generic parameter of the Repository. This class can be used to verify the type of incoming aggregates.

Requires API change.

EventBus should allow more that one Event in the publish method

The EventBus interface now allows only a single EventMessage to be published. Some applications require a batch of events to be published in a single transaction. The current API does not provide a means to indicate the bounds of such a batch.

Therefore, change the EventBus API to have a vararg parameter of EventMessage, allowing any number of EventMessage instances to be provided. The same goes for the Cluster interface and any other interfaces that publish events.

Improve Event API by extracting application-specific payload

What are the limitations you encounter in the current version? Please provide a simple use-case.
The current Event implementation structure requires applications to create Events that extends one of the Axon provied implementations, e.g. DomainEvent.
Axon will add some extra information in these events, needed to identify the aggregate it belongs to and the order in which events should be read back in.

Please describe the enhancement you would like to have.
In the discussion group (http://groups.google.com/group/axonframework/browse_thread/thread/9e88daef9ff5e61f), Esfand suggested to introduce an explicit "payload". This payload is an application-provided POJO, untouched by Axon. Axon will keep its meta-data separate from that payload.

Do you have any ideas on how to implement the enhancement? If so, any suggestions are welcome.
See http://groups.google.com/group/axonframework/browse_thread/thread/9e88daef9ff5e61f.

Add support for guaranteed event processing in asynchronous event handler

Currently, when the application crashes while events are handled
asynchronously, unprocessed events may get lost.
Therefore, asynchronous event handlers should have the ability to maintain a
journal that keeps track of all processing actions.
Upon startup, this journal can be used to reproduce the last known state of
the event handler.
Since journals can become quite large, they should be compacted once in a
while. When an event queue is empty, the journal may be cleared.


This feature has a high level of complexity, but doesn't provide much more than can be achieved using existing products.

It is probably easier to use a MQ product to manage asynchronous queues. They already come with delivery guarantees (at most, at least, exactly once). So instead of creating a custom queue implementation, a connector should be made available to make it easy to connect to MQ products.


Migrated from http://code.google.com/p/axonframework/issues/detail?id=49

GenericAggregateFactory should use default no-arg constructor

Currently the GenericAggregateFactory requires a constructor with a single parameter: the aggregate identifier. Many other frameworks have chosen to rely on a no-arg constructor for "empty initialization" (e.g. Hibernate, Java Serialization, etc).

Initialization of the identifier could be done in the initializeState(DomainEventStream) method, by adding the identifier as parameter to that method.

Enhance Domain Model: allow any Object as AggregateIdentifier

What are the limitations you encounter in the current version? Please provide a simple use-case.
The application's domain model is "polluted" with Axon specific classes and interfaces. While most of these classes have limited scope (like the aggregates), some have a more public function.
The identifiers of aggregates are an example of such objects. They currently need to implement an Axon-specific interface, which makes them less re-usable on systems that don't need Axon.

Please describe the enhancement you would like to have.
Instead of relying on the AggregateIdentifier interface, Axon should accept any Object as aggregate identifier. When components rely on a String (e.g. JpaEventStore) for lookup purposes, a converter should be used to convert the Object to a String (a default converter will accept Number and String instances, and will call toString() on other objects).

Enhance EventStoreManagement

We're creating a service to browse the EventStore, but also to fetch all Events for a given Aggregate (or list of Aggregates).

It would be really nice if EventStoreManagement would allow something similar to visitEvents where it's possible to select on (at least) AggregateId level...

/Jeppe


Comment by Jason:

Hi Jeppe,

We are actually in the process of creating a monitoring interface to the event store for exactly this purpose. The idea will be that you can either query specific aggregates or start watching aggregates in real-time.

Jason

PessimisticLockManager should detect deadlocks

Deadlocks are inevitable from the framework's position. If two procesees try to lock multiple aggregates in a different order, there is always a possibility of a deadlock. Currently, the deadlocked threads are lost forever....
A deadlock monitor should (on regular intervals) check for deadlocks. The management factory provides access to an MBean that can detect deadlocks. If a deadlock is detected, the deadlock monitor should pick one of the threads and interrupt it. This allows the other thread to obtain the locks it required. The "losing" thread can reattempt its request.

Mongo MongoEventStoreBenchMark could be faster

I tried running the MongoEventStoreBenchMark today and I got this result on a box with Core i7, 8GB RAM, Intel SSD and OSX with Java HotSpot(TM) 64-Bit Server VM:

Result (MongoEventStoreBenchMark): 100 threads concurrently wrote 500 * 2 events each in 13271 milliseconds. That is an average of 7535 events per second.

Wouldn't the benchmark be more accurate if the datafile was preallocated to 512MB before the benchmark starts?
In the Mongo log those 13 seconds look like this, see the last six lines:

Fri Aug 26 17:37:45 [initandlisten] connection accepted from 192.168.166.92:55383
Fri Aug 26 17:37:45 [conn15] dropDatabase axonframework
Fri Aug 26 17:37:45 [initandlisten] connection accepted from 192.168.166.92:55384
Fri Aug 26 17:37:45 [FileAllocator] allocating new datafile /usr/local/var/mongodb/axonframework.ns, filling with zeroes...
Fri Aug 26 17:37:45 [FileAllocator] done allocating datafile /usr/local/var/mongodb/axonframework.ns, size: 16MB, took 0.008 secs
Fri Aug 26 17:37:45 [initandlisten] connection accepted from 192.168.166.92:55385
Fri Aug 26 17:37:45 [initandlisten] connection accepted from 192.168.166.92:55386
Fri Aug 26 17:37:45 [initandlisten] connection accepted from 192.168.166.92:55387
Fri Aug 26 17:37:45 [initandlisten] connection accepted from 192.168.166.92:55388
Fri Aug 26 17:37:45 [initandlisten] connection accepted from 192.168.166.92:55389
Fri Aug 26 17:37:45 [initandlisten] connection accepted from 192.168.166.92:55390
Fri Aug 26 17:37:45 [initandlisten] connection accepted from 192.168.166.92:55391
Fri Aug 26 17:37:45 [initandlisten] connection accepted from 192.168.166.92:55392
Fri Aug 26 17:37:45 [FileAllocator] allocating new datafile /usr/local/var/mongodb/axonframework.0, filling with zeroes...
Fri Aug 26 17:37:45 [FileAllocator] done allocating datafile /usr/local/var/mongodb/axonframework.0, size: 64MB, took 0.042 secs
Fri Aug 26 17:37:46 [FileAllocator] allocating new datafile /usr/local/var/mongodb/axonframework.1, filling with zeroes...
Fri Aug 26 17:37:46 [conn16] building new index on { _id: 1 } for axonframework.domainevents
Fri Aug 26 17:37:46 [conn16] done for 0 records 0.008secs
Fri Aug 26 17:37:46 [conn16] info: creating collection axonframework.domainevents on add index
Fri Aug 26 17:37:46 [conn16] building new index on { aggregateIdentifier: 1, serializedEvent: 1 } for axonframework.domainevents
Fri Aug 26 17:37:46 [conn16] done for 0 records 0secs
Fri Aug 26 17:37:46 [conn16] insert axonframework.system.indexes 706ms
Fri Aug 26 17:37:46 [conn19] building new index on { sequenceNumber: 1 } for axonframework.domainevents
Fri Aug 26 17:37:46 [conn19] done for 228 records 0.002secs
Fri Aug 26 17:37:46 [FileAllocator] done allocating datafile /usr/local/var/mongodb/axonframework.1, size: 128MB, took 0.626 secs
Fri Aug 26 17:37:50 [FileAllocator] allocating new datafile /usr/local/var/mongodb/axonframework.2, filling with zeroes...
Fri Aug 26 17:37:51 [FileAllocator] done allocating datafile /usr/local/var/mongodb/axonframework.2, size: 256MB, took 0.16 secs
Fri Aug 26 17:37:55 [FileAllocator] allocating new datafile /usr/local/var/mongodb/axonframework.3, filling with zeroes...
Fri Aug 26 17:37:56 [FileAllocator] done allocating datafile /usr/local/var/mongodb/axonframework.3, size: 512MB, took 0.949 secs
Fri Aug 26 17:37:58 [conn16] end connection 192.168.166.92:55384

NullPointerException when loading inexistent aggregate in GenericJpaRepository

The GenericJpaRepository throws a NPE when an inexistent aggregate is loaded. This should be an AggregateNotFoundException.

Cause of the bug is the lack of a null-check after an EntityManager.load(...) call.

Stacktrace:
INFO [org.axonframework.repository.LockingRepository] Exception
occurred while trying to load an aggregate. Releasing lock.
java.lang.NullPointerException
at org.axonframework.unitofwork.DefaultUnitOfWork.registerAggregate(DefaultUnitOfWork.java: 94)
at org.axonframework.repository.AbstractRepository.load(AbstractRepository.java: 71)
at org.axonframework.repository.LockingRepository.load(LockingRepository.java: 119)
at org.axonframework.repository.AbstractRepository.load(AbstractRepository.java: 79)
at com.atlaschase.falcon.commands.domain.repositories.aircraft.AircraftService.getAircraftFromHexcode(AircraftService.java: 20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.