/*
*
* 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.entity;
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;
import com.agiletec.aps.system.common.AbstractSearcherDAO;
import com.agiletec.aps.system.common.entity.model.ApsEntityRecord;
import com.agiletec.aps.system.common.entity.model.EntitySearchFilter;
/**
* Abstract class extended by those DAO that perform searches on entities.
* @author E.Santoboni
*/
public abstract class AbstractEntitySearcherDAO extends AbstractSearcherDAO implements IEntitySearcherDAO {
@Override
public List<ApsEntityRecord> searchRecords(EntitySearchFilter[] filters) {
Connection conn = null;
List<ApsEntityRecord> records = new ArrayList<ApsEntityRecord>();
PreparedStatement stat = null;
ResultSet result = null;
try {
conn = this.getConnection();
stat = this.buildStatement(filters, true, conn);
result = stat.executeQuery();
this.flowRecordsResult(records, filters, result);
} catch (Throwable t) {
processDaoException(t, "Error while loading records list", "searchRecord");
} finally {
closeDaoResources(result, stat, conn);
}
return records;
}
protected void flowRecordsResult(List<ApsEntityRecord> records, EntitySearchFilter[] filters, ResultSet result) throws Throwable {
while (result.next()) {
ApsEntityRecord record = this.createRecord(result);
if (!records.contains(record)) {//TODO DA ANALIZZARE
if (!this.isForceTextCaseSearch() || null == filters || filters.length == 0) {
records.add(record);
} else {
boolean verify = this.verifyLikeFieldFilters(result, filters);
if (verify) records.add(record);
}
}
}
}
protected abstract ApsEntityRecord createRecord(ResultSet result) throws Throwable;
@Override
public List<String> searchId(String typeCode, EntitySearchFilter[] filters) {
if (typeCode != null && typeCode.trim().length()>0) {
EntitySearchFilter filter = new EntitySearchFilter(IEntityManager.ENTITY_TYPE_CODE_FILTER_KEY, false, typeCode, false);
EntitySearchFilter[] newFilters = this.addFilter(filters, filter);
return this.searchId(newFilters);
}
return this.searchId(filters);
}
@Override
public List<String> searchId(EntitySearchFilter[] 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 EntitySearchFilter[] addFilter(EntitySearchFilter[] filters, EntitySearchFilter filterToAdd){
int len = 0;
if (filters != null) {
len = filters.length;
}
EntitySearchFilter[] newFilters = new EntitySearchFilter[len + 1];
for(int i=0; i < len; i++){
newFilters[i] = filters[i];
}
newFilters[len] = filterToAdd;
return newFilters;
}
protected void flowResult(List<String> contentsId, EntitySearchFilter[] filters, ResultSet result) throws SQLException {
while (result.next()) {
String id = result.getString(this.getEntityMasterTableIdFieldName());
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,
EntitySearchFilter[] likeFieldFilters) throws SQLException {
boolean verify = true;
for (int i=0; i<likeFieldFilters.length; i++) {
EntitySearchFilter filter = likeFieldFilters[i];
if (filter.getKey() == null || !filter.isLikeOption() || !this.isForceTextCaseSearch()) {
continue;
}
String fieldName = null;
if (filter.isAttributeFilter()) {
fieldName = this.getAttributeFieldColunm(filter)+i;
} else {
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;
}
private PreparedStatement buildStatement(EntitySearchFilter[] filters, boolean selectAll, Connection conn) {
String query = this.createQueryString(filters, selectAll);
PreparedStatement stat = null;
try {
stat = conn.prepareStatement(query);
int index = 0;
index = this.addAttributeFilterStatementBlock(filters, index, stat);
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(EntitySearchFilter[] filters, int index, PreparedStatement stat) throws Throwable {
if (filters == null) return index;
for (int i=0; i<filters.length; i++) {
EntitySearchFilter filter = filters[i];
if (filter.getKey() != null && !filter.isAttributeFilter()) {
index = this.addObjectSearchStatementBlock(filter, index, stat);
}
}
return index;
}
/**
* Add the attribute filters to the statement.
* @param filters The filters on the entity filters to insert 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 addAttributeFilterStatementBlock(EntitySearchFilter[] filters,
int index, PreparedStatement stat) throws SQLException {
if (filters == null) return index;
for (int i=0; i<filters.length; i++) {
EntitySearchFilter filter = filters[i];
if (filter.getKey() != null && filter.isAttributeFilter()) {
stat.setString(++index, filter.getKey());
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(EntitySearchFilter filter, int index, PreparedStatement stat) throws SQLException {
if (filter.isAttributeFilter() && null != filter.getLangCode()) {
stat.setString(++index, filter.getLangCode());
}
return super.addObjectSearchStatementBlock(filter, index, stat);
}
private String createQueryString(EntitySearchFilter[] filters, boolean selectAll) {
StringBuffer query = this.createBaseQueryBlock(filters, selectAll);
boolean hasAppendWhereClause = this.appendFullAttributeFilterQueryBlocks(filters, query, false);
this.appendMetadataFieldFilterQueryBlocks(filters, query, hasAppendWhereClause);
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(EntitySearchFilter[] filters, boolean selectAll) {
StringBuffer query = this.createMasterSelectQueryBlock(filters, selectAll);
this.appendJoinSerchTableQueryBlock(filters, query);
return query;
}
private StringBuffer createMasterSelectQueryBlock(EntitySearchFilter[] filters, boolean selectAll) {
String masterTableName = this.getEntityMasterTableName();
StringBuffer query = new StringBuffer("SELECT ").append(masterTableName).append(".");
if (selectAll) {
query.append("* ");
} else {
query.append(this.getEntityMasterTableIdFieldName());
if (this.isForceTextCaseSearch() && filters != null) {
String searchTableName = this.getEntitySearchTableName();
for (int i=0; i<filters.length; i++) {
EntitySearchFilter filter = filters[i];
if (!filter.isAttributeFilter() && filter.isLikeOption()) {
query.append(", ").append(masterTableName).append(".").append(this.getTableFieldName(filters[i].getKey()));
} else if (filter.isAttributeFilter() && filter.isLikeOption()) {
String columnName = this.getAttributeFieldColunm(filter);
query.append(", ").append(searchTableName).append(i).append(".").append(columnName);
query.append(" AS ").append(columnName).append(i).append(" ");
}
}
}
}
query.append(" FROM ").append(masterTableName).append(" ");
return query;
}
private void appendJoinSerchTableQueryBlock(EntitySearchFilter[] filters, StringBuffer query) {
if (filters == null) return;
String masterTableName = this.getEntityMasterTableName();
String masterTableIdFieldName = this.getEntityMasterTableIdFieldName();
String searchTableName = this.getEntitySearchTableName();
String searchTableIdFieldName = this.getEntitySearchTableIdFieldName();
for (int i=0; i<filters.length; i++) {
if (null != filters[i].getKey() && filters[i].isAttributeFilter() && !filters[i].isNullOption()) {
query.append("INNER JOIN ");
query.append(searchTableName).append(" ").append(searchTableName).append(i).append(" ON ")
.append(masterTableName).append(".").append(masterTableIdFieldName).append(" = ")
.append(searchTableName).append(i).append(".").append(searchTableIdFieldName).append(" ");
}
}
}
protected boolean appendFullAttributeFilterQueryBlocks(EntitySearchFilter[] filters, StringBuffer query, boolean hasAppendWhereClause) {
if (filters != null) {
for (int i=0; i<filters.length; i++) {
EntitySearchFilter filter = filters[i];
if (filter.getKey() == null || !filter.isAttributeFilter()) {
continue;
}
if (filter.isNullOption()) {
hasAppendWhereClause = this.appendNullAttributeFilterQueryBlocks(filter, query, hasAppendWhereClause);
} else {
hasAppendWhereClause = this.appendValuedAttributeFilterQueryBlocks(filter, i, query, hasAppendWhereClause);
}
}
}
return hasAppendWhereClause;
}
private boolean appendNullAttributeFilterQueryBlocks(EntitySearchFilter filter, StringBuffer query, boolean hasAppendWhereClause) {
hasAppendWhereClause = this.verifyWhereClauseAppend(query, hasAppendWhereClause);
query.append(this.getEntityMasterTableName()).append(".").append(this.getEntityMasterTableIdFieldName());
query.append(" NOT IN (");
String searchTableName = this.getEntitySearchTableName();
query.append("SELECT ").append(searchTableName).append(".").append(this.getEntitySearchTableIdFieldName());
query.append(" FROM ").append(searchTableName).append(" WHERE ").append(searchTableName).append(".attrname = ? ");
this.addAttributeLangQueryBlock(searchTableName, query, filter, true);
query.append(" AND (").append(searchTableName).append(".datevalue IS NOT NULL OR ").append(searchTableName).append(".textvalue IS NOT NULL OR ").append(searchTableName).append(".numvalue IS NOT NULL) ");
query.append(" ) ");
return hasAppendWhereClause;
}
private boolean appendValuedAttributeFilterQueryBlocks(EntitySearchFilter filter, int index, StringBuffer query, boolean hasAppendWhereClause) {
String searchTableNameAlias = this.getEntitySearchTableName()+index;
hasAppendWhereClause = this.verifyWhereClauseAppend(query, hasAppendWhereClause);
query.append(searchTableNameAlias).append(".attrname = ? ");
hasAppendWhereClause = this.addAttributeLangQueryBlock(searchTableNameAlias, query, filter, hasAppendWhereClause);
if (filter.isLikeOption() && this.isForceTextCaseSearch()) {
return hasAppendWhereClause;
}
if (filter.getAllowedValues() != null && filter.getAllowedValues().size() > 0) {
hasAppendWhereClause = this.verifyWhereClauseAppend(query, hasAppendWhereClause);
List<Object> allowedValues = filter.getAllowedValues();
for (int j = 0; j < allowedValues.size(); j++) {
Object allowedValue = allowedValues.get(j);
if (j == 0) {
query.append(" ( ");
} else {
query.append(" OR ");
}
String operator = filter.isLikeOption() ? this.getLikeClause() : "= ? ";
query.append(searchTableNameAlias).append(".").append(this.getAttributeFieldColunm(allowedValue)).append(" ");
query.append(operator);
if (j == (allowedValues.size()-1)) query.append(" ) ");
}
} else if (filter.getValue() != null) {
Object object = filter.getValue();
String operator = filter.isLikeOption() ? this.getLikeClause() : "= ? ";
hasAppendWhereClause = this.addAttributeObjectSearchQueryBlock(searchTableNameAlias, query,
object, operator, hasAppendWhereClause, filter.getLangCode());
} else {
//creazione blocco selezione su tabella ricerca
if (null != filter.getStart()) {
hasAppendWhereClause = this.addAttributeObjectSearchQueryBlock(searchTableNameAlias, query,
filter.getStart(), ">= ? ", hasAppendWhereClause, filter.getLangCode());
}
if (null != filter.getEnd()) {
hasAppendWhereClause = this.addAttributeObjectSearchQueryBlock(searchTableNameAlias, query,
filter.getEnd(), "<= ? ", hasAppendWhereClause, filter.getLangCode());
}
if (null == filter.getStart() && null == filter.getEnd()) {
hasAppendWhereClause = this.verifyWhereClauseAppend(query, hasAppendWhereClause);
query.append(" (").append(searchTableNameAlias).append(".datevalue IS NOT NULL OR ").append(searchTableNameAlias).append(".textvalue IS NOT NULL OR ").append(searchTableNameAlias).append(".numvalue IS NOT NULL) ");
}
}
return hasAppendWhereClause;
}
protected boolean addAttributeLangQueryBlock(String searchTableName, StringBuffer query,
EntitySearchFilter filter, boolean hasAppendWhereClause) {
if (filter.isAttributeFilter() && null != filter.getLangCode()) {
hasAppendWhereClause = this.verifyWhereClauseAppend(query, hasAppendWhereClause);
query.append(searchTableName).append(".langcode = ? ");
}
return hasAppendWhereClause;
}
protected boolean appendMetadataFieldFilterQueryBlocks(EntitySearchFilter[] filters, StringBuffer query, boolean hasAppendWhereClause) {
if (filters == null) return hasAppendWhereClause;
for (int i=0; i<filters.length; i++) {
EntitySearchFilter filter = filters[i];
if (filter.getKey() != null && !filter.isAttributeFilter()) {
hasAppendWhereClause = this.addMetadataFieldFilterQueryBlock(filter, query, hasAppendWhereClause);
}
}
return hasAppendWhereClause;
}
protected boolean appendOrderQueryBlocks(EntitySearchFilter[] filters, StringBuffer query, boolean ordered) {
if (filters == null) return ordered;
for (int i=0; i<filters.length; i++) {
EntitySearchFilter filter = filters[i];
if (null != filter.getKey() && null != filter.getOrder() && !filter.isNullOption()) {
if (!ordered) {
query.append("ORDER BY ");
ordered = true;
} else {
query.append(", ");
}
if (filter.isAttributeFilter()) {
String tableName = this.getEntitySearchTableName() + i;
this.addAttributeOrderQueryBlock(tableName, query, filter, filter.getOrder());
} else {
String fieldName = this.getTableFieldName(filter.getKey());
query.append(this.getEntityMasterTableName()).append(".").append(fieldName).append(" ").append(filter.getOrder());
}
}
}
return ordered;
}
protected boolean addAttributeObjectSearchQueryBlock(String searchTableName,
StringBuffer query, Object object, String operator, boolean hasAppendWhereClause, String langCode) {
hasAppendWhereClause = this.verifyWhereClauseAppend(query, hasAppendWhereClause);
query.append(searchTableName).append(".").append(this.getAttributeFieldColunm(object)).append(" ");
query.append(operator);
return hasAppendWhereClause;
}
protected boolean verifyWhereClauseAppend(StringBuffer query, boolean hasAppendWhereClause) {
if (hasAppendWhereClause) {
query.append("AND ");
} else {
query.append("WHERE ");
hasAppendWhereClause = true;
}
return hasAppendWhereClause;
}
private void addAttributeOrderQueryBlock(String searchTableNameAlias, StringBuffer query, EntitySearchFilter filter, String order) {
if (order == null) order = "";
Object object = filter.getValue();
if (object == null) object = filter.getStart();
if (object == null) object = filter.getEnd();
if (null == object) {
query.append(searchTableNameAlias).append(".textvalue ").append(order).append(", ")
.append(searchTableNameAlias).append(".datevalue ").append(order).append(", ")
.append(searchTableNameAlias).append(".numvalue ").append(order);
return;
}
query.append(searchTableNameAlias).append(".").append(this.getAttributeFieldColunm(object)).append(" ");
query.append(order);
}
private String getAttributeFieldColunm(EntitySearchFilter filter) {
Object object = null;
if (null != filter.getAllowedValues() && filter.getAllowedValues().size() > 0) {
object = filter.getAllowedValues().get(0);
} else if (null != filter.getValue()) {
object = filter.getValue();
} else if (null != filter.getStart()) {
object = filter.getStart();
} else if (null != filter.getEnd()) {
object = filter.getEnd();
} else {
return null;
}
return this.getAttributeFieldColunm(object);
}
private String getAttributeFieldColunm(Object attributeValue) {
String columnName = null;
if (null == attributeValue) {
columnName = null;
} else if (attributeValue instanceof String) {
columnName = "textvalue";
} else if (attributeValue instanceof Date) {
columnName = "datevalue";
} else if (attributeValue instanceof BigDecimal) {
columnName = "numvalue";
} else if (attributeValue instanceof Boolean) {
columnName = "textvalue";
}
return columnName;
}
/**
* Return the name of the entities master table.
* @return The name of the master table.
*/
protected abstract String getEntityMasterTableName();
/**
* Return the name of the "entity ID" field in the master entity table.
* @return The name of the "entity ID" field.
*/
protected abstract String getEntityMasterTableIdFieldName();
/**
* Return the name of the "Entity Type code" in the master entity table.
* @return The name of the "Entity Type code".
*/
protected abstract String getEntityMasterTableIdTypeFieldName();
/**
* Return the name of the support table used to perform search on entities.
* @return The name of the support table.
*/
protected abstract String getEntitySearchTableName();
/**
* Return the name of the "Entity ID" in the support table used to perform search on entities.
* @return The name of "Entity ID" field.
*/
protected abstract String getEntitySearchTableIdFieldName();
@Override
protected String getMasterTableIdFieldName() {
return this.getEntityMasterTableIdFieldName();
}
@Override
protected String getMasterTableName() {
return this.getEntityMasterTableName();
}
}