/**
* Copyright (C) 2015 Orion Health (Orchestral Development Ltd)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xbdd.webapp.resource.feature;
import java.util.Collection;
import java.util.Comparator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.apache.commons.lang.StringUtils;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.mongodb.DBObject;
/**
* Matcher that compares two DBObjects by the number of times they match a set of regular expressions
*/
public class DBObjectComparator implements Comparator<DBObject> {
final private ConcurrentMap<DBObject, Integer> cachedCounts = new ConcurrentHashMap<>();
private Pattern pattern;
/**
* Construct a {@link Comparator} with the given set of expressions
*
* @param searchExpressions a list of regular expressions
* @throws PatternSyntaxException if any of the expressions are not valid regex
*/
public DBObjectComparator(final Collection<String> searchExpressions) {
final String regex = StringUtils.join(Collections2.transform(searchExpressions, new Function<String, String>() {
@Override
public String apply(final String input) {
return "(" + input + ")";
}
}), "|");
this.pattern = Pattern.compile(regex);
}
@Override
public int compare(final DBObject obj1, final DBObject obj2) {
final int obj1Count = getCount(obj1);
final int obj2Count = getCount(obj2);
return obj2Count - obj1Count;
}
private int getCount(final DBObject obj) {
int count;
if (obj == null) {
count = 0;
} else if (this.cachedCounts.containsKey(obj)) {
count = this.cachedCounts.get(obj);
} else {
count = countMatches(this.pattern.matcher(obj.toString()));
this.cachedCounts.put(obj, count);
}
return count;
}
private int countMatches(final Matcher matcher) {
int accumulator = 0;
while (matcher.find()) {
accumulator++;
}
return accumulator;
}
}