Value List Handler Pattern in Java

The Value List Handler provides the search and iteration functionality. To perform a search, the Value List Handler uses a Data Access Object to execute the query and retrieve the matching results from the database.
It is hard to understand this pattern so my suggestion is to go to source code section and have a look at code step by step gives you more clarity. This pattern is divided into a number of sections for simplicity like problem, forces, solution etc.

Problem

(Problem section describes the design issues faced by the developer)
You have a remote client that wants to iterate over a large results list.

Forces

(This section describes Lists the reasons and motivations that affect the problem and the solution. The list of forces highlights the reasons why one might choose to use the pattern and provides a justification for using the pattern)
  • You want to avoid the overhead of using EJB finder methods for large searches.
  • You want to implement a read-only use-case that does not require a transaction.
  • You want to provide the clients with an efficient search and iterate mechanism over a large results set.
  • You want to maintain the search results on the server side.

Solution

(Here solution section describes the solution approach briefly and the solution elements in detail)
Use a Value List Handler to search, cache the results, and allow the client to traverse and select items from the results. The Value List Handler provides the search and iteration functionality. To perform a search, the Value List Handler uses a Data Access Object to execute the query and retrieve the matching results from the database. This bypasses using the EJB finders for your applications where Business Objects are implemented as entity beans.

Structure

Let's use UML class diagram to represent the basic structure of the solution and the UML Sequence diagram in this section present the dynamic mechanisms of the solution. 
Below is the class diagram representing the relationships for the Value List Handler Pattern.

Class Diagram

Sequence Diagram

Participants and Responsibilities

Client - A Client is any client that needs to execute a query that returns a large set of results. The client can be a presentation-tier component that wants to display search results to a user. The client can also be a session bean that encapsulates the ValueListHandler.
ValueListIterator - A ValueListIterator provides an iteration mechanism with the following methods to iterate over the contents of the ValueList.
ValueListHandler - The ValueListHandler executes the search and obtains the query results, which it manages in a privately held collection represented by the ValueList object. The ValueListHandler creates and manipulates the ValueList collection typically using a Data Access Object. When the client requests the results, the ValueListHandler creates a sub-list from the original ValueList and sends it to the Client. Typically, a ValueListHandler manages a single ValueList. However, ValueListHandler can manage more than one ValueList instances in case it has to combine and handle multiple search results.
DataAccessObject - The ValueListHandler uses the DataAccessObject to access the data source, execute the query, and retrieve the results.
ValueList - The ValueList is a collection that holds the results of the query. Typically, you might use a List implementation from the Java Collections API or implement your own custom List based on your needs.
Value - The Value represents a result data object from the search.

Implementation

(This section includes source code implementations and code listings for the patterns).
Consider an example where a list of Project business objects is retrieved and displayed. You can use the Value List Handler in this case.
ProjectsListHandler class, which is responsible for providing the list of Projects. This class extends the ValueListHandler base abstract class, which provides the generic implementation for a Value List Handler.
Step 1: Create ProjectTO class
public class ProjectTO {
    private String projectId;
    private String projectName;
    private String managerId;
    private Date startDate;
    private Date endDate;
    private boolean started;
    private boolean completed;
    private boolean accepted;
    private Date acceptedDate;
    private String customerId;
    private String projectDescription;
    private String projectStatus;

    public String getProjectId() {
        return projectId;
    }

    public void setProjectId(String projectId) {
        this.projectId = projectId;
    }

    public String getProjectName() {
        return projectName;
    }

    public void setProjectName(String projectName) {
        this.projectName = projectName;
    }

    public String getManagerId() {
        return managerId;
    }

    public void setManagerId(String managerId) {
        this.managerId = managerId;
    }

    public Date getStartDate() {
        return startDate;
    }

    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }

    public Date getEndDate() {
        return endDate;
    }

    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

    public boolean isStarted() {
        return started;
    }

    public void setStarted(boolean started) {
        this.started = started;
    }

    public boolean isCompleted() {
        return completed;
    }

    public void setCompleted(boolean completed) {
        this.completed = completed;
    }

    public boolean isAccepted() {
        return accepted;
    }

    public void setAccepted(boolean accepted) {
        this.accepted = accepted;
    }

    public Date getAcceptedDate() {
        return acceptedDate;
    }

    public void setAcceptedDate(Date acceptedDate) {
        this.acceptedDate = acceptedDate;
    }

    public String getCustomerId() {
        return customerId;
    }

    public void setCustomerId(String customerId) {
        this.customerId = customerId;
    }

    public String getProjectDescription() {
        return projectDescription;
    }

    public void setProjectDescription(String projectDescription) {
        this.projectDescription = projectDescription;
    }

    public String getProjectStatus() {
        return projectStatus;
    }

    public void setProjectStatus(String projectStatus) {
        this.projectStatus = projectStatus;
    }
}
Step 2: Implementing Value List Handler: ProjectListHandler.
public class ProjectListHandler extends ValueListHandler {

    private ProjectDAO dao = new ProjectDAO();
    // use ProjectTO as a template to determine
    // search criteria
    private ProjectTO projectCriteria = null;

    // Client creates a ProjectTO instance, sets the 
    // values to use for search criteria and passes 
    // the ProjectTO instance as projectCriteria
    // to the constructor and to setCriteria() method
    public ProjectListHandler(ProjectTO projectCriteria)
    throws Exception {
        try {
            this.projectCriteria = projectCriteria;
            executeSearch();
        } catch (Exception e) {
            // Handle exception, throw ListHandlerException
        }
    }

    public void setCriteria(ProjectTO projectCriteria) {
        this.projectCriteria = projectCriteria;
    }

