"JDO vs. Entity Beans", now that's a sensitive and politically-charged topic.
In an earlier message titled "Real Talk", Chester asked about comparisons between Entity Beans and JDO. I've put together a few thoughts.
I'd be interested in having frank and objective discussions on the merits of the two technologies. My current opinion is that Entity Beans do not compete with JDO on most of the essential issues. However I'm not a CMR expert yet, and there may be places where CMR is more advanced than JDO. The moment these discussions start, however, they seem rapidly to become "heated".
I've put down a list of points that I feel to be of significance. I've tried to be objective. Be aware, however, that this is necessarily a LONG post, and please read all of it before passing comment.
My suggestions regarding the motivation of JDO for a project in the face of Entity Beans would be along the lines of:
Entity Beans were originally (EJB 1.1) remote components, and this was the root of many problems. J2EE design patterns advise against using Entity Beans remotely, so there is little benefit in their having remote capabilities. Now, with EJB 2.0, Entity Beans can support local interfaces as well as remote ones. This mitigates earlier performance concerns of remote invocation.
JDO instances are not remote objects. They satisfy the requirements for persistent data in the JVM that employs JDO, and do not attempt to address other concerns.
Entity Beans are cached by the application server. Advanced J2EE application servers support distributed caches with inter-cache messaging to prevent applications from receiving dirty data.
JDO instances are cached by the persistence manager. Advanced JDO implementations support distributed caches with inter-cache messaging to prevent applications from receiving dirty data.
Entity Beans are "complex" components involving two interfaces, one class and potentially a primary key class as well. This is in addition to the complexity of component-based service lookup through JNDI (e.g. ejb-references).
JDO instances are objects that you have decided should be stored in databases. The source code does not have to implement any JDO-specific infrastructure interfaces. You must have a no-arg constructor, but it may be private if so desired.
Entity Beans have to be written as entity beans. They must abide by certain contracts and conventions. These are embodied by the lifecycle-methods and implementation of the EntityBean interface. Conventions include public fields for data (CMP1) and abstract methods for data (CMP2), and others.
With JDO, you can take an object you wrote yesterday (when you didn't think it needed to be persistent) and store it through JDO today. No JDO-specific design or coding is required (bar having a no-arg constructor that might be private).
With JDO you can even take a class that is not persistence-capable and create a subclass that is.
To use an Entity Bean you usually have to look up its Home Object through JNDI. Each class of entity bean has its own home object that must be looked up independently.
To use a JDO instance you need access to a PersistenceManager, obtained from a PersistenceManagerFactory that is looked up from JNDI. However the PersistenceManager is good for all classes of JDO instance - no separate lookups for different classes of instance.
A big word for managers, but it should be clear to developers.
Entity Beans are not polymorphic. They do not support inheritance in a meaningful way (inheritance of component interfaces is possible). The finder methods return instance of the Entity Bean class on which they are invoked, even though the data may conceptually pertain to a "subclass" thereof.
It could be said that Entity Beans were conceived to represent the contents of a particular database table, and since relational tables have no concept of "subclasses" an equivalent concept is unnecessary in Entity Beans. However, techniques for mapping inheritance hierarchies to combinations of one or more relational tables are well known, as are the heuristics for using inheritance to best effect when building a model.
JDO instances are polymorphic. What you get back is what you stored. If you store a subclass of Customer, then queries of the Extent of Customer will include the subclass, and the instance returned as part of the query result will be an "instanceof" the subclass. Queries can even be executed against the Extent of abstract classes; what you get back is a Collection of concrete subclasses matching the filter criteria.
Entity Beans provide searching functionality through find methods. The parameterization and implementation of these query paths is expressed by the developer in terms of find method signatures and EJBQL queries. This cannot be changed after the component is deployed. Searching beans in a "new" way requires the developers of the entity bean components to implement support for the "new" query path.
JDO provides a query language (JDOQL). Most O/R vendors also support SQL. These query languages return collections of instances. However the query path is chosen by the Application developer, and is not reliant on the provision of supporting query methods by developer of the domain object model.
Entity Beans have their data Loaded from and Saved to the database at the discretion of the J2EE application server. Thus the client does not have to explicitly "load" and "save" the entity bean. However the client does have to "find" the entity bean first.
JDO supports transparent persistence. This means that
1. If you want to "save" a new object, which will not be referenced by any other persistent instance, then you call makePersistent() to do so. However this is not the usual case. Usually you add a new (transient) object to an already persistent instance (e.g. adding a new Order to an existing persistent Customer). The developer does not have to make the instance persistent; it will become persistent on commit. This is known as Persistence-by-Reachability. (There's no Entity Bean equivalent.)
2. If you change an object and make it dirty these changes will be transparently made durable on commit. You never have to "save" an instance. (This is analogous to Entity Beans).
3. If you navigate a reference (this.orderline.order.customer) JDO will load the appropriate instance from the database (the orderline, the order, the customer) if it's not already in the cache. (I believe Container-Managed Relationships (CMR) provides equivalent capabilities for Entity Beans where the relationships are to other Entity Beans and are appropriately declared.)
Entity Beans support Container Managed Transactions, by which transaction semantics are declared in the bean's deployment descriptor and may be changed without changing the source code of the bean. Entity Beans must execute within a J2EE application server, which provides these services.
JDO instances can and usually do operate transactionally. The transaction management is XA-compliant, and can integrate with the J2EE UserTransaction if required. This allows JDO instances to be enrolled in the same transaction as any of your J2EE components (including Session/Entity/Message-driven beans).
However JDO also facilitates non-transactional operation. More usefully, JDO supports the transactional operation of non-persistent instances (Plain old java objects that have their state rolled back in sync with transaction rollback). Entity Beans do not support this, although a similar effect can be achieved (but not transparently) with Stateful Session Beans and the SessionSynchronization interface.
Finally JDO persistence managers support transaction demarcation outside a J2EE context if required. This is great for Web applications needing transactional data access but not wishing to involve an EJB tier. Thus you don't need a J2EE application server to use JDO as a persistence infrastructure.
Entity Beans allow authorization to be enforced on a per-method basis. The implementation is transparent to the bean, based on properties set in the deployment descriptor.
JDO does not have an analogous mechanism.
Usually, Entity Beans are fronted by Session Facade objects that handle transaction demarcation and method-level permissions. JDO instances can also be fronted by Session Facades in the same way.
With Entity Beans you can only achieve reuse if all applications seek to manipulate persistent data through the EJB container. Session Beans and Servlets/Custom Tags that go direct to the database bypass the entity bean and reduce the reuse of Entity Bean components.
JDO instances can be used components within a J2EE application server, or without one by Servlets/Custom Tags, by command-line command-line Java applications, and by Client-Server Swing/AWT/SWT applications. This variety of deployment options massively improves reuse.
** this section strays towards the subjective, but is an important point never-the-less **
Traditionally, usage of Entity Beans has caused developers to create mere Value Objects (entity beans) that manage persistent state, whilst putting behavior relevant to that state into one or more Session Facade (Session Bean) components. This is not mandated by J2EE, but is my personal experience of consulting in the field.
Object Orientation says Objects have State and Behavior. By putting the state into one component (the Entity Bean), and the behavior in another (the Session Bean), object orientation is compromised. This in turn affects the reusability of components.
JDO abstracts developers, designers and architects from the complexities of object persistence. Relationships of arbitrary complexity can be managed transparently. Thus we can now build object models where objects have State and Behavior. Such objects are inherently reusable.
This is an emotive topic and personally I have a reputation for "not liking" Entity Beans. However I have tried to be as objective as possible. I also admit to not being an expert as far as CMR is concerned. Where CMR affects the points I have raised I would like to know, to further my own expertise and provide better clarification to readers.
So, I've said my piece. What do you all think?
Kind regards, Robin.
Robin M. Roos