1- ) INTRODUCTION
In its relatively short lifetime the Java™ platform has achieved an unprecedented degree of acceptance by industry and academia. The Java programming language synthesized many good
ideas from earlier languages and married these with the unassailable heritage of the C family.
The simple but pragmatic package mechanism has supported the construction of a large collection
of reusable software packages that allows the Java platform to be applied to virtually all segments of the computing landscape.
The language provides a simple, yet powerful, object model, a strong, mostly static, type system, automatic storage management, and concurrency through built-in synchronization mechanisms. These language features are a major factor in the robustness and reliability of applications. However, the Java platform does not extend these virtues to the domain of persistent data (objects). Rather, the Java platform supports the traditional approach, that of input, computation and output, with an explicit transformation to an external representation occurring at the input/output points. In practice, this model is increasingly less applicable, as most applications now require access to volumes of data that demand an incremental approach, for which the transformation code becomes both a source of errors and a time and effort sink.
To mitigate this deficiency, several persistence mechanisms have been developed, many of which are written in the Java programming language. The natural desire to implement the mechanisms in the Java programming language, coupled with a strong resistance to additions to the Java virtual machine (JVM™), inevitably affects the extent to which a mechanism can support the full language and the performance that can be achieved. In addition, although the mechanism itself can leverage the portability of the Java platform, application development and deployment often become correspondingly more complex.
2- ) WHAT IS PERSISTENCE
To define a persistence framework in a few words and some properties, a persistence framework moves the program data in its most natural form (in memory objects) to and from a permanent data store, the database. The persistence framework manages the database and the mapping between the database and the objects. Persistence framework simplifies the development process.
3- ) PERSISTENCE IN THE JAVA PLATFORM
The first version of the Java Language Specification (JLS) did not address object persistence directly; the only reference to the concept appears in the specification of the transient modifier, a keyword that was essentially reserved for future use. With each evolution of the Java platform, the range of available persistence mechanisms increased, and we will briefly review the history of these developments.
The initial release of the Java platform, JDK™ 1.0, provided very limited support for persistence. There was the conventional mechanism to encode and decode basic types using input/output streams that could be connected to files in an external file system. There was also support for encoding and decoding a table of properties (java.util.Properties) to and from a stream.
With the JDK 1.1 release came support for Java Object Serialization (JOS), a mechanism that supports the automatic encoding and decoding of nearly any object to and from a stream, respectively. Unlike the property table encoding, which is textual, object serialization uses a standard binary encoding format. JOS is effectively the default persistence mechanism for the Java platform, and the second edition of the JLS refers to it in the specification of the transient modifier. JOS is also used as the argument marshalling protocol for Java™ Remote Method Invocation (Java RMI). At its lowest levels, JOS builds on the platform support for encoding and decoding basic types. As we shall discuss later, serialization suffers some serious problems with class evolution, and this led to a new system called “Long-term Persistence for JavaBeans™” that debuted in Java 1.4.
JDK 1.1 also introduced the Java™ Database Connectivity (JDBC) API as a standard way to communicate with a relational database through the SQL language. JDBC provided the springboard for a major assault by the Java platform on the enterprise computing domain and arguably is by far the most successful API in the Java platform. The designers were remarkably successful in marrying the Java programming language to SQL and, consequently, JDBC is very easy to use for straightforward database access. However, in the situation where the application requires an object-oriented view of the underlying data, for example, transforming foreign key relationships into equivalent inter-object references, the programming is considerably more complicated and error-prone. To address this issue many systems have been developed that attempt to automate the process, which is generally referred to as object-relational mapping. Most development environments provide some degree of support for this process. The JDBC API continues to evolve and has recently added support for directly mapping a class in the Java programming language to the equivalent type in the object-relational extensions to SQL.
In parallel with the JDBC development, the Object Database Management Group (ODMG) defined a binding of its object model to the Java programming language, and several object-database vendors provided implementations of the binding. Since object-databases are much less widely deployed than relational databases, and are less standard, which is reflected in the ODMG binding, this exercise was less successful. With the advent of the Java Community Process (JCP), the focus of this effort was replaced by a broader proposal, Java™ Data Objects (JDO). JDO aims to support a wide range of underlying persistent stores, including relational databases, while presenting an object model to the programmer that is similar to that defined by the JLS, but with a small number of restrictions and a few additions. Many of the object database vendors now support JDO in their products.
Paralleling these efforts was the collaborative research project between Sun Microsystems Laboratories and Glasgow University to specify and prototype orthogonal persistence for the Java platform (OPJ). This approach aimed for complete support for all aspects of the language with a very high degree of transparency. In essence OPJ added support for stable memory to the JVM, and the implications of this requirement on JVM implementations ultimately prevented its acceptance.
Finally, the success of the Java platform in the enterprise domain, begun by JDBC, led to the development of Enterprise JavaBeans™ (EJB), an ambitious attempt to marry a component model for application development with support for distributed transactions and legacy datastores. EJB forms part of the Java Enterprise Edition (J2EE™) [Sun03a] and is supported by all the major vendors. EJB provides transparency for persistence and transactions at the cost of a rigid and complex framework that limits the use of many of the standard features of the Java programming language.
4- ) PERSISTENCE FRAMEWORKS IN JAVA
- Apache OpenJPA
- Castor
- TJDO
- JDBM
- pBeans
- SimpleORM
- Speedo
- XORM
- Java Ultra-Lite Framework
- Smyle
- Space4J
- O/R Broker
- PAT
- Super CSV
- JGrinder
- QLOR
- Ibatis SQL Maps
- HIBERNATE
- Oracle Toplink JPA
- OJB
- Torque
- Cayenne
- Jaxor
- Prevayler
- JPOX Java Persistence Objects
- JDBCPersistence
- Ammentos
- Daozero
- Velosurf
- ODAL
- jPersist
- Mr. Persister
- SeQuaLite
- BeanKeeper
- Persist
- Ebean ORM
- LightweightModelLayer
4.1 -) Java Persistence API (JPA)
The Java Persistence API provides an object/relational mapping facility to Java developers for managing relational data in Java applications. Java Persistence consists of three areas:
- the Java Persistence API
- the query language
- Object/relational mapping metadata
4.1.1 -) Persistence Entities
An entity is a lightweight persistence domain object. Typically an entity represents a table in a relational database, and each entity instance corresponds to a row in that table. The primary programming artifact of an entity is the entity class, although entities can use helper classes. The persistent state of an entity is represented either through persistent fields or persistent properties. These fields or properties use object/relational mapping annotations to map the entities and entity relationships to the relational data in the underlying data store.
4.1.1.1 -) Requirements for Entity Classes
An entity class must follow these requirements:
- The class must be annotated with the javax.persistence.Entity annotation.
- The class must have a public or protected, no-argument constructor. The class may have other constructors.
- the class must not be declared final. No methods or persistent instance variables must be declared final.
- if an entity instance be passed by value as a detached object, such as through a session bean’s remote business interface, the class must implement the Serializable interface.
- Entities may extend both entity and non-entity classes and non-entity classes may extend entity classes.
- Persistent instance variables must be declared private, protected, or package-private, and can only be accessed directly by the entity class’s methods. Clients must access the entity’s state through accessor or business methods.
4.1.1.2 -) Persistent Fields and Properties in Entity Classes
The persistent state of an entity can be accessed either through the entity’s instance variables or through JavaBeans-style properties. The fields or properties must be of the following Java language types:
■ Java primitive types
■ java.lang.String
■ Other serializable types including:
■ Wrappers of Java primitive types
■ java.math.BigInteger
■ java.math.BigDecimal
■ java.util.Date
■ java.util.Calendar
■ java.sql.Date
■ java.sql.Time
■ java.sql.TimeStamp
■ User-defined serializable types
■ byte[]
■ Byte[]
■ char[]
■ Character[]
■ Enumerated types[]
■ Other entities and/or collections of entities
■ Embeddable classes
Entities may either use persistent fields or persistent properties. If the mapping annotations are
applied to the entity’s instance variables, the entity uses persistent fields. If the mapping
annotations are applied to the entity’s getter methods for JavaBeans-style properties, the entity
uses persistent properties. You cannot apply mapping annotations to both fields and properties
in a single entity.
4.1.1.2.1 -) Persistent Fields
If the entity class uses persistent fields, the Persistence runtime accesses entity class instance variables directly. All fields not annotated javax.persistence.Transient or not marked as Java transient will be persisted to the data store. The object/relational mapping annotations must be applied to the instance variables.
4.1.1.2.2 -) Persistent Properties
If the entity uses persistent properties, the entity must follow the method conventions of JavaBeans components. JavaBeans-style properties use getter and setter methods that are typically named after the entity class’s instance variable names. For every persistent property property of type Type of the entity, there is a getter method getProperty and setter method setProperty. If the property is a boolean, you may use isProperty instead of getProperty. For example, if a Customer entity uses persistent properties, and has a private instance variable called firstName, the class defines a getFirstName and setFirstName method for retrieving and setting the state of the firstName instance variable. The method signature for single-valued persistent properties is as follows:
Type getProperty()
void setProperty(Type type)
Collection-valued persistent fields and properties must use the supported Java collection interfaces regardless of whether the entity uses persistent fields or properties. The following collection interfaces may be used:
■ java.util.Collection
■ java.util.Set
■ java.util.List
■ java.util.Map
If the entity class uses persistent fields, the type in the above method signatures must be one of these collection types. Generic variants of these collection types may also be used. For example, if the Customer entity has a persistent property that contains a set of phone numbers, it would have the following methods:
Set getPhoneNumbers() {}
void setPhoneNumbers(Set) {}
The object/relational mapping annotations for must be applied to the getter methods. Mapping annotations cannot be applied to fields or properties annotated @Transient or marked transient.
4.1.2 -) Persistence Units
A persistence unit defines a set of all entity classes that are managed by EntityManager instances in an application. This set of entity classes represents the data contained within a single data store.
Persistence units are defined by the persistence.xml configuration file. The JAR file or directory whose META-INF directory contains persistence.xml is called the root of the persistence unit. The scope of the persistence unit is determined by the persistence unit’s root. Each persistence unit must be identified with a name that is unique to the persistence unit’s scope.
Persistent units can be packaged as part of a WAR or EJB JAR file, or can be packaged as a JAR file that can then be included in a WAR or EAR file. If you package the persistent unit as a set of classes in an EJB JAR file, persistence.xml should be put in the EJB JAR’s META-INF directory. If you package the persistence unit as a set of classes in a WAR file, persistence.xml should be located in the WAR file’s WEB-INF/classes/META-INF directory. If you package the persistence unit in a JAR file that will be included in a WAR or EAR file, the JAR file should be located:
- In the WEB-INF/lib directory of a WAR.
- In the top-level of an EAR file.
- In the EAR file’s library directory.
4.2 -) Enterprise JavaBeans (EJB)
EJB is a component architecture for the development of distributed business applications and forms part of the Java™ 2 Platform Enterprise Edition (J2EE™ platform). In exchange for following the EJB architecture, developers are provided transparent support for distribution, persistence, transactions and security. There is also the promise of a “write-once, run-anywhere” guarantee for EJBs, similar to that for standard Java classes, in any J2EE-compliant implementation. Beans are deployed in a container that forms part of a J2EE implementation, provides life-cycle support for the bean and interposes on all access to beans. Beans come in three forms: session, entity and message.
Session beans model workflow and typically support a specific client that is interacting with the system. Session beans are not intended to model persistent data although they may access datastores and may survive crashes. Session beans come in two forms, stateless and stateful. The former carry no data specific to a particular client and can be pooled and used for any invocation, whereas the former carry client-specific state and are bound to that client for the duration of the session. Since session beans do not model persistent data, we do not consider them further.
Entity beans are intended to correspond to persistent data, typically a row in a relational database table8 and have strong availability guarantees in the face of system failures. The persistence of entity beans can be managed directly by the bean (bean-managed) typically using JDBC, or managed automatically by the container (container-managed). Container-managed persistence might itself be implemented using a mechanism like JDO.
The EJB framework is relatively complex and involves the creation - at a minimum - of two interfaces, called home and remote and also an implementation class, referred to as the bean class.
This set is collectively referred to as the bean. The home interface is used for locating or creating bean instances and the remote interface is used by clients to invoke a bean’s business methods.
The bean class provides implementations for (some of) these methods as well as a number of callback methods required by the framework. The J2EE implementation will typically provide additional implementation classes, for example, of the remote interface.
Similar to JDO, EJBs follow a defined life-cycle, but it is more visible to the programmer because it is reflected by required callbacks from the container to the bean implementation class.
The programmer-provided bean implementation class must implement these callbacks. The lifecycle includes an explicit pooled state, which corresponds to an allocated but unassigned bean class instance. Pooled instances are activated as needed, for example, when a new persistent entity is created or when retrieved by a finder method from the underlying datastore. To support scalability, the life-cycle also includes passivation and activation transitions that allow a bean instance to be freed up, similar to memory paging in a virtual memory system.
EJB provides a query language, EJBQL, which can be used to implement finder methods directly. EJBQL supports the relational model, with some syntactic sugar to close the gap with the Java programming language.
In addition to the bean code, a developer must also provide a deployment descriptor, in XML, that provides information on the bean. This is used by bean assemblers and bean deployers and can be used to customize the bean to a particular environment. In EJB 1.0 this information was
coded in the Java programming language and used JOS as the persistence mechanism. The switch to XML in EJB 1.1 is indicative of the general trend away from JOS to XML.
4.3 -) Java Data Objects (JDO)
JDO is an attempt to provide “transparent persistence” for developers of Java applications, across a wide range of underlying datastores including relational databases, object databases and other custom datastores. It is an outgrowth of the work that was begun by the ODMG on the binding between the Java platform and object databases.
JDO therefore shares some similarities with OPJ in that both aim for transparency. The essential difference is that JDO explicitly introduces the existence of an external datastore that may be accessed concurrently by unknown third-parties, and that an explicit mapping exists between the JVM environment and the external store. OPJ, in contrast, addresses the stability of the Java object memory and associated JVM state. This difference is reflected in two key aspects of the JDO specification, namely the introduction of an additional form of object identity, JDO-identity, that subsumes JVM object-identity, and the specification of an object-model life cycle that introduces states, potentially visible to an application, such as “hollow,” where the object fields are not filled in from the corresponding data in the datastore. JDO-identity comes in three forms: Datastore, which is managed by the external store and unrelated to the fields of an object; Application, which is managed by the application and based on certain (primary-key) fields of the class; and Nondurable, which is managed by the JDO implementation for data that has no natural unique identifier, for example entries in a log file.
JDO is not transparent for all data types and explicitly introduces first-class and second-class objects for persistence purposes. These transparency limitations arise from two sources: firstly from the constraints imposed by the underlying datastores, which have to be treated as immutable legacy systems, and secondly from the fact that a JDO implementation must treat the JVM as a black box. In particular, although arrays in the Java programming language have some object-like features, they cannot be handled by the standard JDO bytecode post-processing (“enhancement”) as they are not full-fledged classes in the JVM. In consequence, arrays are second-class objects in JDO, and must be encapsulated inside a (persistent) class. In particular, if such an array is passed outside the class, modifications to the array will not be detected by the JDO implementation, leading to incorrect behaviour.
JDO includes a query subsystem that is accessed programmatically via the Query class. It operates over collections of objects and allows simple boolean conditions to be expressed using Java programming language syntax. JDO provides a way to access the entire extent of a class, and this typically forms the starting point for queries. JDO also allows objects to be looked up using JDO object identity, which is the other way to locate objects.
JDO defines a standard way to describe the details of the persistence of a class or package specified in XML. At a minimum this must specify which classes can be made persistent but may include details such as exactly which fields are to be persisted.
JDO defines the PersistenceManager class as the main client interface for controlling the system. Instances of PersistenceManager are themselves created by a PersistenceManagerFactory class that is created either from a properties file or by explicit instantiation in the code. Object creation and access must run inside a transaction bracketed by the begin and commit methods of the Transaction class. The current transaction can be accessed from the PersistenceManager instance.
4.4 -) Hibernate
Hibernate is an object persistence framework that simplifies object-relational mapping between a Java application and an underlying relational database. It does so by providing transparent persistence of POJOs, working as a "mediator" layer to provide automatic persistence and loading of objects from a Java application to database tables. With Hibernate, saving object state to and loading object state from a database is as easy as calling methods in Java objects. You don't have to manage low-level database operations from your application code; the Hibernate framework takes care of all the intermediate steps for you.
Its primary feature is mapping from Java classes to database tables (and from Java data types to SQL data types). Hibernate also provides data query and retrieval facilities. Hibernate generates the SQL calls and relieves the developer from manual result set handling and object conversion, keeping the application portable to all supported SQL databases, with database portability delivered at very little performance overhead.
Mapping Java classes to database tables is accomplished through the configuration of an XML file or by using Java Annotation. When using an XML file, Hibernate can generate skeletal source code for the persistence classes. This is unnecessary when annotation is used. Hibernate can use the XML file or the annotation to maintain the database schema. Facilities to arrange one-to-many and many-to-many relationships between classes are provided. In addition to managing association between objects, Hibernate can also manage reflexive associations where an object has a one-to-many relationship with other instances of its own type. Hibernate supports the mapping of custom value types. This makes the following scenarios possible:
- Overriding the default SQL type that Hibernate chooses when mapping a column to a property
- Mapping Java Enum to columns as if they were regular properties
- Mapping a single property to multiple columns
Hibernate provides transparent persistence for Plain Old Java Objects (POJOs). The only strict requirement for a persistent class is a no-argument constructor, not necessarily public. Proper behaviour in some applications also requires special attention to the equals() and hashCode() methods.
Collections of data objects are typically stored in Java collection objects such as Set and List. Java generics, introduced in Java 5, are supported. Hibernate can be configured to lazy load associated collections. Lazy loading is the default as of Hibernate 3.
Related objects can be configured to cascade operations from one to the other. For example, a parent such as an Album object can be configured to cascade its save and/or delete operation to its child Track objects. This can reduce development time and ensure referential integrity. A dirty checking feature avoids unnecessary database write actions by performing SQL updates only on the modified fields of persistent objects.
Hibernate provides a SQL inspired language called Hibernate Query Language (HQL) which allows SQL-like queries to be written against Hibernate's data objects. Criteria Queries are provided as an object-oriented alternative to HQL.
Hibernate can be used both in standalone Java applications and in Java EE applications using servlets or EJB session beans.
In Hibernate jargon, an entity is a stand-alone object in Hibernate's persistent mechanism which can be manipulated independently of other objects. In contrast, a component is subordinate to other entities and can be manipulated only with respect to other entities. For example, an Album object may represent an entity but the Tracks object associated with the Album objects would represent a component of the Album entity if it is assumed that Tracks can only be saved or retrieved from the database through the Album object.
Hibernate was developed by a team of Java software developers around the world led by Gavin King. JBoss, Inc. (now part of Red Hat) later hired the lead Hibernate developers and worked with them in supporting Hibernate.
The current version of Hibernate is Version 3.x. This version has new features like a new Interceptor/Callback architecture, user defined filters, and JDK 5.0 Annotations (Java's metadata feature). Hibernate 3 is now a certified implementation of the Java Persistence API 1.0 specification via a wrapper for the Core module which provides conformity with the JSR 220 JPA standard.
5-) CONCLUSION
Object relational mapping became important due to increasing coupling between relational database management systems and object oriented application concepts and development. In conclusion, it is clear that the impact of persistence on application code covers a wide spectrum, as does the performance of the resulting system. Access to persistent data is an important aspect of virtually all applications. The Java programming language follows the traditional approach of separating persistent data and transient data, leaving the management of persistence to applications or layered mechanisms. As today, this is the point where the technology on persistence frameworks have reached but we all know that everything but the change itself changes. I am sure that the point where these frameworks will reach in a year will be very far away from the current one.