/*
*
* Copyright 2005 AgileTec s.r.l. (http://www.agiletec.it) All rights reserved.
*
* This file is part of jAPS software.
* jAPS is a free software;
* you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) as published by the Free Software Foundation; version 2.
*
* See the file License for the specific language governing permissions
* and limitations under the License
*
*
*
* Copyright 2005 AgileTec s.r.l. (http://www.agiletec.it) All rights reserved.
*
*/
package com.agiletec.aps.system.common;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Utility Class for searching operation on db.
* This class presents utility method for searching on db table throw
* Field search filter.
* @author E.Santoboni
*/
public abstract class AbstractSearcherDAO extends AbstractDAO {
protected List<String> searchId(FieldSearchFilter[] filters) {
Connection conn = null;
List<String> idList = new ArrayList<String>();
PreparedStatement stat = null;
ResultSet result = null;
try {
conn = this.getConnection();
stat = this.buildStatement(filters, false, conn);
result = stat.executeQuery();
this.flowResult(idList, filters, result);
} catch (Throwable t) {
processDaoException(t, "Error while loading the list of IDs", "searchId");
} finally {
closeDaoResources(result, stat, conn);
}
return idList;
}
protected FieldSearchFilter[] addFilter(FieldSearchFilter[] filters, FieldSearchFilter filterToAdd){
int len = 0;
if (filters != null) {
len = filters.length;
}
FieldSearchFilter[] newFilters = new FieldSearchFilter[len + 1];
for(int i=0; i < len; i++){
newFilters[i] = filters[i];
}
newFilters[len] = filterToAdd;
return newFilters;
}
protected void flowResult(List<String> contentsId, FieldSearchFilter[] filters, ResultSet result) throws SQLException {
while (result.next()) {
String id = result.getString(this.getMasterTableIdFieldName());
if (contentsId.contains(id)) continue;
if (!this.isForceTextCaseSearch() || null == filters || filters.length == 0) {
contentsId.add(id);
} else {
boolean verify = this.verifyLikeFieldFilters(result, filters);
if (verify) contentsId.add(id);
}
}
}
protected boolean verifyLikeFieldFilters(ResultSet result,
FieldSearchFilter[] likeFieldFilters) throws SQLException {
boolean verify = true;
for (int i=0; i<likeFieldFilters.length; i++) {
FieldSearchFilter filter = likeFieldFilters[i];
if (filter.getKey() == null || !filter.isLikeOption() || !this.isForceTextCaseSearch()) {
continue;
}
String fieldName = this.getTableFieldName(filter.getKey());
String value = result.getString(fieldName);
if (null != filter.getValue()) {
verify = this.checkText((String)filter.getValue(), value);
if (!verify) break;
} else if (filter.getAllowedValues() != null && filter.getAllowedValues().size() > 0) {
List<Object> allowedValues = filter.getAllowedValues();
verify = this.verifyLikeAllowedValuesFilter(value, allowedValues);
if (!verify) break;
}
}
return verify;
}
protected boolean verifyLikeAllowedValuesFilter(String extractedValue, List<Object> allowedValues) {
boolean verify = false;
for (int j = 0; j < allowedValues.size(); j++) {
String allowedValue = (String) allowedValues.get(j);
verify = this.checkText(allowedValue, extractedValue);
if (verify) break;
}
return verify;
}
/**
* This utility method checks if the given Text matches or is contained inside
* another one.
* @param insertedText The text to look for
* @param text The text to search in
* @return True if an occurrence of 'insertedText' is found in 'text'.
*/
protected boolean checkText(String insertedText, String text) {
if (this.isForceCaseInsensitiveLikeSearch()
&& (null == insertedText || insertedText.trim().length() == 0
|| (null != text && text.toLowerCase().indexOf(insertedText.trim().toLowerCase()) != -1))) {
return true;
}
if (this.isForceCaseSensitiveLikeSearch()
&& (null == insertedText || insertedText.trim().length() == 0
|| (null != text && text.indexOf(insertedText.trim()) != -1))) {
return true;
}
return false;
}
private PreparedStatement buildStatement(FieldSearchFilter[] filters, boolean selectAll, Connection conn) {
String query = this.createQueryString(filters, selectAll);
PreparedStatement stat = null;
try {
stat = conn.prepareStatement(query);
int index = 0;
index = this.addMetadataFieldFilterStatementBlock(filters, index, stat);
} catch (Throwable t) {
processDaoException(t, "Error while creating the statement", "buildStatement");
}
return stat;
}
/**
* Add to the statement the filters on the entity metadata.
* @param filters the filters to add to the statement.
* @param index The current index of the statement.
* @param stat The statement.
* @return The current statement index, eventually incremented by filters.
* @throws Throwable In case of error.
*/
protected int addMetadataFieldFilterStatementBlock(FieldSearchFilter[] filters, int index, PreparedStatement stat) throws Throwable {
if (filters == null) return index;
for (int i=0; i<filters.length; i++) {
FieldSearchFilter filter = filters[i];
if (filter.getKey() != null) {
index = this.addObjectSearchStatementBlock(filter, index, stat);
}
}
return index;
}
/**
* Add to the statement a filter on a attribute.
* @param filter The filter on the attribute to apply in the statement.
* @param index The last index used to associate the elements to the statement.
* @param stat The statement where the filters are applied.
* @return The last used index.
* @throws SQLException In case of error.
*/
protected int addObjectSearchStatementBlock(FieldSearchFilter filter, int index, PreparedStatement stat) throws SQLException {
if (filter.isLikeOption() && this.isForceTextCaseSearch()) {
return index;
}
if (filter.isNullOption()) {
return index;
}
if (filter.getAllowedValues() != null && filter.getAllowedValues().size() > 0) {
List<Object> allowedValues = filter.getAllowedValues();
for (int i = 0; i < allowedValues.size(); i++) {
Object allowedValue = allowedValues.get(i);
this.addObjectSearchStatementBlock(stat, ++index, allowedValue, filter.isLikeOption());
}
} else if (filter.getValue() != null) {
this.addObjectSearchStatementBlock(stat, ++index, filter.getValue(), filter.isLikeOption());
} else {
if (null != filter.getStart()) {
this.addObjectSearchStatementBlock(stat, ++index, filter.getStart(), false);
}
if (null != filter.getEnd()) {
this.addObjectSearchStatementBlock(stat, ++index, filter.getEnd(), false);
}
}
return index;
}
protected void addObjectSearchStatementBlock(PreparedStatement stat, int index,
Object object, boolean isLikeOption) throws SQLException {
if (object instanceof String) {
if (isLikeOption) {
stat.setString(index, "%"+((String) object)+"%");
} else {
stat.setString(index, (String) object);
}
} else if (object instanceof Date) {
stat.setDate(index, new java.sql.Date(((Date) object).getTime()));
} else if (object instanceof BigDecimal) {
stat.setBigDecimal(index, (BigDecimal) object);
} else if (object instanceof Boolean) {
stat.setString(index, ((Boolean) object).toString());
} else {
stat.setObject(index, object);
}
}
private String createQueryString(FieldSearchFilter[] filters, boolean selectAll) {
StringBuffer query = this.createBaseQueryBlock(filters, selectAll);
boolean hasAppendWhereClause = this.appendMetadataFieldFilterQueryBlocks(filters, query, false);
boolean ordered = appendOrderQueryBlocks(filters, query, false);
return query.toString();
}
/**
* Create the 'base block' of the query with the eventual references to the support table.
* @param filters The filters defined.
* @param selectAll When true, this will insert all the fields in the master table in the select
* of the master query.
* When true we select all the available fields; when false only the field addressed by the filter
* is selected.
* @return The base block of the query.
*/
protected StringBuffer createBaseQueryBlock(FieldSearchFilter[] filters, boolean selectAll) {
StringBuffer query = this.createMasterSelectQueryBlock(filters, selectAll);
return query;
}
private StringBuffer createMasterSelectQueryBlock(FieldSearchFilter[] filters, boolean selectAll) {
String masterTableName = this.getMasterTableName();
StringBuffer query = new StringBuffer("SELECT ").append(masterTableName).append(".");
if (selectAll) {
query.append("* ");
} else {
query.append(this.getMasterTableIdFieldName());
if (this.isForceTextCaseSearch() && filters != null) {
for (int i=0; i<filters.length; i++) {
FieldSearchFilter filter = filters[i];
if (filter.isLikeOption()) {
query.append(", ").append(masterTableName).append(".").append(this.getTableFieldName(filters[i].getKey()));
}
}
}
}
query.append(" FROM ").append(masterTableName).append(" ");
return query;
}
protected boolean appendMetadataFieldFilterQueryBlocks(FieldSearchFilter[] filters, StringBuffer query, boolean hasAppendWhereClause) {
if (filters == null) return hasAppendWhereClause;
for (int i=0; i<filters.length; i++) {
FieldSearchFilter filter = filters[i];
if (filter.getKey() != null) {
hasAppendWhereClause = this.addMetadataFieldFilterQueryBlock(filter, query, hasAppendWhereClause);
}
}
return hasAppendWhereClause;
}
protected boolean addMetadataFieldFilterQueryBlock(FieldSearchFilter filter, StringBuffer query, boolean hasAppendWhereClause) {
if (filter.isLikeOption() && this.isForceTextCaseSearch()) {
return hasAppendWhereClause;
}
hasAppendWhereClause = this.verifyWhereClauseAppend(query, hasAppendWhereClause);
String tableFieldName = this.getTableFieldName(filter.getKey());
if (filter.getAllowedValues() != null && filter.getAllowedValues().size() > 0) {
List<Object> allowedValues = filter.getAllowedValues();
for (int j = 0; j < allowedValues.size(); j++) {
if (j == 0) {
query.append(" ( ");
} else {
query.append(" OR ");
}
query.append(this.getMasterTableName()).append(".").append(tableFieldName).append(" ");
if (filter.isLikeOption()) {
query.append(this.getLikeClause());
} else {
query.append("= ? ");
}
if (j == (allowedValues.size()-1)) query.append(" ) ");
}
} else {
query.append(this.getMasterTableName()).append(".").append(tableFieldName).append(" ");
if (filter.getValue() != null) {
if (filter.isLikeOption()) {
query.append(this.getLikeClause());
} else {
query.append("= ? ");
}
} else {
if (null != filter.getStart()) {
query.append(">= ? ");
if (null != filter.getEnd()) {
query.append("AND ").append(this.getMasterTableName()).append(".").append(tableFieldName).append(" ");
query.append("<= ? ");
}
} else if (null != filter.getEnd()) {
query.append("<= ? ");
} else {
if (filter.isNullOption()) {
query.append(" IS NULL ");
} else {
query.append(" IS NOT NULL ");
}
}
}
}
return hasAppendWhereClause;
}
protected boolean appendOrderQueryBlocks(FieldSearchFilter[] filters, StringBuffer query, boolean ordered) {
if (filters == null) return ordered;
for (int i=0; i<filters.length; i++) {
FieldSearchFilter filter = filters[i];
if (null != filter.getKey() && null != filter.getOrder() && !filter.isNullOption()) {
if (!ordered) {
query.append("ORDER BY ");
ordered = true;
} else {
query.append(", ");
}
String fieldName = this.getTableFieldName(filter.getKey());
query.append(this.getMasterTableName()).append(".").append(fieldName).append(" ").append(filter.getOrder());
}
}
return ordered;
}
protected boolean verifyWhereClauseAppend(StringBuffer query, boolean hasAppendWhereClause) {
if (hasAppendWhereClause) {
query.append("AND ");
} else {
query.append("WHERE ");
hasAppendWhereClause = true;
}
return hasAppendWhereClause;
}
protected abstract String getTableFieldName(String metadataFieldKey);
/**
* Return the name of the entities master table.
* @return The name of the master table.
*/
protected abstract String getMasterTableName();
/**
* Return the name of the ID field in the master table.
* @return The name of the ID field.
*/
protected abstract String getMasterTableIdFieldName();
protected String getLikeClause() {
if (null == this._likeClause || this._likeClause.trim().length() == 0) {
return DEFAULT_LIKE_CLAUSE;
}
return _likeClause;
}
public void setLikeClause(String likeClause) {
this._likeClause = likeClause;
}
protected boolean isForceTextCaseSearch() {
return (this.isForceCaseInsensitiveLikeSearch() || this.isForceCaseSensitiveLikeSearch());
}
protected boolean isForceCaseSensitiveLikeSearch() {
return _forceCaseSensitiveLikeSearch;
}
public void setForceCaseSensitiveLikeSearch(boolean forceCaseSensitiveLikeSearch) {
this._forceCaseSensitiveLikeSearch = forceCaseSensitiveLikeSearch;
}
protected boolean isForceCaseInsensitiveLikeSearch() {
return _forceCaseInsensitiveLikeSearch;
}
public void setForceCaseInsensitiveLikeSearch(boolean forceCaseInsensitiveLikeSearch) {
this._forceCaseInsensitiveLikeSearch = forceCaseInsensitiveLikeSearch;
}
private String _likeClause;
private static final String DEFAULT_LIKE_CLAUSE = "LIKE ? ";
private boolean _forceCaseSensitiveLikeSearch = false;
private boolean _forceCaseInsensitiveLikeSearch = false;
}