AxonFramework + OSGi + JPA EventStore

Hi,
I’m working to integrate Axon in some OSGi/Apache-Karaf examples (https://github.com/lburgazzoli/lb-karaf-examples):

  • axon-data
  • axon-engine
  • axon-event-listener

The first thing I’ve noticed is that the axon-core jar is not OSGi ready so in Apache Karaf I’ve installed it trough Karaf’s bundle wrap functionality:

karaf@kha-1> install -s wrap:mvn:org.axonframework/axon-core/2.0
Bundle ID: 687

karaf@kha-1> la | grep axon
[ 687] [Active ] [ ] [ 80] wrap_mvn_org.axonframework_axon-core_2.0 (0)

Is there any plan to build an OSGi friendly distribution ?

Then when a dummy CreateDataCommand is sent to the framework. OpenJPA raises the following exception and roll-back:

2013-05-15 13:34:55,197|WARN |org.apache.openjpa |org.apache.openjpa.lib.log.SLF4JLogFactory$LogAdapter > Found no persistent property in “org.axonframework.eventstore.jpa.DomainEventEntry”
2013-05-15 13:34:55,217|DEBUG|wrap_mvn_org.axonframework_axon-core_2.0 |org.axonframework.unitofwork.NestableUnitOfWork > An error occurred while committing this UnitOfWork. Performing rollback…
2013-05-15 13:34:55,217|DEBUG|org.springframework.transaction |framework.transaction.support.AbstractPlatformTransactionManager > Initiating transaction rollback
2013-05-15 13:34:55,217|DEBUG|wrap_mvn_org.axonframework_axon-core_2.0 |org.axonframework.unitofwork.UnitOfWorkListenerCollection > Notifying listeners of rollback
2013-05-15 13:34:55,217|DEBUG|wrap_mvn_org.axonframework_axon-core_2.0 |org.axonframework.unitofwork.UnitOfWorkListenerCollection > Notifying listener [org.axonframework.repository.LockingRepository$LockCleaningListener] of rollback
2013-05-15 13:34:55,218|DEBUG|wrap_mvn_org.axonframework_axon-core_2.0 |org.axonframework.unitofwork.NestableUnitOfWork > Stopping Unit Of Work
2013-05-15 13:34:55,218|DEBUG|wrap_mvn_org.axonframework_axon-core_2.0 |org.axonframework.unitofwork.UnitOfWorkListenerCollection > Notifying listeners of cleanup
2013-05-15 13:34:55,218|DEBUG|wrap_mvn_org.axonframework_axon-core_2.0 |org.axonframework.unitofwork.UnitOfWorkListenerCollection > Notifying listener [org.axonframework.repository.LockingRepository$LockCleaningListener] of cleanup
2013-05-15 13:34:55,218|DEBUG|wrap_mvn_org.axonframework_axon-core_2.0 |org.axonframework.unitofwork.UnitOfWorkListenerCollection > Listeners successfully notified
2013-05-15 13:34:55,218|DEBUG|wrap_mvn_org.axonframework_axon-core_2.0 |org.axonframework.unitofwork.NestableUnitOfWork > Clearing resources of this Unit Of Work.
2013-05-15 13:34:55,218|DEBUG|axon-engine |m.github.lburgazzoli.examples.karaf.axon.cmd.CreateDataCommand$1 > onFailure => <org.apache.openjpa.persistence.ArgumentException>
2013-05-15 13:34:55,218|DEBUG|axon-engine |m.github.lburgazzoli.examples.karaf.axon.cmd.CreateDataCommand$1 > onFailure
<openjpa-2.2.2-r422266:1468616 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: You have specified Table annotation or XML descriptor element for MappedSuperclass “org.axonframework.eventstore.jpa.AbstractEventEntry”. A class designated as a mapped superclass can not have a separate table defined for it.
at org.apache.openjpa.persistence.jdbc.AnnotationPersistenceMappingParser.parseTable(AnnotationPersistenceMappingParser.java:530)
at org.apache.openjpa.persistence.jdbc.AnnotationPersistenceMappingParser.parseClassMappingAnnotations(AnnotationPersistenceMappingParser.java:350)
at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parseClassAnnotations(AnnotationPersistenceMetaDataParser.java:697)
at org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser.parse(AnnotationPersistenceMetaDataParser.java:415)
at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:260)
at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:586)
at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:396)
at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:388)
at org.apache.openjpa.meta.MetaDataRepository.resolveMeta(MetaDataRepository.java:693)
at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:649)
at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:417)
at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:388)
at org.apache.openjpa.jdbc.meta.MappingRepository.getMapping(MappingRepository.java:354)
at org.apache.openjpa.jdbc.meta.MappingTool.getMapping(MappingTool.java:682)[755:org.apache.openjpa:2.2.2]
at org.apache.openjpa.jdbc.meta.MappingTool.buildSchema(MappingTool.java:754)[755:org.apache.openjpa:2.2.2]
at org.apache.openjpa.jdbc.meta.MappingTool.run(MappingTool.java:652)[755:org.apache.openjpa:2.2.2]
at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.synchronizeMappings(JDBCBrokerFactory.java:154)[755:org.apache.openjpa:2.2.2]
at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.synchronizeMappings(JDBCBrokerFactory.java:164)[755:org.apache.openjpa:2.2.2]
at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.newBrokerImpl(JDBCBrokerFactory.java:122)[755:org.apache.openjpa:2.2.2]
at org.apache.openjpa.kernel.AbstractBrokerFactory.newBroker(AbstractBrokerFactory.java:209)[755:org.apache.openjpa:2.2.2]
at org.apache.openjpa.kernel.DelegatingBrokerFactory.newBroker(DelegatingBrokerFactory.java:156)[755:org.apache.openjpa:2.2.2]
at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:227)[755:org.apache.openjpa:2.2.2]
at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:60)[755:org.apache.openjpa:2.2.2]
at org.apache.aries.jpa.container.impl.CountingEntityManagerFactory.createEntityManager(CountingEntityManagerFactory.java:71)[59:org.apache.aries.jpa.container:1.0.0]
at org.apache.aries.jpa.container.context.transaction.impl.JTAPersistenceContextRegistry.getCurrentPersistenceContext(JTAPersistenceContextRegistry.java:152)[60:org.apache.aries.jpa.container.context:1.0.1]
at org.apache.aries.jpa.container.context.transaction.impl.JTAEntityManager.getPersistenceContext(JTAEntityManager.java:84)[60:org.apache.aries.jpa.container.context:1.0.1]
at org.apache.aries.jpa.container.context.transaction.impl.JTAEntityManager.persist(JTAEntityManager.java:278)[60:org.apache.aries.jpa.container.context:1.0.1]
at org.axonframework.eventstore.jpa.DefaultEventEntryStore.persistEvent(DefaultEventEntryStore.java:50)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at org.axonframework.eventstore.jpa.JpaEventStore.appendEvents(JpaEventStore.java:152)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at org.axonframework.eventsourcing.EventSourcingRepository.doSaveWithLock(EventSourcingRepository.java:119)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at org.axonframework.eventsourcing.EventSourcingRepository.doSaveWithLock(EventSourcingRepository.java:53)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at org.axonframework.repository.LockingRepository.doSave(LockingRepository.java:126)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at org.axonframework.repository.AbstractRepository$SimpleSaveAggregateCallback.save(AbstractRepository.java:167)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at org.axonframework.unitofwork.DefaultUnitOfWork$AggregateEntry.saveAggregate(DefaultUnitOfWork.java:312)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at org.axonframework.unitofwork.DefaultUnitOfWork.saveAggregates(DefaultUnitOfWork.java:277)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at org.axonframework.unitofwork.NestableUnitOfWork.commit(NestableUnitOfWork.java:48)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at org.axonframework.commandhandling.SimpleCommandBus.doDispatch(SimpleCommandBus.java:137)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at org.axonframework.commandhandling.SimpleCommandBus.doDispatch(SimpleCommandBus.java:103)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at org.axonframework.commandhandling.SimpleCommandBus.dispatch(SimpleCommandBus.java:75)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at org.axonframework.commandhandling.gateway.AbstractCommandGateway.send(AbstractCommandGateway.java:69)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at org.axonframework.commandhandling.gateway.DefaultCommandGateway.send(DefaultCommandGateway.java:85)[687:wrap_mvn_org.axonframework_axon-core_2.0:0]
at com.github.lburgazzoli.examples.karaf.axon.SimpleAxonEngine.send(SimpleAxonEngine.java:179)[754:axon-engine:1.0.0.SNAPSHOT]
at com.github.lburgazzoli.examples.karaf.axon.cmd.CreateDataCommand.doExecute(CreateDataCommand.java:42)[754:axon-engine:1.0.0.SNAPSHOT]
at org.apache.karaf.shell.console.OsgiCommandSupport.execute(OsgiCommandSupport.java:38)[14:org.apache.karaf.shell.console:2.3.0]
at org.apache.felix.gogo.commands.basic.AbstractCommand.execute(AbstractCommand.java:35)[14:org.apache.karaf.shell.console:2.3.0]
at org.apache.felix.gogo.runtime.CommandProxy.execute(CommandProxy.java:78)[14:org.apache.karaf.shell.console:2.3.0]
at org.apache.felix.gogo.runtime.Closure.executeCmd(Closure.java:474)[14:org.apache.karaf.shell.console:2.3.0]
at org.apache.felix.gogo.runtime.Closure.executeStatement(Closure.java:400)[14:org.apache.karaf.shell.console:2.3.0]
at org.apache.felix.gogo.runtime.Pipe.run(Pipe.java:108)[14:org.apache.karaf.shell.console:2.3.0]
at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:183)[14:org.apache.karaf.shell.console:2.3.0]
at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:120)[14:org.apache.karaf.shell.console:2.3.0]
at org.apache.felix.gogo.runtime.CommandSessionImpl.execute(CommandSessionImpl.java:89)[14:org.apache.karaf.shell.console:2.3.0]
at org.apache.karaf.shell.console.jline.Console.run(Console.java:175)[14:org.apache.karaf.shell.console:2.3.0]
at java.lang.Thread.run(Thread.java:722)[:1.7.0_21]

