📘 Premium Read: Access my best content on Medium member-only articles — deep dives into Java, Spring Boot, Microservices, backend architecture, interview preparation, career advice, and industry-standard best practices.
✅ Some premium posts are free to read — no account needed. Follow me on Medium to stay updated and support my writing.
🎓 Top 10 Udemy Courses (Huge Discount): Explore My Udemy Courses — Learn through real-time, project-based development.
▶️ Subscribe to My YouTube Channel (172K+ subscribers): Java Guides on YouTube
Problem
Forces
- 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
Structure
Class Diagram
Sequence Diagram
Participants and Responsibilities
Implementation
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;
}
}
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
}
}
}
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
}
}
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
//...
}
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
// ...
}
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
- Data Transfer Object Design Pattern in Java
- Service Locator Design Pattern in Java
- Business Delegate Design Pattern in Java
- Converter Design Pattern in Java
- Transfer Object Assembler Pattern in Java
- Value List Handler Pattern in Java
Comments
Post a Comment
Leave Comment