|
SYS-CON.TV Webcasts
Comments
Did you read today's front page stories & breaking news?
SYS-CON.TV
|
Top Links You Must Click On
General Java Coming Out of the JDO Closet
Coming Out of the JDO Closet
By: Yaron Telem
Feb. 1, 2002 12:00 AM
As part of building the infrastructures for a large J2EE project, we've spent the last few months designing and implementing a JDO-based O/R persistency framework. This framework provides our business logic programmers with the following features: an interface-based abstract view of the data-layer with full OO semantics, zero-need knowledge of the object-to-database mapping details, "delta" support, and more. This article presents the persistency framework that we've built on top of JDO, and offers a commentary on the current advantages and shortcomings based on our experience with the JDO specification.
Choosing an Object Persistency Layer
While all the above vendors offer (more or less) the features listed in Table 1, since we're especially zealous about standardization and vendor independence, we decided on JDO, a strategic decision. Left with choosing between entity beans and Java Data Objects (it was about a year ago that we made this decision), we went again for the second choice. Entity beans seemed rather too bulky and heavyweight for our purposes, obscuring the simple Java model while providing (unnecessarily in our case) factory-wrapped network interfaces and limited inheritance capabilities. We felt that JDO provided a simpler, cleaner API with pure OO syntax. Still another advantage of JDO lies in its relative lightness. (Note that by saying that we're certainly not trying to slight EJB entity beans. Indeed, the initial doubts about their true usefulness seem to have died out, especially after the improvements introduced in the EJB 2.0 spec.)
Short Overview of JDO
The JDO specification provides a flexible method for handling persistent objects. It originates from JSR-000012, approved in July 1999 - those not yet familiar with the spec should consult the "Resources" section of this article for the appropriate URL - and was designed to integrate with existing frameworks (most notably J2EE), offering more complete transactional facilities. Indeed, session beans can directly manipulate JDO persistent instances, while entity beans can delegate business logic and persistence management to JDO classes. In our project we took the first approach. Working with JDO, classes that can be made persistent implement the PersistenceCapable interface, but the class author need not explicitly declare this in the code. All a developer needs to do is to provide a companion XML file, which contains metadata about the class (e.g., the names of the fields that are to be made persistent). This XML metadata is used by a "class enhancer" to generate a persistence-capable copy of the original class. (JDO ensures binary compatibility between persistence-capable classes, even if generated by different vendors' enhancers.) As a result, all the details of the class's actual persistence management happen behind the scenes. Each JDO instance of a persistent class has its own unique identity in the datastore and hence can be shared between different applications concurrently. When a reference is followed from one persistent class to another, the JDO implementation transparently instantiates it as necessary into the JVM. When fields of a persistent object are accessed or modified, the JDO implementation transparently marks them for change in the datastore. Almost all user-defined classes can be made persistent. While this excludes most system classes (like those in java.io or java.net), some are handled specially by a JDO implementation. For instance, the java.util.Collection interface is supported, as are immutable classes like Integer, Float, String, and Date - in addition to arrays. The PersistenceManager is the primary interface for JDO-aware applications. It enables users to store and fetch persistent objects from the datastore and allows users to perform synchronized transactions and queries on those objects. JDO uses a neutral query syntax similar to OQL (Object Query Language).
Pros and Cons of JDO
JDO touts as an advantage its back-end and datastore neutrality. This is indeed a virtue of the specification. But on the other hand it entirely ignores various important O/R issues such as object locking paradigm and O/R mapping instructions (e.g., schema structure, referential integrity, constraints, and so on). That is, JDO can be categorized as a general object persistence framework, with no special interest in being "baptized" as a full-blown O/R persistence specification. Furnishing no O/R mapping guidelines (let alone standards) and leaving this important role to the different product vendors makes the application developer's life somewhat confusing. For instance, Kodo (www.solarmetric.com), ObjectFusion (www.prismtech.com), and IntelliBO (www.signsoft.com) don't use database-referential constraints. But other vendors may choose to do so. And while IntelliBO lets you define code mappings (translation of pre-defined values into more compact database representations), it requires you to use proprietary XML tags to do it. Aside from its current "O/R uncertainties," there's still some uncertainty surrounding JDO. Sun, by not making a very good job of telling us when to use EJB entity beans and when to use Java Data Objects, has added to the overall confusion. Furthermore, the current JDO vendors tend to be "niche vendors" in the Java industry. A major step toward the acceptance of JDO would happen when the "big guns" like IBM, Oracle, and BEA begin to follow suit and join them - something that's not yet happened. Finally, JDO has also managed to win itself some sour enemies. The infamous duel on TheServerSide.com between JDO specification lead Craig Russel and Thought Inc. CTO Ward Mullins is just one example (see "Resources"). Balancing the pros and cons of JDO, we believe that in spite of its current shortcomings JDO will mature into a pervasive first-class object persistency solution. An up-to-date portrait of the JDO market can be found on the JDO official site (see "Resources").
A Simple Approach to Working with JDO
The Java code pertaining to the UML specification is presented in Listing 1. Examining the syntax of class Age, a question arises: Is the use of an Integer necessary? Can't we simply use an int? Using the latter would, curiously enough, make it impossible to create an ageless life form, since there's no Java null value for int, thus no datastore NULL value for age. Of course, you can allocate a prespecified int value representing null (e.g., -1) but this would make writing your queries a tad peculiar. Writing the Java code, our next step is to run the vendor's JDO enhancer tool on the classes. Using the XML metadata file supplied in Listing 2, the enhancer will make these classes PersistenceCapable by applying direct bytecode manipulation. Some enhancers will automatically generate DD SQL statements (or directly create the database schema given a JDBC connection) as part of the enhancing process, while other vendors will politely ask you to run their schema-building tool. Notwithstanding, some vendors let you capture a preexisting schema and declare the O/R mappings yourself. Robust OO models should follow the real world. Thus, when our dog passes away, its fleas should gracefully pass along with it. The dog's best friend, however, won't (we hope). In JDO terms (see Listing 2) Dog and Man are First Class Objects (FCOs) - i.e., they possess an independent life cycle. On the other hand, Fleas are embedded in Dog as Second Class Objects (SCOs). SCOs have no JDO identity of their own and are stored/deleted from the datastore as part of their owning FCO. To complete the picture, note that Age and Name are embedded as SCOs in LifeForm. Finally, some business logic code using our data objects can be found in Listing 3. Observe that in deleteDog(Dog) it's enough to explicitly delete the Dog object. Its fleas are implicitly deleted from the datastore along with its Name and Age objects.
Performance Analysis (Round 1)
You're probably curious why Name and Age aren't represented as columns in LifeFormT, even though they've been declared as "embedded" SCOs. Well, in order to be consistent with the JDO specification, an O/R vendor must make the life cycle of Name and Age dependent on their owner, but there are no restrictions regarding the actual O/R mapping. All the vendors we've tested have failed to exploit the "embed" hint into a smart datastore embedding. It should be clear that the issue that causes a problem isn't the creation of the NameT and AgeT tables. Since a vendor's knowledge of the application semantics is limited to that defined in the metadata XML file, it would rightfully choose to generate the NameT and AgeT tables. Indeed, Name and Age could be used as an FCO or as elements of Collection in another part of the application. It's the lack of O/R embedding capabilities in cases analogous to LifeFormT that causes the problem.
Introducing Persistency Framework Based on JDO
Our JDO-based persistency framework introduces two additional layers, namely the interface layer and the wrapper layer, thereby attaining the following added-value goals:
Figure 3 shows the architecture of our framework. A vertical view of the framework reveals two major components: data entities (generated from the repository) and persistency management (an adapter, delegating the application persistency instructions to the concrete JDO implementation - e.g., persistence by reachability, JDOQL query engine, integration with EJB container, and so on). The horizontal view unveils the framework's layers: interface layer, wrapper layer, JDO layer, JDO implementation, and datastore. We won't go any further into the persistency management component, since it's mainly just an adapter. Readers eager to learn about persistency features are wholeheartedly directed to the JDO specification. Figure 4 presents the life form example, refactored to fit our framework. Relations connecting different layers are, as you can see, framework driven, while relations within a layer are OO-model driven. In fact, each layer encapsulates a "replica" of the life form model, using its own abstraction level to do so. Note that whereas Dog, Flea, and Man are explicitly represented throughout the layers, Name and Age are missing from the JDO layer. The reason for this will be made clear later.
Interface Layer
The interface layer (see Listing 4) provides a façade toward the business logic, allowing it to work in terms of abstract interfaces (Goal A). The clear separation between interfaces and implementing classes is not just a good programming practice, but also allows for a more loosely coupled compilation model. Moreover, as our data entities can implement multiple interfaces, we're able to provide different business logic modules with personalized local views of the data and enable the creation of generic mechanisms/algorithms operating on interfaces. For instance, one could declare Dog and Man to implement a Trainable interface. Doing that, it's possible to write a generic algorithm working in terms of trainable life forms.
Wrapper Layer
Wrapper objects make use of OO mechanisms such as reflection, dynamic invocation, dynamic proxy, lazy wrappings, and more. Their concrete code, being somewhat intricate (yet generic and actively generated), is not listed.
Object Embedding
1 public static void main(String[] args)Not surprisingly, we call this feature embedding, since the persisted ManJdo class actually embeds fields pertaining to several wrapper objects (e.g., NameImpl, AgeImpl). In fact, we use our metadata repository to define which fields in an entity are embedded and which are simply referenced. Our framework also supports (to some extent) the embedding of "complex" types, themselves containing multiple types, though the concrete implementation details would be out of scope. For instance, an Address composed of street, city, zip code, state, and country can be declared embedded in a Person. And while the business logic would work in terms of person and address interfaces, the only class to be actually persisted would be PersonJdo.
Delta Support and Change Tracking
Delta Support
As Listing 5 shows, each entity interface (implementation) has a matching - actively generated - delta interface (implementation) exposing only the getter (accessor) methods. This is both type-safe and logically firm. Our entities (in fact, the wrapper objects) support the creation and application of deltas by continuously keeping track of the changes made on them during the transaction. The delta-build and delta-apply code is entity-specific - i.e., it's actively generated along with each data entity. We chose this method over a general mechanism that uses reflection due to complexity, maintainability, and speed issues.
Change Tracking
JDO and Database Layers
Performance Analysis (Round 2)
Conclusion
In this article we've tried to contribute from our experience of doing just that by presenting the JDO-based framework we've built for our own project. We demonstrated how our framework attains the important added-value goals of abstraction and performance, while providing additional capabilities such as code generation, delta-oriented business logics, and more.
Resources
Reader Feedback: Page 1 of 1
Enterprise Open Source Magazine Latest Stories . . .
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
|
SYS-CON Featured Whitepapers
Most Read This Week |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||