Is there any way to tell the framework that the exception org.apache.openjpa.persistence.ArgumentException is not fatal?

thx - luca

Hi Luca,

direct OSGi support has been crossing my mind, but hasn’t found it’s place on the concrete roadmap yet. Some OSGi related issues have been reported (related to ServiceLoader). I am planning to find a solution, to make it work in OSGi environments. Adding the necessary manifest entries to make the axon-core jar an OSGi bundle shouldn’t be too hard, but I don’t know if that’s enough. As you mentioned, bundle wrapping is pretty simple to do.

It seems that OpenJPA doesn’t allow the @Table annotation on an @MappedSupperclass. I checked the specification, but I couldn’t find anything about this.
Yes, you can indicate that the ArgumentException should not rollback the UnitOfWork. In the SimpleCommandBus, you can configure a RollbackConfiguration. By default, it rolls back on runtime exceptions only. By providing your own implementation, you can tell it to commit on ArgumentException.
Are you sure everything is properly persisted, even though the exception is raised?

Cheers,

Allard

Hi Allard,

I’ve configured the SimpleCommandBus to use my own RollbackConfiguration (configuration done through OSGi Blueprint) :

Hi Luca,

my bad. The rollbackOn method is only invoked for exceptions caused by the domain logic. In this case, the exception is caused by the “commit” of the UnitOfWork. It looks like I need to move the @Table annotations from the mapped superclass to the entities to make it work in OpenJpa.

I didn’t create issues for the OSGi related work yet. I will break it down to sensible items and create the issues soon.

Cheers,

Allard

I’ve sent a pull request https://github.com/AxonFramework/AxonFramework/pull/89 to make axon-core OSGi compliant.
Do you have any info about the issues with ServiceLoader? I may have a look at it as soon as I have a little time :slight_smile:

Hi Luca,

thanks for the pull request. I will look at it shortly.

The issues were discussed on the mailinglist: https://groups.google.com/forum/?fromgroups=#!topic/axonframework/1fgnW0CNUcQ. Check the message by Ivica Munitic, who describes the problems encountered.

Cheers,

Allard