/*
* Jajuk
* Copyright (C) The Jajuk Team
* http://jajuk.info
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package org.jajuk.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.apache.commons.lang.StringUtils;
import org.jajuk.base.Item;
import org.jajuk.base.PropertyMetaInformation;
import org.jajuk.util.log.Log;
/**
* Filter on meta information.
*/
public class Filter {
/** Key. */
String key;
/** Value*. */
String sValue;
/** Human*. */
boolean bHuman = false;
/** Exact*. */
boolean bExact = false;
/**
* Filter constructor.
*
* @param key key (property name). null if the filter is on any property
* @param sValue value
* @param bHuman is the filter apply value itself or its human representation if
* different ?
* @param bExact is the filter should match exactly the value ?
*/
public Filter(String key, String sValue, boolean bHuman, boolean bExact) {
this.key = key;
this.sValue = sValue;
this.bHuman = bHuman;
this.bExact = bExact;
}
/**
* Checks if is exact.
*
* @return true, if is exact
*/
public boolean isExact() {
return bExact;
}
/**
* Checks if is human.
*
* @return true, if is human
*/
public boolean isHuman() {
return bHuman;
}
/**
* Gets the property.
*
* @return the property
*/
public String getProperty() {
return key;
}
/**
* Gets the value.
*
* @return the value
*/
public String getValue() {
return sValue;
}
/**
* Filter a list.
* <p>
* Work on the input collection (for performance reasons and to save memory we
* don't create a new list)
* </p>
* <p>
* This filter is not thread safe.
* </p>
*
* @param list The input list to filter. Filtering is done in-place on this list.
* @param filter The filter to apply on the list.
*/
public static <T extends Item> List<T> filterItems(List<T> list, Filter filter,
@SuppressWarnings("unused")
Class<T> clazz) {
if (filter == null || filter.getValue() == null) {
return list;
}
// Check if property is not the "fake" any property
boolean bAny = (filter.getProperty() == null || "any".equals(filter.getProperty()));
String comparator = null;
String checked = filter.getValue();
// If checked is void, return the list as it
if (StringUtils.isBlank(checked)) {
return list;
}
// If pattern is wrong, return a void list
try {
Pattern.compile(checked);
} catch (PatternSyntaxException e) {
Log.debug("Wrong regexp pattern: " + checked);
return Collections.emptyList();
}
List<T> newList = new ArrayList<T>();
Iterator<T> it = list.iterator();
while (it.hasNext()) {
T item = it.next();
// If none property set, the search if global "any"
if (bAny) {
comparator = item.getAny();
} else {
if (filter.isHuman()) {
comparator = item.getHumanValue(filter.getProperty());
} else {
comparator = item.getStringValue(filter.getProperty());
}
}
// perform the test
boolean bMatch = false;
if (filter.isExact()) {
// Check every item property (no not use getAny() string will not match
// as it is a concatenation of all properties)
for (String propertyName : item.getProperties().keySet()) {
// Ignore technical/invisible property (id for instance)
PropertyMetaInformation meta = item.getMeta(propertyName);
if (!meta.isVisible()) {
continue;
}
String value = item.getHumanValue(propertyName);
// Escape the string so regexp ignore special characters
value = UtilString.escapeString(value);
if (value.matches(checked)) {
bMatch = true;
break;
}
}
} else {
// Do not use Regexp matches() method, too costly
bMatch = UtilString.matchesIgnoreCaseAndOrder(checked, comparator);
}
if (bMatch) {
newList.add(item);
}
}
return newList;
}
}