Статьи

Использование JPA и CDI Bean с верблюдом на WildFly

Я на самом деле не планировал этого, но в месяц без конференции у меня была возможность еще немного покопаться и показать вам еще больше магии Camel о WildFly, которую обеспечивает подсистема WildFly-Camel.

Бизнес фон

Демо взято из одной на JBoss Demo-Central Кристиной Лин. Она демонстрирует использование коннекторов File и JDBC в Camel, а также добавила использование шаблона Spilled pattern и Exception. Сценарий демонстрации заключается в том, чтобы имитировать процесс транзакции между банковскими счетами. Входные данные представляют собой пакетный XML-файл, который содержит несколько транзакций. Это могут быть как внесение наличных, так и снятие наличных или передача информации о банковских счетах. В зависимости от типа транзакции они разливаются, и каждая транзакция извлекает соответствующую информацию из базы данных, выполняет транзакцию и рассчитывает комиссию за транзакцию до помещения их обратно в базу данных. Вы можете найти полный исходный код на GitHub .

Почему я это трогал

Some reasons: I actually don’t want to think about new business cases. And don’t just want to show you something in nitty-gritty details on a technical level. So, I thought it is a quick win to just take the scenario from Christina. Second of all, she is doing everything in Fuse, based on Karaf and using the XML DSL for the route definitions. I am just a poor Java guy, and learned to hate XML. Plus, she is using a couple of components, which I wouldn’t in a Java EE context.

Prerequisites — Getting The App Deployed

Before you begin, playing around with the demo, please make sure to have WildFly 8.2.0.Final installed together with the WildFly-Camel subsystem patch 2.2.0. Now feel free to fork the demo repository on my github account into a directory of your choice. It is nothing more than a maven Java EE 7 project with some additional dependencies. Just do a

mvn clean install

and deploy the resulting target/javaee-bankdemo-1.0-SNAPSHOT.war to your WildFly server.

There isn’t any UI in this example, so you basically have to watch the logfile and copy an xml file around. The src\main\in-data folder contains a bank.xml, which you need to copy over to your standalone\data\inbox folder. The second this is done, camel starts it’s magic.

The CustomerStatus

Everything begins with the standard Java EE app. The Entity CustomerStatus holds account information (ID, VipStatus, Balance). It also has some NamedQueries on it. Doesn’t look Camel specific at all. The in-memory H2 database, which WildFly uses as the default db, get’s pre-populated with the help of three scripts which are configured as schema-generation properties in the persistance.xml. I’m working with two customers here, named A01 and A02.

Camel And Java EE

The Camel bootstrapping is quite simple in this case. The BankRouteBuilder has a @ContextName(«cdi-context») annotation and is itself an application scoped startup-bean which contains all the needed routes for the little demo. Feel free to re-read and learn about other potential options to deploy / configure routes. The hawt.io console (http://localhost:8080/hawtio/) displays all of them nicely. The application has five routes.

ReadFile is the first one, which basically only ready the xml file and pushes the individual entries (split by an xPath expression) to the processTransaction route.

This one decides on whether it is a «Cash» transaction or a «Transfer» transaction. Respectively ending in «direct:doTransfer» or «direct:processCash«. I left all of the original xml route definitions in the BankRouteBilder as comments. Might be helpful, if you search for a particular solution.

Differences To The Fuse Demo

Christina used the Camel JDBC component a lot. It does all the heavy lifting and even the initial database setup. This is nothing we want to do anywhere, but especially not in a Java EE environment where we have all the JPA magic ready to use. In fact, there is a Camel JPA componente, but it is very limited and doesn’t really support NamedQueries or alike.

A very powerful way to work around that is to use the Camel Bean component with all the bean binding and the cdi component, which is already integrated. All the database access is managed via the CustomerStatusService. Which is basically a @Named bean which get’s an EntityManager injected and knows how to load CustomerStatus entities. It get’s injected into the RouteBuilder by simply referencing it in the bean endpoint:

.to("bean:customerService?method=loadCustomer")

I agree, that there is a lot of magic happening behind the scenes and the fact, that the CustomerStatusService depends on Camel classes is another thing, that I dislike. But this could be easily worked around by just @Inject-ing the service into the route and referencing it alike. I decided to not do this, because I wanted to keep the initial flow of Christina’s demo alive. She is working with the Exchanges a lot and relies on them. So, I stayed closer to her example.

A Word On Transactions

I am actually using an extended persistent context in this example and marked the updateCustomer method in the service as @Transactional. This is a very simple way of merging complete and updated CustomerStatus entities back into the database. The whole doTransfer route isn’t transactional right now. Even if the second customer isn’t in the system, the amount would still be withdrawn from the first customer account. I want to cover this at a later stage and a separate blog-post.

That’s it for now. Enjoy your weekend and playing with Camel and the WildFly Camel subsystem. Happy to receive your ideas or questions via @myfear or as a comment on the blog-post.