2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.northbound.commons.query;
10 import java.util.ArrayList;
11 import java.util.Collection;
12 import java.util.Iterator;
13 import java.util.List;
14 import java.util.regex.Pattern;
16 import org.opendaylight.controller.northbound.commons.query.CompareExpression.OP;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
23 /*package*/ class QueryImpl<T> implements Query<T> {
24 public static final Logger LOGGER = LoggerFactory.getLogger(QueryImpl.class);
25 private static final boolean ALLOW_OBJECT_STRING_COMPARE = true;
27 private final Expression expression;
28 private final TypeInfo rootType ;
30 * Set the expression and cache
34 public QueryImpl(Class<T> type, Expression expression) {
35 this.expression = expression;
36 this.rootType = TypeInfo.createRoot(null, type);
40 public List<T> find(Collection<T> collection) throws QueryException {
41 // new arraylist for result
42 List<T> result = new ArrayList<T>();
43 for (T item : collection) {
44 if (match(item, rootType)) {
52 public int filter(Collection<T> collection) throws QueryException {
54 List<T> matched = new ArrayList<T>();
55 for (T item : collection) {
56 if (match(item, rootType)) {
61 collection.addAll(matched);
62 return matched.size();
65 @SuppressWarnings({ "rawtypes", "unchecked" })
67 public int filter(T rootObject, Class<?> childClass) throws QueryException {
68 // retrieve underlying collection
69 TypeInfo childType = rootType.getCollectionChild(childClass);
70 if (childType == null || !(childType instanceof IteratableTypeInfo)) {
73 Collection collection = (Collection)
74 childType.getAccessor().getValue(rootObject);
75 // get the child type of the collection type
76 TypeInfo ti = childType.getCollectionChild(childClass);
77 List matched = new ArrayList();
78 for (Object item : collection) {
79 if (match(item, ti)) {
84 collection.addAll(matched);
85 return matched.size();
88 private boolean match(final Object object, final TypeInfo rootType)
89 throws QueryException {
90 return expression.accept(new Visitor () {
92 public boolean visit(LogicalExpression le) throws QueryException {
93 if (LOGGER.isDebugEnabled()) {
94 LOGGER.debug("Logical exp {}|{}|{}", le.getOperator(), le.getFirst(),
97 return (le.getOperator() == LogicalExpression.OP.AND) ?
98 le.getFirst().accept(this) && le.getSecond().accept(this) :
99 le.getFirst().accept(this) || le.getSecond().accept(this);
103 public boolean visit(CompareExpression ce) throws QueryException {
104 boolean result = visitInternal(ce);
105 if (LOGGER.isDebugEnabled()) {
106 LOGGER.debug("=== Compare exp {}|{}|{} == {}", ce.getOperator(),
107 ce.getSelector(), ce.getArgument(), result);
112 public boolean visitInternal(CompareExpression ce) throws QueryException {
113 String[] selector = ce.getSelector().split("\\.");
114 if (!rootType.getName().equals(selector[0])) {
115 if (LOGGER.isDebugEnabled()) {
116 LOGGER.debug("Root name mismatch: {} != {}",
117 rootType.getName(), selector[0]);
121 Object value = rootType.retrieve(object, selector, 1);
122 if(value == null){ // nothing to compare against
125 if (LOGGER.isDebugEnabled()) {
126 LOGGER.debug("Comparing [{}] {} [{}]", ce.getArgument(),
127 ce.getOperator(), value.toString());
129 if (value instanceof Collection) {
130 Collection<?> collection = (Collection<?>) value;
131 if(collection.size() == 0 && ce.getOperator() == OP.NE) {
132 // collection doesn't contain query string
135 // If there are elements iterate
136 Iterator<?> it = collection.iterator();
137 OP operator = ce.getOperator();
138 if (operator == OP.NE) {
139 // negate the operator
142 while (it.hasNext()) {
143 Object item = it.next();
144 if (compare(parse(ce.getArgument(), item), item, operator)) {
145 // if match found check the operator and return false for NE
146 return (ce.getOperator() != OP.NE);
149 // return true for NE and false for rest
150 return (ce.getOperator() == OP.NE);
152 return compare(parse(ce.getArgument(), value), value,
160 private boolean compare(Object valueToMatch, Object actualValue, OP operator) {
161 if (valueToMatch == null || actualValue == null) {
164 if (ALLOW_OBJECT_STRING_COMPARE && (valueToMatch instanceof String)
165 && !(actualValue instanceof String)) {
166 actualValue = actualValue.toString();
169 int compareResult = -1;
170 if (valueToMatch instanceof Comparable) {
171 compareResult = ((Comparable)actualValue).compareTo(valueToMatch);
173 if (LOGGER.isDebugEnabled()) {
174 LOGGER.debug("Not a comparable type: {} {}",
175 valueToMatch.getClass().getName(),
176 actualValue.getClass().getName());
182 return compareResult == 0;
185 if (valueToMatch instanceof String) {
186 return Pattern.matches((String)valueToMatch, actualValue.toString());
188 return compareResult == 0;
191 return compareResult != 0;
193 return compareResult > 0;
195 return compareResult >= 0;
197 return compareResult < 0;
199 return compareResult <= 0;
201 if (LOGGER.isDebugEnabled()) {
202 LOGGER.debug("Unrecognized comparator - {}", operator);
207 private Object parse(String arg, Object value) {
213 if (value instanceof String) {
215 } else if (value instanceof Byte) {
216 return Byte.decode(arg);
217 } else if (value instanceof Double) {
218 return Double.parseDouble(arg);
219 } else if (value instanceof Float) {
220 return Float.parseFloat(arg);
221 } else if (value instanceof Integer) {
222 return Integer.parseInt(arg);
223 } else if (value instanceof Long) {
224 return Long.parseLong(arg);
225 } else if (value instanceof Short) {
226 return Short.parseShort(arg);
228 } catch (NumberFormatException ignore) {
229 if (LOGGER.isDebugEnabled()) {
230 LOGGER.debug("Exception parsing {}", arg, value);
233 if (LOGGER.isDebugEnabled()) {
234 LOGGER.debug("Using string comparision for type - {}",
235 value.getClass().getName());
237 // Not a number or string. Convert to a string and compare as last resort
238 return ALLOW_OBJECT_STRING_COMPARE ? arg.toString() : null;