For the sake of simplicity, let's say that business process processes customer accounts.
There are several types of accounts (silver, gold, extra, ...). There is totally 30 types of customer accounts.
In the beginning of each month the process must be started.
Following code describes all business logic in two for cycles:-).
Transaction tx = null;
try {
tx = transactionManager.begin();
List<AccountType> accountTypes = accountTypesDAO.getScheduledAccountTypes();
for (AccountType accountType : accountTypes) {
List<Account> accounts = accountsDAO.getAccountsByType(accountType) // out of memory exception is thrown
for (Account account : accounts) {
AccountResult accountResult = processAccount(account); // makes some computation
accountResultsDAO.persist(accountResult); // persists result of computation
}
}
tx.commit
} catch (Exception e) {
if (tx != null)
tx.rollback();
}
This implemenation of BP does not work in reality, because total number of accounts of particular type
can be up to 1 000 000, so out of memory exception is thrown. The workaround could be following: I read only
ids of accounts (it's ok with memory). I split selected ids into sets of fixed size (let's say 250), and then
I read and process only acounts which have id in the set. Garbage collector frees memory transparently after
each set of ids is completely processed.
As I have written, the challenge was to use more computers to process the BP. That could save memory,
CPU load of single computers, scalability, load balancing etc... Primarily the performance could be much better.
I wanted to use JBoss ESB, because
1. I want to use messaging (I want to use parallel execution, but I do not want to create own threads in session beans, which is discouraged in J2EE. Messaging (MDB) is the ideal means for parallel execution in J2EE)
2. I want to make use of added value of ESB that gives to JMS, resp. MDB (routing,
action processing pipeline, splitters, aggregators, separation! of application logic and communication logic (I can not see this separation in MDB),....)
3. I have studied esb, transactions, distributed transactions, ws-transactions, jBPM,... a lot (more then half an year), I do not want to throw that time away.
4. I needed to integrate distributed transactions, I have a plan to create action classes that works with transaction. Action classes are ideal to place to put transaction logic. Distributed transaction support in JBoss-4.2.1 is ehmmm, poor (I can not see any distributed transaction support at all).
I have created following esb services.
1. ReadScheduledAccountTypes - The service begins distributed transaction. It is a splitter that reads
scheduled account types. Each type is inserted into a single esb message. The service then routes all created
messages to service ReadAccountIds.
2. ReadAccountIds - It's a splitter, that reads accounts ids of particular account type. It creates a lot of smaller
lists of ids from the one big list. The size of smaller list is configurable from jboss-esb.xml.
Each smaller list of ids is inserted into single esb message. The service then routes all created messages to
service ProcessAccounts.
3. ProcessAccounts - The service processes input message containing one set of accounts ids. It reads accounts of
particular ids from database. Then it processes these accounts and persists accounts results to database.
The service sends esb message to aggregator AccountAggregator.
4. AccountAggregator - The service aggregates results from service ProcessAccounts. When all
accounts of particular type are processed, it sends aggregated message to AccountTypeAggregator.
5. AccountTypeAggregator - It aggregates results from AccountAggregator. When all account types are processed,
I can commit distributed transaction and end whole business process. The service aggregates "aggregated messages".
As you can see, I use nested splitters and aggregators. To ensure that all acounts of particular type are aggregated in
one AccountAggregator, the ReadAccountIds splitter must choose one concrete AccountAggregator in a cluster. The service
ProcessAccounts uses special action RouteToAggregator that routes the result message to chosen aggregator.
The same applies to ReadScheduledAccountTypes and AccountTypeAggregator.
I have solve exception handling as well. I use faultTo in messages. For example if ProcessAccounts fails, it automatically sends message to chosen AccountAggregator, so no messages are lost.
Now I will write stuff about distributed transactions....
I am looking forward for your comments!
Pavel