Defining the generic DAO implementation

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

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.

The@PersistenceContext(unitName = "tttPU") line

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

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 false

It is a good practice to define all properties including default settings, as we have done previously. Let's examine these properties in detail.

The Propagation.REQUIRED property

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.

The Propagation.SUPPORTS property

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.

The readOnly property

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.

Other transaction properties

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.97.187