I have an interface for a Service object that looks something like this (simplified for brevity):
public interface ItemService { public Item getItemById(String itemId, int version); public void create(Item item, User user); public void update(Item item, User user); public void delete(Item item, User user); }
ItemService only implementation and connects as a Spring bean. It is used by part of the user interface of our project and by code that processes Ajax requests to create and modify Item objects in our data warehouse.
Under the hood, each method sends a series of events when called. Events are taken by other modules to do things like update Lucene indexes, or send messages to administrators so they know something has changed. Each method call represents a single transaction in Spring (using org.springframework.orm.hibernate3.HibernateTransactionManager and org.springframework.transaction.interceptor.TransactionProxyFactoryBean ).
Recently, it became necessary to compose a series of method calls in one transaction. Sometimes with multiple services. For example, we can do something like:
*Begin transaction* Get Items created by User Bill using ItemService for each Item in Items Update field on Item Link Item to User Bill with LinkService Update Item using ItemService *Finish transaction*
We did this by creating another Service, which allows you to make calls from the Services using one method in the parent service. Lets call it ComposingService . ComposingService , like everyone else, is also managed by Spring, and since transactions are reentrant, this should work.
However, a problem arises: if any of these operations in the transaction failed, forcing the transaction to cancel , we do not want to send any events at all .
However, if the transaction fails, half of the events will be dispatched by the ItemService before the transaction returns, which means that some modules will receive a bunch of events for things that haven't happened yet.
We are trying to find some way to fix this, but we could not come up with anything elegant. The best thing we've come up with so far is something like this (and it's ugly):
public interface ItemService { public Item getItemById(String itemId, int version); public void create(Item item, User user, List<Event> events); public void update(Item item, User user, List<Event> events); public void delete(Item item, User user, List<Event> events); }
In this modified ItemService, and not about events dispatched immediately, they are added to the list of events passed as an argument. The list is maintained by ComposingService , and events are dispatched by ComposingService after all calls to ItemService and other services have completed successfully.
Obviously, the problem is that we changed the contract to ItemService ugly. Calling classes, even if they are services, does not have to worry about event management. But I could not think about it, therefore this question.
This seems like a problem that was probably resolved earlier. Has anyone had a problem that looks similar, and if so, how did you resolve it?