We will once again use Java generics to define a common ancestor class that will be extended by each of our implementation classes (CompanyDaoImpl
, ProjectDaoImpl
, TaskDaoImpl
, TaskLogDaoImpl
, and UserDaoImpl
). The GenericDaoImpl
and all other implementing classes will be added to the same com.gieman.tttracker.dao
package as our DAO interfaces. Key lines of code in GenericDaoImpl
are highlighted and will be explained in the following sections:
package com.gieman.tttracker.dao; import java.io.Serializable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; public class GenericDaoImpl<T, ID extends Serializable> implements GenericDao<T, ID> { final protected Logger logger = LoggerFactory.getLogger(this.getClass()); @PersistenceContext(unitName = "tttPU") protected EntityManager em; private Class<T> type; public GenericDaoImpl(Class<T> type1) { this.type = type1; } @Override @Transactional(readOnly = true, propagation = Propagation.SUPPORTS) public T find(ID id) { return (T) em.find(type, id); } @Override @Transactional(readOnly = false, propagation = Propagation.REQUIRED) public void persist(T o) { em.persist(o); } @Override @Transactional(readOnly = false, propagation = Propagation.REQUIRED) public T merge(T o) { o = em.merge(o); return o; } @Override @Transactional(readOnly = false, propagation = Propagation.REQUIRED) public void remove(T o) { // associate object with persistence context o = merge(o); em.remove(o); } }
There are a lot of new concepts in this class! Let's tackle them one at a time.
The Simple Logging Facade for Java or SLF4J is a simple abstraction for key logging frameworks including java.util.logging
, log4j
and logback
. SLF4J allows the end user to plug in the desired logging framework at deployment time by simply including the appropriate implementation library. More information about SLF4J can be found at http://slf4j.org/manual.html. Logging not only allows developers to debug code, but it can also provide a permanent record of actions and application state within your application. Examples of application state could be current memory usage, the number of authorized users currently logged on, or the number of pending messages awaiting processing. Log files are usually the first place to look at when analyzing production bugs, and they are an important component of any enterprise application.
Although the default Java logging is adequate for simple uses, it would not be appropriate for more sophisticated applications. The log4J
framework (http://logging.apache.org/log4j/1.2) and the logback
framework (http://logback.qos.ch) are examples of highly configurable logging frameworks. The logback
framework is usually considered the successor of log4j
as it offers some key advantages over log4j
including better performance, less memory consumption, and automatic reloading of configuration files. We will use logback
in our application.
The required SLF4J and logback
libraries will be added to the application by adding the following dependency to pom.xml
:
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency>
You will also need to add the additional logback.version
property to pom.xml
:
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>3.2.4.RELEASE</spring.version>
<logback.version>1.0.13</logback.version>
</properties>
You can now perform a Clean and Build Project to download the logback-classic
, logback-core
, and slf4j-api
JAR files. This will then enable us to add the imports defined in GenericDaoImpl
as well as the logger definition:
final protected Logger logger = LoggerFactory.getLogger(this.getClass());
All descendent classes will now be able to use the logger (it is declared as protected
) but will not be able to change it (it is declared as final
). We will start using the logger in Chapter 5, Testing the DAO Layer with Spring and JUnit, where we will examine the logback.xml
configuration file in detail.
This one line annotating the EntityManager
interface method is all that's required for Spring Framework to plug in or inject the EclipseLink
implementation during runtime. The EntityManager
interface defines methods for interacting with the persistence context such as persist
, merge
, remove
, and find
. A full listing of the EntityManager
interface methods can be found at http://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html.
Our persistence context is defined in persistence.xml
in which we have named it as tttPU
. This is what binds EntityManager
in GenericDaoImpl
to the persistence context through the @PersistenceContext
annotation unitName
property. A persistence context is a set of entity instances (in our application, these are the Company
, Project
, Task
, User
, and TaskLog
objects) in which, for any persistent entity, there is a unique entity instance. Within the persistence context, the entity instances and their lifecycle is managed.
The EntityManager
API is used to create and remove persistent entity instances, to find entities by their primary key, and to query over entities. In our GenericDaoImpl
class, the EntityManager
instance em
is used to perform the generic CRUD operations. Each descendent class will hence have access to these methods as well as the em
instance itself (it is declared as protected).
The @Transactional
annotation is the cornerstone of Spring's declarative transaction management. It allows you to specify transactional behavior at an individual method level and is very simple to use. This option has the least impact on application code, and it does not require any complex configuration. In fact, it is completely non-invasive as there is no Java coding required for commits and rollbacks.
Spring recommends that you only annotate classes (and methods of classes) with the @Transactional
annotation as opposed to annotating interfaces (a full explanation can be found at http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/transaction.html). For this reason, we will annotate all appropriate methods in the generic and implementing classes with one of the following:
@Transactional(readOnly = false, propagation = Propagation.REQUIRED) @Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
The @Transactional
annotation is metadata that specifies that a method must have transactional semantics. For example, we could define metadata that defines starting a brand new read-only transaction when this method is invoked, suspending any existing transaction. The default @Transactional
settings are as follows:
propagation
setting is Propagation.REQUIRED
readOnly
is falseIt is a good practice to define all properties including default settings, as we have done previously. Let's examine these properties in detail.
It is the default value for transactions that do not specify a propagation
setting. This property supports a current transaction if one exists or creates a new one if none exists. This ensures that the Propagation.REQUIRED
annotated method will always have a valid transaction available and should be used whenever the data is modified in the persistence storage. This property is usually combined with readOnly=false
.
This property supports a current transaction if one exists or executes non-transactionally if none exists. The Propagation.SUPPORTS
property should be used if the annotated method does not modify the data (will not execute an insert
, update
, or delete
statement against the database). This property is usually combined with readOnly=true
.
This just serves as a hint for the actual transaction subsystem to allow optimization of executed statements if possible. It may be possible that the transaction manager may not be able to interpret this property. For self-documenting code, however, it is a good practice to include this property.
Spring allows us to fine-tune transactional properties with additional options that are beyond the scope of this book. Browse the link that was mentioned earlier to find out more about how transactions can be managed in more complex scenarios including multiple transactional resources.
3.144.97.187