    // executes search. Client can invoke this
    // provided that the search criteria has been
    // properly set. Used to perform search to refresh
    // the list with the latest data.
    public void executeSearch()
    throws Exception {
        try {
            if (projectCriteria == null) {
                throw new Exception(
                    "Project Criteria required...");
            }
            List resultsList =
                dao.executeSelect(projectCriteria);
            setList(resultsList);
        } catch (Exception e) {
            // Handle exception, throw ListHandlerException
        }
    }
}
Step 3: Implementing Generic ValueListHandler Class.
The ValueListHandler is a generic iterator class that provides the iteration functionality.
public class ValueListHandler
implements ValueListIterator {

    protected List list;
    protected ListIterator listIterator;

    public ValueListHandler() {}

    protected void setList(List list)
    throws IteratorException {
        this.list = list;
        if (list != null)
            listIterator = list.listIterator();
        else
            throw new IteratorException("List empty");
    }

    public Collection getList() {
        return list;
    }

    public int getSize() throws IteratorException {
        int size = 0;

        if (list != null)
            size = list.size();
        else
            throw new IteratorException("No data found"); //No Data

        return size;
    }

    public Object getCurrentElement()
    throws IteratorException {

        Object obj = null;
        // Will not advance iterator
        if (list != null) {
            int currIndex = listIterator.nextIndex();
            obj = list.get(currIndex);
        } else
            throw new IteratorException("");
        return obj;

    }

    public List getPreviousElements(int count)
    throws IteratorException {
        int i = 0;
        Object object = null;
        LinkedList list = new LinkedList();
        if (listIterator != null) {
            while (listIterator.hasPrevious() && (i < count)) {
                object = listIterator.previous();
                list.add(object);
                i++;
            }
        } // end if
        else
            throw new IteratorException("No data found"); // No data

        return list;
    }

    public List getNextElements(int count)
    throws IteratorException {
        int i = 0;
        Object object = null;
        LinkedList list = new LinkedList();
        if (listIterator != null) {
            while (listIterator.hasNext() && (i < count)) {
                object = listIterator.next();
                list.add(object);
                i++;
            }
        } else
            throw new IteratorException("No data found"); // No data

        return list;
    }

    public void resetIndex() throws IteratorException {
        if (listIterator != null) {
            listIterator = list.listIterator();
        } else
            throw new IteratorException("No data found"); // No data
    }

}
Step 4 : Create ProjectDAO Class.
public class ProjectDAO {
    final private String tableName = "PROJECT";

    // select statement uses fields
    final private String fields = "project_id, name," +
        "project_manager_id, start_date, end_date, " +
        " started, completed, accepted, acceptedDate," +
        " customer_id, description, status";

    // the methods relevant to the ValueListHandler
    // are shown here.
    // See Data Access Object pattern for other details.
    // ...
    public List < ProjectTO > executeSelect(ProjectTO projCriteria)
    throws SQLException {

        PreparedStatement stmt = null;
        List < ProjectTO > list = null;
        Connection con = getConnection();
        StringBuffer selectStatement = new StringBuffer();
        selectStatement.append("SELECT " + fields +
            " FROM " + tableName + "where 1=1");

        // append additional conditions to where clause
        // depending on the values specified in 
        // projCriteria
        if (projCriteria.getProjectId() != null) {
            selectStatement.append(" AND PROJECT_ID = '" +
                projCriteria.getProjectId() + "'");
        }
        // check and add other fields to where clause
        //...

        try {
            stmt = con.prepareStatement(selectStatement.toString());
            stmt.setString(1, projCriteria.getProjectId());
            ResultSet rs = stmt.executeQuery();
            list = prepareResult(rs);
            stmt.close();
        } finally {
            con.close();
        }
        return list;
    }

    private Connection getConnection() {
        // TODO Auto-generated method stub
        return null;
    }

    private List < ProjectTO > prepareResult(ResultSet rs)
    throws SQLException {
        List < ProjectTO > list = new ArrayList();
        while (rs.next()) {
            int i = 1;
            ProjectTO proj = new ProjectTO();
            proj.setProjectName(rs.getString(i++));
            proj.setManagerId(rs.getString(i++));
            proj.setStartDate(rs.getDate(i++));
            proj.setEndDate(rs.getDate(i++));
            proj.setStarted(rs.getBoolean(i++));
            proj.setCompleted(rs.getBoolean(i++));
            proj.setAccepted(rs.getBoolean(i++));
            proj.setAcceptedDate(rs.getDate(i++));
            proj.setCustomerId(rs.getString(i++));
            proj.setProjectDescription(rs.getString(i++));
            proj.setProjectStatus(rs.getString(i++));
            list.add(proj);

        }
        return list;
    }

    // implement other stuff
    //...
}
Step 5 : ValueListIterator interface.
import java.util.List;
//http://www.oracle.com/technetwork/java/valuelisthandler-142464.html
public interface ValueListIterator {
    public int getSize() throws IteratorException;

    public Object getCurrentElement() throws IteratorException;

    public List getPreviousElements(int count) throws IteratorException;

    public List getNextElements(int count) throws IteratorException;

    public void resetIndex() throws IteratorException;

    // other common methods as required
    // ...
}
Step 6: Create custom exception class.
public class IteratorException extends Exception {

    public IteratorException(String message) {
        super(message);
    }

}

Consequences

  • Provides efficient alternative to EJB finders
  • Caches search results
  • Provides flexible search capabilities
  • Improves network performance
  • Allows deferring entity bean transactions
  • Promotes layering and separation of concerns
  • Creating a large list of Transfer Objects can be expensive

References

Related Patterns


Comments