Domain-driven design with Java EE 6

An object-oriented architecture for interactive applications

1 2 3 Page 3
Page 3 of 3

Rethinking J2EE best practices

The idea of a gateway became possible only recently, with the introduction of Java EE 5. In the J2EE world such a pattern wouldn't make any sense, because of the lack of inheritance and detaching capabilities in Container-Managed Persistence (CMP) 2.0.

The attempt to introduce such a pattern could become really interesting in real-world projects. You will probably experience some resistance. In the past, one of the important measurement points of a scalable architecture was the degree of coupling and number of layers. Such a metric applied to a gateway pattern would produce rather poor results. A gateway tries neither to encapsulate the PDOs nor to introduce another layer of indirection. The opposite is true: a gateway is glue between layers, because it tries to make access to the domain objects as easy as possible.

A gateway is the reaction to the "Leaky Abstraction" principle. No matter how hard you try to encapsulate a nontrivial implementation, it will always be leaky. It is therefore smarter to expose an already well-designed entity directly, instead trying to encapsulate it further. This is especially true for UI-driven projects. The customer drives the requirements from the UI perspective, so the implementation of a feature will affect the presentation tier first. Such changes are not local to the presentation tier and will hit the adjacent layers as well. The leakier the boundary between layers, the more beneficial will be the effects of introducing a gateway into your architecture.

The gateway's responsibilities

A gateway exposes PDOs directly to the presentation layer. The most important participant is the PDO and the UI itself. The gateway is just an intermediary and provides only the execution context for the PDOs. A gateway is responsible for:

  • Keeping the EntityManager open between method calls, so that the already known PDOs do not become detached.
  • As convenient and direct exposure of PDOs as possible.
  • Providing a defined synchronization point (the save() method ) and optional undo method (EntityManager#refresh).
  • Per-reference (local) access to the PDOs. This requires you to run the EJB container in the same JVM as your Web container. This is the default setting in most application servers.
  • Implementation of crosscutting operations and especially query methods.

A gateway, however, relies on some minimum set of PDO qualities as well:

  • PDOs should be designed to be directly accessed in the presentation. Their functionality should be well encapsulated.
  • A PDO's public methods should always leave the domain object in consistent state. This can't be achieved easily with plain getters and setters.

The presentation tier must be able to keep, or at least determine, user's state. Your Web framework should be capable of keeping the reference to the gateway associated with the user's session. This is already a given in JSF, can be easily achieved with Wicket, and is a little bit harder with plain servlets.

State, distribution, and scalability

The direct manipulation of domain objects without synchronization and lazy loading requires attached entities and direct per-reference access to the PDOs. Only then can the EntityManager flush the changed entities to the database. Working with always-attached entities in the UI layer also solves the lazy-loading problem. Although the entities are used outside the gateway, they remain attached. You don't need to preload the entities in advance or use fetch joins for that purpose in the gateway. Lazy loading will just work as expected.

Gateways are stateful, so every user gets his or her own gateway instance, which in turn is associated with an EntityManager. Each EntityManager instance maintains its own JPA entity cache. The EntityManagers are configured as PersistenceContext.EXTENDED, so the cache is not cleared after every transaction.

Furthermore, all PDOs will remain attached, in extreme cases for the length of the session. The size of PDOs in memory is hard to estimate in advance, but can be easily measured during a load test. Such tests do not have to be realistic; it's simply important to test the system's behavior under heavy load. A small proof of concept will help you better understand and estimate the application's scalability characteristics and hardware requirements. You can even attach a profiler to the server during the load test to get a sense of the system behavior.

Object-oriented persistence is not limited to use in stateful, server-centric environments. PDOs can be also used behind a stateless, remote service facade. In that case they remain attached for the length of the transaction and therefore the method invocation. After the invocation they become detached and must be reattached after every method call. Lazy loading and automatic synchronization between layers will not work and must be implemented manually. Usually you will not transfer the PDOs to the client. The invocation of business methods may lead to state changes in the PDOs that must be synchronized manually with the server. For that reason a stateless service facade already implies either the use of anemic persistent structures, or dedicated objects just for data transport between layers. Unfortunately this introduces a lot of plumbing and empty copy-logic.

In conclusion

Domain-driven design and service-oriented design are opposite approaches. Domain-driven design relies mainly on encapsulated objects with state and behavior, whereas SOA emphasizes the procedure (a service). Object-oriented applications tend to be stateful, SOA rather stateless. The best practices in one case become anti-patterns in the other.

Interestingly, SOA is a good match to SOAP services defined in Web Services Description Language (WSDL), which emphasize contracts and actions. In contrast, REST focuses on direct addressing and manipulation of resources, which is more compatible with the domain-driven approach.

This article is based on Adam Bien's forthcoming book: Real World Java EE Patterns: Rethinking Best Practices.

Consultant and author Adam Bien is an Expert Group member for the Java EE 6, EJB 3.1, and JPA 2.0 JSRs; a NetBeans Dream Team Member; and a Java Champion. He has edited several books about Java and J2EE technology. He is an architect and developer on Java EE 5 projects and participates in several open source projects as committer and owner. He is working on Real World Java EE Patterns: Rethinking Best Practices. Visit Adam's blog.

Learn more about this topic

  • The profiler shipped with NetBeans 6.5/6.7 supports remote profiling.

More from JavaWorld

1 2 3 Page 3
Page 3 of 3