Now that we have explored the details of JDO integration with EJB in this chapter, an often-asked question may be on your mind: "Should I use EJB in a given application?" The answer, as happens so often, is "It depends." Before proceeding, let's quickly recall what has been said in this chapter already. Enterprise JavaBeans come in three flavors: entity, session and message-driven beans. The authors of this book believe that JDO clearly offers a better alternative over EJB entity beans and advocate using JDO as primary persistence API within the service methods of session- and message-driven beans. Alternatively, directly using JDBC or possibly a combination of JDO and JDBC may also be applicable . However, as we have seen above and as readers familiar with the matter know, EJB-based development even with just two remaining bean types of interest represents a certain inherent complexity. The real question, then, is this: "Should I use EJB session- and message-driven beans at all?" Session- and message-driven beans are components in the EJB architecture, which essentially provides a distributed component model, plus features such as security, transaction management, and scalability. Another J2EE API provides similar features: the Servlets API. Servlets represent another kind of J2EE component architecture. It is worth comparing the two in more detail with respect to the features of interest to help decide whether EJB is appropriate for a given application:
Concluding briefly, the first (distributed components) and the last (transaction context propagation) issues are often the decisive ones in favor of EJB if an application requires such. For most other systems, most notably the common enterprise information systems (EIS) and productivity applications with mainly a Web-centric presentation tier and straightforward transactional requirements, a Servlet-only based architecture is generally simpler and makes more sense. [8]
If, while going through the above bullet points, you conclude "mixed" results for your application, a "mixed" approach may well be what you need: EJB session beans for remote invocation via RMI, plus a few thin and simple Servlets for HTTP-based access. In this scenario, the Servlets may use the EJB 2.0 local interfaces to forward requests to co-located session beans, or both session beans and Servlets could possibly access Plain Old Java components. Last but not least, a point must be made that this discussion centered specifically around the usage of the EJB session and message-driven beans and their APIs, and not J2EE application servers in general. Indeed, the J2EE universe and a compliant application server offers many other APIs such as JMS, Servlets, JSP, JCA, JDBC, JNDI, JavaMail, JTA with a JTS-compliant transaction manager for possibly distributed transactions, JMX, and so on. Modern J2EE application servers often also provide other services such as connection pooling and monitoring, hot deployment, clustering, cluster-related distribution and update features, security and user administration, generic monitoring, and management features. All of these other APIs and features are also available to and integrate with JDO-based enterprise applications on a server that chooses not to use the EJB component model. 9.5.1 Scalable JDO-based applications with clusteringIf scalability requirements are the only reason to develop an application based on the EJB component model, then a second look at alternatives is time well spent. Figure 9-4 is an illustration of a typical non-clustered scenario, which will be extended next . Figure 9-4. Simple system architecture with one server and no clustering.
Scalability in this context usually refers to clustering mechanisms where requests can be redirected by software (or a hardware load-balancer) to different physical Java virtual machines, often on physically different hardware boxes, depending on load and availability of servers. A clustered-system architecture is a goal generally for one or both of the following reasons:
Such features are often provided by J2EE application servers and are thus far unrelated to JDO. Enter JDO into the picture, and with the extensive caching that JDO implementations usually perform, a minor problem for clustering architectures appears: If nodes in a cluster are not aware of each other, and if each keeps an in-memory cache of persistent data, write access to a persistent object on one node quickly renders cached instances on other nodes out of date and thus invalid. Furthermore, concurrent modification of identical instances on different nodes arise as a related issue. Two basic approaches exist to counter the issue and make clustering possible:
Implementations of such cache synchronization features vary widely between JDO implementations, for those that offer such a feature at all, and include anything from simple broadcast UDP messages, to IP multicast-based solution, to a JMS-based one, or an HTTP-based one, possibly using SOAP or even RMI. This feature is not standardized in the JDO 1.0 specification, but is available from several JDO implementations. This type of feature is generally regarded as an implementation differentiator between vendors , and may not need standardization under the specification. Relevant implementations naturally do not interoperate . Configuration of a particular feature is highly dependent on the respective JDO implementation. However, such a clustered deployment configuration should be completely transparent to application logic, and using an implementation-specific cache synchronization feature may not be a major portability issue, because changing to another JDO implementation ( ideally ) only changes the runtime deployment configuration, but no code. In fact, the architecture used here is one of application-level clustering, as opposed to individual object-level clustering: The objects representing business entities, the business logic, caches, and the container are all co-located within one VM. Each node in such a cluster persists data directly to the underlying datastore. The nodes then use some sort of distributed caching coherency strategy akin to classical data replication among themselves . This architecture can perform particularly well for read-often, change-rarely data scenarios. Note that clustering using this approach can be applied both when using JDO from within EJB and when using JDO directly from, for example, the Web tier. Figure 9-5 visualizes such an architecture. Figure 9-5. Cluster with two server nodes running JDO implementations with cache synchronization on one database server. Note how the JDO implementations on both servers directly access the datastore.
9.5.2 Round-tripping approachesA slightly different approach to the one above is what is often known as "round-tripping" in its various forms. The basic idea is to provide a more or less lightweight client-side JDO PersistenceManager without access to the underlying datastore. Such a local PM can transparently request copies of objects from a master server, e.g., via a generic service with getAllObjects(Query q, String[] fields) and updateObjects(Object[] changedObjects) sort of methods, but provided by the JDO implementation and transparent to the application. Issues such as object graph diffing and instance reconciliation, relationship graph management, and instance insertion ordering have to be addressed by such implementations. In a less transparent and more explicit variation, an EJB session bean could send objects and partial object graphs that are copied to the remote machine, manipulated there, and then sent back for resynchronization with the original persistent objects. Such features are not standardized in the JDO specification, but are available in different shapes in some JDO implementations. Figure 9-6 visualizes such an architecture. Figure 9-6. Architecture of "Distributed JDO" with a round-tripping approach. Note how clients interact only with a server that accesses the datastore.
The architecture of such round-tripping approaches (sometimes referred to as "Distributed JDO") is generally more in line with optimistic/long-running transactions. It could typically be well suited for Swing-based fat GUI clients, for example, if security and code distributions implications are not a concern. Such approaches are not service-oriented in the traditional sense. Scalability of architectures based on such features should be evaluated in more detail before embarking fully on them. |