/*
* Copyright 2011 Future Systems, Inc.
*
* 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 org.krakenapps.confdb;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.krakenapps.api.PrimitiveConverter;
public class Predicates {
public static Predicate eq(Object o) {
return new EqObject(o);
}
public static Predicate has(String field) {
return new HasKey(field);
}
public static Predicate field(String field, Object value) {
return new KeyMatch(field, value);
}
public static Predicate field(Map<String, Object> terms) {
return new KeyMatch(terms);
}
public static Predicate in(String field, Collection<? extends Object> values) {
return new KeyContains(field, values);
}
public static Predicate and(Predicate... pred) {
return new Conjunction(pred);
}
public static Predicate or(Predicate... pred) {
return new Disjunction(pred);
}
public static Predicate not(Predicate pred) {
return new Not(pred);
}
static Object getValue(Config c, String[] keys) {
return getValue(c, keys, false);
}
@SuppressWarnings("unchecked")
static Object getValue(Config c, String[] keys, boolean throwException) {
Object value = c.getDocument();
for (String k : keys) {
if (!(value instanceof Map)) {
if (throwException)
throw new IllegalArgumentException();
return null;
}
Map<String, Object> m = (Map<String, Object>) value;
if (!m.containsKey(k)) {
if (throwException)
throw new IllegalArgumentException();
return null;
}
value = m.get(k);
}
return value;
}
private static List<Predicate> checkPredicateNull(Predicate... pred) {
List<Predicate> ps = new ArrayList<Predicate>();
for (Predicate p : pred) {
if (p != null)
ps.add(p);
}
return ps;
}
private static class EqObject implements Predicate {
private Object o;
public EqObject(Object o) {
this.o = o;
}
@Override
public boolean eval(Config c) {
return c.getDocument().equals(o);
}
}
private static class HasKey implements Predicate {
private String key;
public HasKey(String key) {
this.key = key;
}
@Override
public boolean eval(Config c) {
try {
getValue(c, key.split("/"), true);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
}
private static class KeyMatch implements Predicate {
private Map<String, Object> terms;
private Map<String, String[]> underscoreMap = new HashMap<String, String[]>();
public KeyMatch(String key, Object value) {
this.terms = new HashMap<String, Object>();
this.terms.put(key, value);
underscoreMap.put(key, PrimitiveConverter.toUnderscoreName(key).split("/"));
}
public KeyMatch(Map<String, Object> terms) {
this.terms = terms;
for (String term : terms.keySet())
underscoreMap.put(term, PrimitiveConverter.toUnderscoreName(term).split("/"));
}
@Override
public boolean eval(Config c) {
Object doc = c.getDocument();
if (!(doc instanceof Map))
return false;
for (String k : terms.keySet()) {
Object value = getValue(c, underscoreMap.get(k));
Object comp = terms.get(k);
if (value == null && comp != null)
return false;
if (value == null && comp == null)
continue;
if (!value.equals(comp))
return false;
}
return true;
}
}
private static class KeyContains implements Predicate {
private String[] keys;
private Collection<? extends Object> values;
public KeyContains(String key, Collection<? extends Object> values) {
this.keys = PrimitiveConverter.toUnderscoreName(key).split("/");
this.values = values;
}
@Override
public boolean eval(Config c) {
Object v = getValue(c, keys);
return values.contains(v);
}
}
private static class Conjunction implements Predicate {
private Predicate[] pred;
public Conjunction(Predicate... pred) {
List<Predicate> ps = checkPredicateNull(pred);
this.pred = ps.toArray(new Predicate[ps.size()]);
}
@Override
public boolean eval(Config c) {
for (Predicate p : pred) {
if (!p.eval(c))
return false;
}
return true;
}
}
private static class Disjunction implements Predicate {
private Predicate[] pred;
public Disjunction(Predicate... pred) {
List<Predicate> ps = checkPredicateNull(pred);
this.pred = ps.toArray(new Predicate[ps.size()]);
}
@Override
public boolean eval(Config c) {
for (Predicate p : pred) {
if (p.eval(c))
return true;
}
return false;
}
}
private static class Not implements Predicate {
private Predicate pred;
public Not(Predicate pred) {
if (pred == null)
throw new IllegalArgumentException("pred should be not null");
this.pred = pred;
}
@Override
public boolean eval(Config c) {
return !pred.eval(c);
}
}
}