Enterprise ApplicationDevelopment with Ext JSand Spring
上QQ阅读APP看书,第一时间看更新

Defining the DAO interfaces

An interface in the Java programming language defines a set of method signatures and constant declarations. Interfaces expose behaviors (or what can be done) and define a contract that implementing classes promise to provide (how it is done). Our DAO layer will contain one interface and one implementing class per domain object.

Note

The use of interfaces is an often misunderstood pattern in enterprise programming. The argument goes along the line, "Why add another set of Java objects to your codebase when they are not required". Interfaces do add to the number of lines of code that you write, but their beauty will be appreciated as soon as you are asked to refactor an aging project that was written with interfaces from the start. I have migrated an SQL-based persistence layer to a JPA persistence layer. The new DAO implementation replaced the old without any significant change in the service layer, thanks to the use of interfaces. Development was done in parallel to supporting the existing (old) implementation until we were ready to swap in the new implementation. This was a relatively painless process that would not have been as easily achieved without the use of interfaces.

Let's start with the company interface.

Adding the CompanyDao interface

  1. Navigate to File | New File from the menu and select Java Interface as shown in the following screenshot:
    Adding the CompanyDao interface
  2. Click on the Next button and fill in the details as shown in the following screenshot:
    Adding the CompanyDao interface

The name of the interface is CompanyDao. We could have named this interface using the uppercase acronym CompanyDAO. In keeping with the newer Java EE naming styles, we have decided to use the camel case form of the acronym. Recent examples of this style include the Html*, Json*, and Xml* classes and interfaces, an example of which is javax.json.JsonObject. We also believe that this form is easier to read. However, this does not prohibit you from using the uppercase acronym; there are many of these examples in Java EE as well (EJB*, JAXB*, and JMS* interfaces and classes to name a few). Whatever you choose, be consistent. Do not mix forms and create CompanyDAO and ProjectDao interfaces!

Note that the package com.gieman.tttracker.dao does not exist yet and will be created for you. Click on Finish to create your first interface, after which NetBeans will open the file in the editor.

Adding the CompanyDao interface

The Company interface will define the persistence methods that we will use in our application. The core methods must include the ability to perform each CRUD operation in addition to any other operations appropriate to our business needs. We will add the following methods to this interface:

  • persist: This method inserts a new company record
  • merge: This method updates an existing company record
  • remove: This method deletes a company record
  • find: This method selects a company record using a primary key
  • findAll: This method returns all the company records

Note that the JPA terminologies persist, merge, remove, and find are equivalent to the SQL operations insert, update, delete, and select. Add the methods to CompanyDao as shown in the following code:

package com.gieman.tttracker.dao;

import com.gieman.tttracker.domain.Company;
import java.util.List;
public interface CompanyDao {

    public Company find(Integer idCompany);

    public List<Company> findAll();

    public void persist(Company company);

    public Company merge(Company company);

    public void remove(Company company);
}

We have defined a contract that the implementing class must promise to deliver. We will now add the ProjectDao interface.

Adding the ProjectDao interface

The ProjectDao interface will define a similar set of methods to the CompanyDao interface:

package com.gieman.tttracker.dao;

import com.gieman.tttracker.domain.Company;
import com.gieman.tttracker.domain.Project;
import java.util.List;

public interface ProjectDao {

    public Project find(Integer idProject);

    public List<Project> findAll();

    public void persist(Project project);

    public Project merge(Project project);

    public void remove(Project project);
}

You will note that all method signatures in the ProjectDao interface are identical to the CompanyDao interface. The only difference is in class types where Company is replaced by project. The same situation will occur in all the other interfaces that we are going to add (TaskDao, UserDao, and TaskLogDao). Each of the interfaces will require a definition for the find method that will look like the following code:

public Company find(Integer idCompany); // in CompanyDao
public Project find(Integer idProject); // in ProjectDao
public Task find(Integer idTask); // in TaskDao
public User find(Integer idUser); // in UserDao
public TaskLog find(Integer idTaskLog); // in TaskLogDao

