Building Perfect Anti-Facades - Almost Without Layers, For Better Maintainability 📎
Sometimes you own the database and the requirements are driven by the customer / sponsor and so mainly by the UI. Decoupling from your own database is, in such scenario, not beneficial. In contrary the decoupling would make your code more complex and harder to maintain. In the case of a feature enhancement, you will have to maintain / enhance the mapping logic and all indirections as well.
Instead of hiding your domain objects behind a Service Facade, you could directly derive the objects from the database (e.g. through generation) and expose them directly (=per reference) to the UI. The presentation tier (JSF, Wicket and other server-centric frameworks) could even bind the persistent objects declaratively to the UI-components.
A stateful session bean is perfectly suitable for this job. The EXTENDED EntityManager keeps all, already loaded, JPA-entities managed. This approach has a significant advantage - there is no synchronization and manual loading of lazy references needed. The EntityManager reacts to transactions and flushes all "dirty" entities into the database. The transaction is initiated the empty save method. The EJB 3.X gateway is simple. It exposes the root / aggregate entity and is very similar to a domain repository:
@Stateful
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class OrderGateway{
@PersistenceContext(type=PersistenceContextType.EXTENDED)
EntityManager em;
private Load current;
public Load find(long id){
this.current = this.em.find(Load.class, id);
return this.current;
}
public Load getCurrent() {
return current;
}
public void create(Load load){
this.em.persist(load);
this.current = load;
}
public void remove(long id){
Load ref = this.em.getReference(Load.class, id);
this.em.remove(ref);
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void save(){
//nothing to do
}
}
The Gateway remembers the root entity and makes it accessible through a getter. This can be leveraged in declarative data binding (you could even navigate from the backing bean, through the Gateway into a JPA entity). A Gateway is very easy to test outside, as well as, inside the EJB-container.
The EJB 3.1 / JSF 2.0 project GatewayWarDeployment was tested with Glassfish v3 and NetBeans 6.8 / 6.7.1 and pushed into: http://kenai.com/projects/javaee-patterns/.
[See Gateway, page 101 in "Real World Java EE Patterns Rethinking Best Practices" book for more in-depth discussion]