/* * * 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.model; import java.io.Serializable; import java.math.BigDecimal; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Properties; import com.agiletec.aps.system.ApsSystemUtils; import com.agiletec.aps.system.common.FieldSearchFilter; import com.agiletec.aps.system.common.entity.model.attribute.AttributeInterface; import com.agiletec.aps.system.common.entity.model.attribute.BooleanAttribute; import com.agiletec.aps.system.common.entity.model.attribute.DateAttribute; import com.agiletec.aps.system.common.entity.model.attribute.ITextAttribute; import com.agiletec.aps.system.common.entity.model.attribute.NumberAttribute; import com.agiletec.aps.system.exception.ApsSystemException; import com.agiletec.aps.util.DateConverter; /** * This class implements a filter to search among entities. * @author E.Santoboni */ public class EntitySearchFilter extends FieldSearchFilter implements Serializable { /** * Filter constructor. * This constructor is used when checking the presence of a value contained * either in the attribute field or in the entity metadata. * @param key The key of the filtering element; it may be a content attribute of type {@link AttributeInterface} * or the ID of metadata). * @param isAttributeFilter Decide whether the filter is applied to an Entity Attribute (true) or * to a metadata (false). */ public EntitySearchFilter(String key, boolean isAttributeFilter) { super(key); this.setAttributeFilter(isAttributeFilter); } /** * Filter constructor. * This constructor must be used to filter the attribute values or entity metadata * looking for a specific value. * @param key The key of the filtering element; it may be a content attribute of type {@link AttributeInterface} * or the ID of metadata). * @param isAttributeFilter Decide whether the filter is applied to an Entity Attribute (true) or * to a metadata (false). * @param value The value to look for. If null, the filter checks if the attribute (or metadata) * has been valued. * @param useLikeOption When true the database search will be performed using the "LIKE" clause. * This option can be used to filter by the value of a string attribute (or metadata). It can be * used only with string and with not null values. */ public EntitySearchFilter(String key, boolean isAttributeFilter, Object value, boolean useLikeOption) { this(key, isAttributeFilter); this.setValue(value); this.setLikeOption(useLikeOption); } /** * Filter constructor. * This constructor is used when filtering by a range of values; this can applied to both * Entity Attributes and metadata). * @param key The key of the filtering element; it may be a content attribute of type {@link AttributeInterface} * or the ID of metadata). * @param isAttributeFilter Decide whether the filter is applied to an Entity Attribute (true) or * to a metadata (false). * @param start The starting value of the interval. It can be an object of type * "String", "Date", "BigDecimal", "Boolean" o null. * @param end The ending value of the interval. It can be an object of type * "String", "Date", "BigDecimal", "Boolean" o null. */ public EntitySearchFilter(String key, boolean isAttributeFilter, Object start, Object end) { this(key, isAttributeFilter); if (start != null && end != null && !start.getClass().equals(end.getClass())) { throw new RuntimeException("Error: 'start' and 'end' types have to be equals"); } this.setStart(start); this.setEnd(end); } /** * Filter constructor. * This constructor is used when filtering by a collection of allowed values; this can applied to both * Entity Attributes and metadata). * @param key The key of the filtering element; it may be a content attribute of type {@link AttributeInterface} * or the ID of metadata). * @param isAttributeFilter Decide whether the filter is applied to an Entity Attribute (true) or * to a metadata (false). * @param allowedValues The allowed values to look for. If null, the filter checks * if the attribute (or metadata) has been valued. * @param useLikeOption When true the database search will be performed using the "LIKE" clause. * This option can be used to filter by the value of a string attribute (or metadata). It can be * used only with string and with allowed values not null. */ public EntitySearchFilter(String key, boolean isAttributeFilter, List<Object> allowedValues, boolean useLikeOption) { this(key, isAttributeFilter); this.setAllowedValues(allowedValues); this.setLikeOption(useLikeOption); } /** * This method shows if the filter must be applied on a Entity Attribute or * a metadata. * @return true if the filter is to be applied to an attribute entity or a * to a metadata of the an entity. */ public boolean isAttributeFilter() { return _attributeFilter; } protected void setAttributeFilter(boolean attributeFilter) { this._attributeFilter = attributeFilter; } public String getLangCode() { return this._langCode; } public void setLangCode(String langCode) { if (null == langCode) return; if (!this.isAttributeFilter()) { throw new RuntimeException("Error: The language can be only specified on attribute filters"); } if ((null != this.getValue() && !(this.getValue() instanceof String)) || (null != this.getStart() && !(this.getStart() instanceof String)) || (null != this.getEnd() && !(this.getEnd() instanceof String)) || (this.getAllowedValues() != null && !this.getAllowedValues().isEmpty() && !(this.getAllowedValues().get(0) instanceof String))) { throw new RuntimeException("Error: The language can be only specified on a null value of type string"); } this._langCode = langCode; } @Override public String toString() { StringBuffer param = new StringBuffer(); param.append(KEY_PARAM).append("=").append(this.getKey()).append(SEPARATOR); param.append(FILTER_TYPE_PARAM).append("=").append(Boolean.toString(this.isAttributeFilter())); this.appendParamValue(param, this.getValue(), VALUE_PARAM); this.appendParamValue(param, this.getOrder(), ORDER_PARAM); if (this.getValue() instanceof String) { this.appendParamValue(param, this.isLikeOption(), LIKE_OPTION_PARAM); } if (null != this.getAllowedValues() && !this.getAllowedValues().isEmpty()) { this.appendParamValue(param, this.getAllowedValues(), ALLOWED_VALUES_PARAM); } this.appendParamValue(param, this.getLangCode(), LANG_PARAM); this.appendParamValue(param, this.getStart(), START_PARAM); this.appendParamValue(param, this.getEnd(), END_PARAM); this.appendParamValue(param, this.getOrder(), ORDER_PARAM); return param.toString(); } private void appendParamValue(StringBuffer param, Object value, String paramValue) { if (null != value) { param.append(SEPARATOR).append(paramValue).append("="); if (value instanceof List) { List<Object> values = (List<Object>) value; for (int i = 0; i < values.size() ; i++) { if (i>0) param.append(ALLOWED_VALUES_SEPARATOR); param.append(values.get(i)); } } else { param.append(this.getToStringValue(value)); } } } private String getToStringValue(Object value) { if (value instanceof String) { return value.toString(); } else if (value instanceof Date) { return DateConverter.getFormattedDate((Date)value, DATE_PATTERN); } else if (value instanceof BigDecimal) { value = ((BigDecimal)value).toString(); } else if (value instanceof Boolean) { value = ((Boolean)value).toString(); } return value.toString(); } @Deprecated public static EntitySearchFilter getInstance(IApsEntity prototype, String toStringFilter) { return getInstance(prototype, getProperties(toStringFilter)); } @Deprecated public static Properties getProperties(String toStringFilter) { Properties props = new Properties(); String[] params = toStringFilter.split(SEPARATOR); for (int i=0; i<params.length; i++) { String[] elements = params[i].split("="); if (elements.length != 2) continue; props.setProperty(elements[0], elements[1]); } return props; } public static EntitySearchFilter getInstance(IApsEntity prototype, Properties props) { EntitySearchFilter filter = null; try { String key = props.getProperty(KEY_PARAM); if (null == key) return null; boolean isAttributeFilter = Boolean.parseBoolean(props.getProperty(FILTER_TYPE_PARAM)); filter = new EntitySearchFilter(key, isAttributeFilter); if (!isAttributeFilter) { String dataType = props.getProperty(DATA_TYPE_PARAM); if (null == dataType) dataType = DATA_TYPE_STRING; setValues(filter, props, dataType); } else { AttributeInterface attr = (AttributeInterface) prototype.getAttribute(key); if (null != attr && null != prototype) { String dataType = null; if (attr instanceof DateAttribute) { dataType = DATA_TYPE_DATE; } else if (attr instanceof ITextAttribute || attr instanceof BooleanAttribute) { dataType = DATA_TYPE_STRING; } else if (attr instanceof NumberAttribute) { dataType = DATA_TYPE_NUMBER; } setValues(filter, props, dataType); } else throw new ApsSystemException("ERROR: Entity type '" + prototype.getTypeCode() + "' and attribute '" + key + "' not recognized"); } String order = props.getProperty(EntitySearchFilter.ORDER_PARAM); filter.setOrder(order); } catch (Throwable t) { ApsSystemUtils.logThrowable(t, EntitySearchFilter.class, "Error on creation of filter instance"); throw new RuntimeException("Error on creation of filter instance", t); } return filter; } private static void setValues(EntitySearchFilter filter, Properties props, String dataType) { if (null == dataType) return; String value = props.getProperty(VALUE_PARAM); String allowedValues = props.getProperty(ALLOWED_VALUES_PARAM); String start = props.getProperty(START_PARAM); String end = props.getProperty(END_PARAM); Object objectValue = getDataObject(value, dataType); List<Object> objectAllowedValues = buildAllowedValues(allowedValues, dataType); Object objectStart = getDataObject(start, dataType); Object objectEnd = getDataObject(end, dataType); String likeOptionString = props.getProperty(LIKE_OPTION_PARAM); boolean likeOption = (null != likeOptionString) ? Boolean.parseBoolean(likeOptionString) : false; if (objectValue != null) { filter.setValue(objectValue); filter.setLikeOption(likeOption); } else if (objectAllowedValues != null) { filter.setAllowedValues(objectAllowedValues); filter.setLikeOption(likeOption); } else { filter.setStart(objectStart); filter.setEnd(objectEnd); } String langCode = props.getProperty(LANG_PARAM); filter.setLangCode(langCode); } private static List<Object> buildAllowedValues(String allowedValues, String dataType) { if (null == allowedValues) return null; List<Object> values = null; String[] stringValues = allowedValues.split(ALLOWED_VALUES_SEPARATOR); if (null != stringValues && stringValues.length > 0) { values = new ArrayList<Object>(); for (int i = 0; i < stringValues.length; i++) { String stringValue = stringValues[i]; Object object = getDataObject(stringValue, dataType); if (null != object) { values.add(object); } } } if (null == values || values.size() == 0) return null; return values; } private static Object getDataObject(String stringValue, String dataType) { if (null == stringValue) return null; Object object = null; if (dataType.equals(DATA_TYPE_DATE)) { object = buildDate(stringValue); } else if (dataType.equals(DATA_TYPE_STRING)) { object = stringValue; } else if (dataType.equals(DATA_TYPE_NUMBER)) { object = buildNumber(stringValue); } return object; } private static Date buildDate(String dateString) { String today = "today, oggi, odierna"; Date data = null; try { if (today.indexOf(dateString) != -1) { data = new java.util.Date(); } else { SimpleDateFormat dataF = new SimpleDateFormat(EntitySearchFilter.DATE_PATTERN); data = dataF.parse(dateString); } } catch (ParseException ex) { ApsSystemUtils.getLogger().severe("Invalid string - '" + dateString + "'"); } return data; } private static BigDecimal buildNumber(String numberString) { BigDecimal number = null; try { number = new BigDecimal(numberString); } catch (NumberFormatException e) { ApsSystemUtils.getLogger().severe("Invalid string - '" + numberString + "'"); } return number; } private boolean _attributeFilter; private String _langCode; public static final String SEPARATOR = ";"; public static final String KEY_PARAM = "key"; public static final String FILTER_TYPE_PARAM = "attributeFilter"; public static final String VALUE_PARAM = "value"; public static final String ALLOWED_VALUES_PARAM = "allowedValues"; public static final String ALLOWED_VALUES_SEPARATOR = ","; public static final String LIKE_OPTION_PARAM = "likeOption"; public static final String LANG_PARAM = "lang"; public static final String START_PARAM = "start"; public static final String END_PARAM = "end"; public static final String ORDER_PARAM = "order"; public static final String DATA_TYPE_PARAM = "dataType"; public static final String DATA_TYPE_STRING = "string"; public static final String DATA_TYPE_DATE = "date"; public static final String DATA_TYPE_NUMBER = "number"; public static final String DATE_PATTERN = "dd/MM/yyyy"; }