As you can see, the only functional difference in each of these methods is the returned type. The same can be said for the persist, merge, and remove methods. This situation lends itself perfectly to the use of Java generics.

Defining a generic DAO interface

This interface will be extended by each of our DAO interfaces. The GenericDao interface uses generics to define each method in a way that can be used by each descendent interface. These methods will then be available free of cost to the extending interfaces. Rather than defining a find(Integer id) method in each of the CompanyDao, ProjectDao, TaskDao, UserDao, and TaskLogDao interfaces, the GenericDao interface defines the generic method that is then available for all descendants.

Note

This is a powerful technique for enterprise application programming and should always be considered when designing or architecting an application framework. A well-structured design using Java generics will simplify change requests and maintenance for many years to come.

The generic interface definition looks like this:

package com.gieman.tttracker.dao;

public interface GenericDao<T, ID> {

    public T find(ID id);

    public void persist(T obj);

    public T merge(T obj);

    public void remove(T obj);
}

We can now refactor the CompanyDao interface as follows:

package com.gieman.tttracker.dao;

import com.gieman.tttracker.domain.Company;
import java.util.List;

public interface CompanyDao extends GenericDao<Company, Integer>{

    public List<Company> findAll();
    
}

Note the way in which we have extended the GenericDao interface using the <Company, Integer> types. The type parameters <T, ID> in the GenericDao interface become placeholders for the types specified in the CompanyDao definition. A T or ID that is found in the GenericDao interface will be replaced with Company and Integer in the CompanyDao interface. This automatically adds the find, persist, merge, and remove methods to CompanyDao.

Generics allow the compiler to check type correctness at compile-time. This improves code robustness. A good explanation of Java generics can be found at http://docs.oracle.com/javase/tutorial/extra/generics/index.html.

In a similar way, we can now refactor the ProjectDao interface:

package com.gieman.tttracker.dao;

import com.gieman.tttracker.domain.Company;
import com.gieman.tttracker.domain.Project;
import java.util.List;

public interface ProjectDao extends GenericDao<Project, Integer>{

    public List<Project> findAll();

}

Let's continue with the missing interfaces in the same manner.

The TaskDao interface

Apart from the common generic methods, we will once again need a findAll method. This interface looks like the following code:

package com.gieman.tttracker.dao;

import com.gieman.tttracker.domain.Project;
import com.gieman.tttracker.domain.Task;
import java.util.List;

public interface TaskDao extends GenericDao<Task, Integer>{
   
    public List<Task> findAll();    
}

The UserDao interface

We will need a list of all the users in the system as well as a few finder methods to identify a user by different parameters. These methods will be required when we develop our frontend user interfaces and service layer functionality. The UserDao interface looks like the following code:

package com.gieman.tttracker.dao;

import com.gieman.tttracker.domain.User;
import java.util.List;

public interface UserDao extends GenericDao<User, String> {

    public List<User> findAll();

    public User findByUsernamePassword(String username, String password);

    public User findByUsername(String username);

    public User findByEmail(String email);
}

Note that the UserDao interface extends GenericDao with a String ID type. This is because the User domain entity has a String primary key type.

The TaskLogDao interface

The TaskLogDao interface will also need a few additional methods to be defined in order to allow different views into the task log data. These methods will once again be required when we develop our frontend user interfaces and service layer functionality.

package com.gieman.tttracker.dao;

import com.gieman.tttracker.domain.Task;
import com.gieman.tttracker.domain.TaskLog;
import com.gieman.tttracker.domain.User;
import java.util.Date;
import java.util.List;

public interface TaskLogDao extends GenericDao<TaskLog, Integer>{

    public List<TaskLog> findByUser(User user, Date startDate, Date endDate);
    
    public long findTaskLogCountByTask(Task task);
    
    public long findTaskLogCountByUser(User user);
}

Note that our finder methods for the TaskLogDao interface have descriptive names that identify the purpose of the method. Each finder method will be used to retrieve a subset of task log entries that are appropriate for the business needs of the application.

This covers all the required interfaces for our application. It is now time to define the implementations for each of our interfaces.