The first design was very simplistic: entity beans simply map to database rows with no functionality (Entity Beans as Data Gateways) with session beans performing the business logic and transaction demarcation. The main business method ended up being several pages long and involved a few queries and a couple inserts/updates. As the domain has to handle some fairly involved logic (mimicing singleton behavior within a cluster), and that the first design was a prototype, I redesigned it.
The second design follows Entity Beans as Domain Objects: all domain logic was moved from the session beans to the entity beans. Now the huge procedural method above has been broken apart into several small, reusable methods living in the appropriate entity beans. This works fairly well, except that it will not work completely in a clustered environment. So again I hit the drawing board.
The third and current design is much more involved. I created POJO domain objects and domain stores (find/load entity beans and create domain objects from them). For each domain object there are six classes. For example, the main object Source has
Source [intf], BaseSource, and EjbSource
SourceStore [intf], BaseSourceStore, and EjbSourceStore
The base domain objects perform as much EJB-independent business logic as possible. The Ejb<foo> subclasses handle transactions and mirroring the logic in the entity beans.
I built the domain such that -- within a single cluster node -- there is exactly one instance of any single domain object. Work is performed by synchronizing access to the domain POJOs (via Syncs from Doug Lea's concurrent package), starting a transaction, modifying the entity beans, committing the transaction, and if it succeeds, performing similar logic on the domain objects themselves.
Now, there are patterns for mapping domain objects to entity beans and vice versa. However, if a problem occurs during the write to the persistence layer, the domain objects will then be in an inconsistent state. As well, without locking the domain objects, how do you let two threads see different values (and much more difficult, different *relationships*) since each is in their own transaction?
Am I barking up the wrong tree? Or is this a good design if I have enough time or tools to build out the same services the container provides for entity beans? I'm at the point now where time is short, and I need to decide whether I should go back to the second design or find a better pattern. Either way, I think this new design is going to fall flat or by much too complicated to finish in time or support later.