J2EE systems that access existing or external information resources should avoid accessing those resources directly from multiple places in the source code. Such direct access entwines your business logic with the implementation details of an external resource. If the API to that resource changes (when, for example, you change resource vendors, or a new version is released, etc.), changes to your J2EE application source code will be necessary throughout the application, and the resulting testing burden can be considerable.
For some resources, either the EIS resource vendor or some third party provides a J2EE Connector Extension, which is an adapter that allows J2EE systems to interoperate with other EIS resources transparently and transactionally.
The JDBC interface, which makes vendors' proprietary technology accessible in an open way, is an example of a J2EE Connector Extension. Switching database implementations, even at runtime, is trivial with JDBC, because it hides the vendor-specfic implementation details in connection configuration data.
Connectors are a new technology, and few examples exist for EIS resources. This section describes how to use the Data Access Object (DAO) design pattern to encapsulate access to EIS resources and prepare for eventual migration to a J2EE Connector architecture-based interface.
If no J2EE Connector Extension is available for your EIS resource, a good alternative is to use DAO classes to represent the EIS system as an abstract resource. Instead of calling the EIS system directly from the enterprise bean, create a DAO class that represents the services your bean needs. This is an application of the Bridge design pattern, which makes an interface's implementation transparently replaceable by decoupling the implementation from the interface. A DAO class that "wraps" an EIS resource insulates the enterprise bean from changes in that resource. New versions or alternative implementations of your EIS resource can then be installed, and modifications to your J2EE application will be limited to the DAO layer. As an additional benefit, when a Connector becomes available for your EIS resource, you can replace the existing DAO implementation with one that simply dispatches calls to the Connector.
For example, imagine your organization is currently using a custom system to which your enterprise bean needs access. A DAO class can be responsible for presenting a "clean" (meaning vendor-neutral) interface to the enterprise bean, while handling the details of passing service requests from the enterprise bean to your custom system. This scheme is particularly advantageous when a single service request (from your J2EE server's point of view) requires access to multiple existing EIS resources (in other words, a DAO can act as a facade to multiple EIS resources.) This pattern can make it easier for your organization to change EIS services. When an existing EIS service is replaced, the existing DAO class can be replaced with a new DAO class that presents the new service to the enterprise bean in terms of the existing DAO interface. Isolating your enterprise bean functionality with a DAO layer makes easier for your J2EE system design to evolve with time.
Keep in mind that the DAO class should reflect the functional requirements of the services your enterprise beans need, not necessarily the structure of your existing system. A DAO class's interface should reflect a single, clear idea. A DAO class called
TheOldSystem is probably not well-chosen as a DAO class, because it describes existing system structure, instead of abstract system services. Instead, analyze what the existing EIS system does, and group conceptually-similar methods into DAO classes which provide medium-grained access its services.
For example, instead of a designing a class called
TheOldSystem, the DAO classes representing the existing system might be called
Payroll, and so on. Likewise, if multiple EIS resources are currently necessary to do a single task, the DAO class can unify access to these systems and present them to an enterprise bean as a single service (there's the facade pattern again).
Avoid letting the structure of existing EIS resources dictate the structure of a new system. Instead, design the new system with your requirements and goals in mind, and then analyze how to use existing and/or legacy resources as services to meet those requirements.
A DAO class should be neither a "Swiss Army knife" (a haphazard collection of unrelated tools), nor an "oyster fork" (a tool designed for precisely one application), but something that cleanly and completely represents a clear, useful, and preferably reusable abstraction. Several UML diagrams, in particular Collaboration, Statechart, Activity, and Package diagrams, can be very helpful in performing this analysis. Also, Object Interaction diagrams are useful in analyzing the behavior and dependencies of existing systems.
The Java Pet Store uses the DAO pattern for another application, abstract persistence management. Each entity enterprise bean class, as well some other classes (like the screen flow configuration file), use a DAO class to manage its persistence. The DAO class handles the details specific to a particular persistence mechanism (such as a particular database, or an XML file in a JAR), hiding those details from the enterprise bean. The bean focuses on implementing business functionality, and defers persistence details to the DAO. The persistence scheme for an enterprise bean can be changed simply by specifying a different DAO class. The Data Access Object (DAO) design pattern documents the DAO pattern in more detail.
It's usually best to enforce value and referential integrity in the database, if possible, not in the EJB tier. Modern databases include declarative value and referential integrity constraint features, usually integrated with the DDL (Data Description Language), and commonly also provide built-in declarative triggers such as cascading deletes. Implementing these in the enterprise bean layer would duplicate logic, making maintenance more difficult (because any change to the database constraints would require making the change to enterprise beans and to the database).
Benefits of placing data integrity constraints in the database layer include:
Drawbacks of using built-in database integrity constraints mechanisms can include:
Value and referential integrity constraints may also be implemented in the EJB tier. The constraints you need for your application may simply not be available in the databases you choose. Or perhaps your data model has constraint requirements beyond the capabilities of the database's constraint language. Such constraints can reasonably be implemented in the EJB tier. EJB-tier constraint management also provides portability, since the enterprise beans will operate identically in J2EE-branded containers. Constraints in the EJB tier can also be controlled by way of environment settings in the application deployment descriptor, centralizing constraint management and making it controllable at deploy time.
A third option is to implement constraints in both the EJB and database tiers, and configuring the constraint implementation at deploy time. This strategy is useful especially when an application must be portable to many different databases, and you want consistent behavior across vendors, while optimizing performance by using each database's full power.
Yet another option is to create a "persistence server" for the EIS tier. Ideally, constraints should be expressed in a declarative constraint language provided by the database vendor. In the absence of such mechanisms (for example, if using light-weight runtime databases), you can choose to wrap a layer of integrity management software around the "raw" database API, and make only the API of the new layer available to outside clients. The EIS tier of your application can be a custom persistence server (or API) that you create to wrap the database. Your application accesses the data store only through that server. This application of the Decorator design pattern can provide a solution which is portable across databases, is declaratively configurable, and provides a consistent constraint behavior across client types. It's also a great deal of work to design, construct, test and maintain, and for that reason is not the recommended solution.
Finally, commercial transaction processing (TP) monitors provide the benefits of the persistence server described above. TP monitors can be purchased instead of built, can provide excellent scalability and availability, and commonly work with multiple database vendors. You can avoid becoming locked in to the TP monitor vendor's technology by wrapping calls to it in DAO classes, and still reap the benefits of a custom transaction processing monitor solution in the EIS tier.