- Retreive operations can be filtered based on FIQL queries.
- Spec at http://tools.ietf.org/html/draft-nottingham-atompub-fiql-00
- Details of the feature can be found at
https://pad.opendaylight.org/p/rest-search
Change-Id: I3d7cc4350e890148fff5bd086f76ec51e63f2c3b
Signed-off-by: Prasanth Pallamreddy <ppallamr@cisco.com>
<ignore></ignore>
</action>
</pluginExecution>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>javacc-maven-plugin</artifactId>
+ <versionRange>[0.0,)</versionRange>
+ <goals>
+ <goal>javacc</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <execute>
+ <runOnIncremental>false</runOnIncremental>
+ </execute>
+ </action>
+ </pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
<version>0.4.2-SNAPSHOT</version>
<packaging>bundle</packaging>
<dependencies>
-
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<groupId>org.opendaylight.controller</groupId>
<artifactId>usermanager</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
<build>
<Export-Package>org.opendaylight.controller.northbound.commons.exception,
org.opendaylight.controller.northbound.commons.types,
org.opendaylight.controller.northbound.commons.utils,
+ org.opendaylight.controller.northbound.commons.query,
org.opendaylight.controller.northbound.commons</Export-Package>
<Import-Package>javax.ws.rs,
javax.ws.rs.ext,
<manifestLocation>${project.basedir}/META-INF</manifestLocation>
</configuration>
</plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>add-source</id>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <phase>generate-sources</phase>
+ <configuration>
+ <sources>
+ <source>${project.build.directory}/generated-sources/javacc</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>javacc-maven-plugin</artifactId>
+ <version>2.6</version>
+ <executions>
+ <execution>
+ <id>javacc</id>
+ <goals>
+ <goal>javacc</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
</plugins>
</build>
<scm>
import javax.xml.bind.annotation.XmlRootElement;
import org.opendaylight.controller.northbound.bundlescanner.IBundleScanService;
+import org.opendaylight.controller.northbound.commons.query.QueryContextProvider;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleReference;
} );
_singletons.add(getJsonProvider());
_singletons.add(new JacksonJsonProcessingExceptionMapper());
+ _singletons.add(new QueryContextProvider());
}
////////////////////////////////////////////////////////////////
--- /dev/null
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+
+/*package*/ class Accessor {
+ protected final AccessibleObject _accessorObj;
+
+ public Accessor(AccessibleObject accessor) {
+ _accessorObj = accessor;
+ _accessorObj.setAccessible(true);
+ }
+
+ public AccessibleObject getAccessibleObject() {
+ return _accessorObj;
+ }
+
+ public Annotation[] getAnnotations() {
+ return _accessorObj.getAnnotations();
+ }
+
+ public Object getValue(Object parent) throws QueryException {
+ try {
+ if (_accessorObj instanceof Field) {
+ return ((Field)_accessorObj).get(parent);
+ } else {
+ // assume method
+ return ((Method)_accessorObj).invoke(parent);
+ }
+ } catch (Exception e) {
+ throw new QueryException("Failure in retrieving value", e);
+ }
+ }
+ public Type getGenericType() {
+ if (_accessorObj instanceof Field) {
+ return ((Field)_accessorObj).getGenericType();
+ } else {
+ // assume method
+ return ((Method)_accessorObj).getGenericReturnType();
+ }
+ }
+ public Class<?> getType() {
+
+ if (_accessorObj instanceof Field) {
+ return ((Field)_accessorObj).getType();
+ } else {
+ // assume method
+ return ((Method)_accessorObj).getReturnType();
+ }
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+/*package*/ class CompareExpression implements Expression {
+
+ public static enum OP { RE, EQ, NE, GT, GE, LT, LE };
+
+ private final OP _operation;
+ private final String _selector;
+ private final String _arg;
+
+ public CompareExpression(OP op, String selector, String arg) {
+ _operation = op;
+ _selector = selector;
+ _arg = unQuote(arg);
+ }
+
+
+ public OP getOperator() {
+ return _operation;
+ }
+
+ public String getSelector() {
+ return _selector;
+ }
+
+ public String getArgument() {
+ return _arg;
+ }
+
+ @Override
+ public boolean accept(Visitor visitor) throws QueryException {
+ return visitor.visit(this);
+ }
+
+ @Override
+ public String toString() {
+ return "[" + _selector + " " + _operation + " " + _arg + "]";
+ }
+
+ private static String unQuote(String s) {
+ if (s.startsWith("\"") && s.endsWith("\"")) {
+ s = s.substring(1, s.length()-1);
+ } else if (s.startsWith("\'") && s.endsWith("\'")) {
+ s = s.substring(1, s.length()-1);
+ }
+ return s;
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+/*package*/ interface Expression {
+ boolean accept(Visitor visitor) throws QueryException;
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.util.Stack;
+
+/*package*/ class ExpressionBuilder {
+ private final Stack<Expression> _stack = new Stack<Expression>();
+ private LogicalExpression.OP _lastOp = null;
+
+ public ExpressionBuilder() {}
+
+ public ExpressionBuilder withAnd() {
+ _lastOp = LogicalExpression.OP.AND;
+ return this;
+ }
+
+ public ExpressionBuilder withOr() {
+ _lastOp = LogicalExpression.OP.OR;
+ return this;
+ }
+
+ public ExpressionBuilder withTerm(Expression exp) {
+ if (_lastOp != null) {
+ exp = new LogicalExpression(_lastOp, _stack.pop(), exp);
+ _lastOp = null;
+ }
+ _stack.push(exp);
+ return this;
+ }
+
+ public Expression build() {
+ return _stack.pop();
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ */
+/*package*/ class IteratableTypeInfo extends TypeInfo {
+
+ public IteratableTypeInfo(String name, Accessor accessor) {
+ super(name, accessor.getType(), accessor);
+ }
+
+ @Override
+ public Object retrieve(Object target, String[] query, int index) throws QueryException {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("retrieve collection: {}/{} type:{}", index, query.length,
+ target.getClass());
+ }
+ explore();
+ Collection<?> c = (Collection<?>) target;
+ Iterator<?> it = c.iterator();
+ List<Object> objects = new ArrayList<Object>();
+ while (it.hasNext()) {
+ Object item = it.next();
+ for (TypeInfo child : _types.values()) {
+ Object val = child.retrieve(item, query, index);
+ if (val != null) objects.add(val);
+ }
+ }
+ return objects;
+
+ }
+
+ @Override
+ public synchronized void explore() {
+ if (_explored) return;
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("exploring iteratable type: {} gtype: {}", _class,
+ _accessor.getGenericType());
+ }
+ Type t = _accessor.getGenericType();
+ if (t instanceof ParameterizedType) {
+ Type[] pt = ((ParameterizedType) t).getActualTypeArguments();
+ // First type is a child, ignore rest
+ if (pt.length > 0) {
+ _types.put(_name, new TypeInfo(_name, (Class)pt[0], null));
+ }
+ }
+ _explored = true;
+ }
+
+ @Override
+ public TypeInfo getCollectionChild(Class<?> childType) {
+ explore();
+ for (TypeInfo ti : _types.values()) {
+ if (ti.getType().equals(childType)) {
+ return ti;
+ }
+ }
+ return null;
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+/*package*/ class LogicalExpression implements Expression {
+
+ public static enum OP { AND, OR }
+
+ private final OP _op;
+ private final Expression _arg1;
+ private final Expression _arg2;
+
+ public LogicalExpression(OP op, Expression first, Expression second) {
+ _op = op;
+ _arg1 = first;
+ _arg2 = second;
+ }
+
+ public OP getOperator() {
+ return _op;
+ }
+
+ public Expression getFirst() {
+ return _arg1;
+ }
+
+ public Expression getSecond() {
+ return _arg2;
+ }
+
+ @Override
+ public boolean accept(Visitor visitor) throws QueryException {
+ return visitor.visit(this);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(_arg1.toString())
+ .append(_op.toString())
+ .append(_arg2.toString());
+ return sb.toString();
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.util.Collection;
+import java.util.List;
+
+
+/**
+ * Represents a parsed query used in filtering of collections.
+ */
+public interface Query<T> {
+
+ /**
+ * Find items in the given collection and return them as a new list. The
+ * original collection is not changed.
+ *
+ * @param collection to search in.
+ * @return list of items which match the query.
+ * @throws QueryException
+ */
+ public List<T> find(Collection<T> collection) throws QueryException;
+
+ /**
+ * Apply the query on the given collection. Note that this method will modify
+ * the given object by removing any items which don't match the query criteria.
+ * If the collection is 'singleton' or unmodifiable, invocation will result in
+ * an exception.
+ *
+ * @param collection
+ * @return the number matched items
+ * @throws QueryException
+ */
+ public int filter(Collection<T> collection) throws QueryException;
+
+ /**
+ * Search the given root for a child collection and them apply the query on.
+ * Note that this method will modify the given object by removing any items
+ * which don't match the query criteria.
+ *
+ * @param root - top level object to search in
+ * @param childType - the child type which represents the collection.
+ * @return the number of matched items
+ * @throws QueryException
+ */
+ public int filter(T root, Class<?> childType) throws QueryException;
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+/**
+ * Query context
+ */
+public interface QueryContext {
+
+ /**
+ * Create a Query
+ * @param queryString - query string to parse
+ * @param clazz - The class which represents the top level jaxb object
+ * @return a query object
+ * @throws QueryException if the query cannot be parsed.
+ */
+ <T> Query<T> createQuery(String queryString, Class<T> clazz)
+ throws QueryException;
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*package*/ class QueryContextImpl implements QueryContext {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(QueryContext.class);
+
+ @Override
+ public <T> Query<T> createQuery(String queryString, Class<T> type) throws QueryException {
+ if (queryString == null || queryString.trim().length() == 0) return null;
+ try {
+ if (LOGGER.isDebugEnabled()) LOGGER.debug("Processing query: {}", queryString);
+ // FiqlParser is a parser generated by javacc
+ Expression expression = FiqlParser.parse(queryString);
+ if (LOGGER.isDebugEnabled()) LOGGER.debug("Query expression: {}", expression);
+ // create Query and return;
+ return new QueryImpl<T>(type, expression);
+ } catch (Exception ex) {
+ if (LOGGER.isDebugEnabled()) LOGGER.error("Query processing failed = {}",
+ queryString, ex);
+ throw new QueryException("Unable to parse query.", ex);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+import javax.ws.rs.ext.ContextResolver;
+import javax.ws.rs.ext.Provider;
+
+/**
+ * A provider for getting hold of the QueryContext.
+ */
+@Provider
+public class QueryContextProvider implements ContextResolver<QueryContext> {
+
+ // Singleton Query Context instance
+ private static final QueryContext queryContext = new QueryContextImpl();
+
+ @Override
+ public QueryContext getContext(Class<?> type) {
+ return queryContext;
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Signals that an error happened during the parsing or processing of a query.
+ */
+public class QueryException extends WebApplicationException {
+
+ private static final long serialVersionUID = 1L;
+
+ public QueryException(String msg) {
+ super(Response.status(Response.Status.BAD_REQUEST)
+ .entity(msg).type(MediaType.TEXT_PLAIN).build());
+ }
+
+ public QueryException(String msg, Throwable cause) {
+ super(cause, Response.status(Response.Status.BAD_REQUEST)
+ .entity(msg).type(MediaType.TEXT_PLAIN).build());
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.opendaylight.controller.northbound.commons.query.CompareExpression.OP;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+/*package*/ class QueryImpl<T> implements Query<T> {
+ public static final Logger LOGGER = LoggerFactory.getLogger(QueryImpl.class);
+ private static final boolean ALLOW_OBJECT_STRING_COMPARE = true;
+
+ private final Expression expression;
+ private final TypeInfo rootType ;
+ /**
+ * Set the expression and cache
+ * @param type
+ * @param expression
+ */
+ public QueryImpl(Class<T> type, Expression expression) {
+ this.expression = expression;
+ this.rootType = TypeInfo.createRoot(null, type);
+ }
+
+ @Override
+ public List<T> find(Collection<T> collection) throws QueryException {
+ // new arraylist for result
+ List<T> result = new ArrayList<T>();
+ for (T item : collection) {
+ if (match(item, rootType)) {
+ result.add(item);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public int filter(Collection<T> collection) throws QueryException {
+ // find items
+ List<T> matched = new ArrayList<T>();
+ for (T item : collection) {
+ if (match(item, rootType)) {
+ matched.add(item);
+ }
+ }
+ collection.clear();
+ collection.addAll(matched);
+ return matched.size();
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Override
+ public int filter(T rootObject, Class<?> childClass) throws QueryException {
+ // retrieve underlying collection
+ TypeInfo childType = rootType.getCollectionChild(childClass);
+ if (childType == null || !(childType instanceof IteratableTypeInfo)) {
+ return 0;
+ }
+ Collection collection = (Collection)
+ childType.getAccessor().getValue(rootObject);
+ // get the child type of the collection type
+ TypeInfo ti = childType.getCollectionChild(childClass);
+ List matched = new ArrayList();
+ for (Object item : collection) {
+ if (match(item, ti)) {
+ matched.add(item);
+ }
+ }
+ collection.clear();
+ collection.addAll(matched);
+ return matched.size();
+ }
+
+ private boolean match(final Object object, final TypeInfo rootType)
+ throws QueryException {
+ return expression.accept(new Visitor () {
+ @Override
+ public boolean visit(LogicalExpression le) throws QueryException {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Logical exp {}|{}|{}", le.getOperator(), le.getFirst(),
+ le.getSecond());
+ }
+ return (le.getOperator() == LogicalExpression.OP.AND) ?
+ le.getFirst().accept(this) && le.getSecond().accept(this) :
+ le.getFirst().accept(this) || le.getSecond().accept(this);
+ }
+
+ @Override
+ public boolean visit(CompareExpression ce) throws QueryException {
+ boolean result = visitInternal(ce);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("=== Compare exp {}|{}|{} == {}", ce.getOperator(),
+ ce.getSelector(), ce.getArgument(), result);
+ }
+ return result;
+ }
+
+ public boolean visitInternal(CompareExpression ce) throws QueryException {
+ String[] selector = ce.getSelector().split("\\.");
+ if (!rootType.getName().equals(selector[0])) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Root name mismatch: {} != {}",
+ rootType.getName(), selector[0]);
+ }
+ return false;
+ }
+ Object value = rootType.retrieve(object, selector, 1);
+ if(value == null){ // nothing to compare against
+ return false;
+ }
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Comparing [{}] {} [{}]", ce.getArgument(),
+ ce.getOperator(), value.toString());
+ }
+ if (value instanceof Collection) {
+ Collection<?> collection = (Collection<?>) value;
+ if(collection.size() == 0 && ce.getOperator() == OP.NE) {
+ // collection doesn't contain query string
+ return true;
+ }
+ // If there are elements iterate
+ Iterator<?> it = collection.iterator();
+ OP operator = ce.getOperator();
+ if (operator == OP.NE) {
+ // negate the operator
+ operator = OP.EQ;
+ }
+ while (it.hasNext()) {
+ Object item = it.next();
+ if (compare(parse(ce.getArgument(), item), item, operator)) {
+ // if match found check the operator and return false for NE
+ return (ce.getOperator() != OP.NE);
+ }
+ }
+ // return true for NE and false for rest
+ return (ce.getOperator() == OP.NE);
+ } else {
+ return compare(parse(ce.getArgument(), value), value,
+ ce.getOperator());
+ }
+ }
+
+ });
+ }
+
+ private boolean compare(Object valueToMatch, Object actualValue, OP operator) {
+ if (valueToMatch == null || actualValue == null) return false;
+ if (ALLOW_OBJECT_STRING_COMPARE && (valueToMatch instanceof String)
+ && !(actualValue instanceof String)) {
+ actualValue = actualValue.toString();
+ }
+
+ int compareResult = -1;
+ if (valueToMatch instanceof Comparable) {
+ compareResult = ((Comparable)actualValue).compareTo(valueToMatch);
+ } else {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Not a comparable type: {} {}",
+ valueToMatch.getClass().getName(),
+ actualValue.getClass().getName());
+ }
+ return false;
+ }
+ switch(operator) {
+ case EQ :
+ return compareResult == 0;
+ case RE :
+ // Regex match,
+ if (valueToMatch instanceof String) {
+ return Pattern.matches((String)valueToMatch, actualValue.toString());
+ } else {
+ return compareResult == 0;
+ }
+ case NE:
+ return compareResult != 0;
+ case GT :
+ return compareResult > 0;
+ case GE :
+ return compareResult >= 0;
+ case LT :
+ return compareResult < 0;
+ case LE :
+ return compareResult <= 0;
+ default:
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Unrecognized comparator - {}", operator);
+ }
+ return false;
+ }
+ }
+ private Object parse(String arg, Object value) {
+ if (value == null) return null;
+
+ try {
+ if (value instanceof String) {
+ return arg;
+ } else if (value instanceof Byte) {
+ return Byte.decode(arg);
+ } else if (value instanceof Double) {
+ return Double.parseDouble(arg);
+ } else if (value instanceof Float) {
+ return Float.parseFloat(arg);
+ } else if (value instanceof Integer) {
+ return Integer.parseInt(arg);
+ } else if (value instanceof Long) {
+ return Long.parseLong(arg);
+ } else if (value instanceof Short) {
+ return Short.parseShort(arg);
+ }
+ } catch (NumberFormatException ignore) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Exception parsing {}", arg, value);
+ }
+ }
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Using string comparision for type - {}",
+ value.getClass().getName());
+ }
+ // Not a number or string. Convert to a string and compare as last resort
+ return ALLOW_OBJECT_STRING_COMPARE ? arg.toString() : null;
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper over a JAXB type to allow traversal of the object graph and
+ * search for specific values in the object tree.
+ */
+/*package*/ class TypeInfo {
+
+ public static final Logger LOGGER = LoggerFactory.getLogger(TypeInfo.class);
+ public static final String DEFAULT_NAME = "##default";
+
+ protected final String _name; // the jaxb name
+ protected Class<?> _class; // jaxb type class
+ protected final XmlAccessType _accessType; // jaxb access type
+ protected final Accessor _accessor; // accessor to access object value
+ protected Map<String,TypeInfo> _types = new HashMap<String,TypeInfo>();
+ protected volatile boolean _explored = false;
+ /**
+ * Create a TypeInfo with a name and a class type. The accessor will be null
+ * for a root node.
+ */
+ protected TypeInfo(String name, Class<?> clz, Accessor accessor) {
+ _name = name;
+ _class = clz;
+ _accessor = accessor;
+ XmlAccessorType accessorType = null;
+ if(clz == null) {
+ throw new NullPointerException("Type class can not be null");
+ }
+ accessorType = clz.getAnnotation(XmlAccessorType.class);
+ _accessType = (accessorType == null ?
+ XmlAccessType.PUBLIC_MEMBER : accessorType.value());
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Created type info name:{} type:{}", _name, _class);
+ }
+ }
+
+ /**
+ * @return the Accessor to access the value
+ */
+ public final Accessor getAccessor() {
+ return _accessor;
+ }
+
+ /**
+ * @return get the child by name
+ */
+ public final TypeInfo getChild(String name) {
+ return _types.get(name);
+ }
+
+ public TypeInfo getCollectionChild(Class<?> childType) {
+ explore();
+ for (TypeInfo ti : _types.values()) {
+ if (Collection.class.isAssignableFrom(ti.getType())) {
+ ParameterizedType p = (ParameterizedType)
+ ti.getAccessor().getGenericType();
+ Type[] pts = p.getActualTypeArguments();
+ if (pts.length == 1 && pts[0].equals(childType)) {
+ return ti;
+ }
+ }
+ }
+ return null;
+ }
+
+ public Class getType() {
+ return _class;
+ }
+
+ public String getName() {
+ return _name;
+ }
+
+ /**
+ * @return the object value by a selector query
+ */
+ public Object retrieve(Object target, String[] query, int index)
+ throws QueryException {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("retrieve: {}/{} type:{}", index, query.length, target.getClass());
+ }
+ if (index >= query.length) return null;
+ explore();
+ if (!target.getClass().equals(_class)) {
+ if (_class.isAssignableFrom(target.getClass())) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Handling subtype {} of {} ", target.getClass(), _class);
+ }
+ // explore the subtype
+ TypeInfo subTypeInfo = new TypeInfo(getRootName(target.getClass()),
+ target.getClass(), _accessor);
+ return subTypeInfo.retrieve(target, query, index);
+ } else {
+ // non compatible object; bail out
+ return null;
+ }
+ }
+ TypeInfo child = getChild(query[index]);
+ if (child == null) return null;
+ target = child.getAccessor().getValue(target);
+ if (index+1 == query.length) {
+ // match found
+ return target;
+ }
+ return child.retrieve(target, query, index+1);
+ }
+
+ /**
+ * Explore the type info for children.
+ */
+ public synchronized void explore() {
+ if (_explored) return;
+ for (Class<?> c = _class; c != null; c = c.getSuperclass()) {
+ if (c.equals(Object.class)) break;
+ // Currently only fields and methods annotated with JAXB annotations are
+ // considered as valid for search purposes.
+ //check methods first
+ for (Method m : c.getDeclaredMethods()) {
+ String tn = getTypeName(m, _accessType);
+ if (tn != null) {
+ if (LOGGER.isDebugEnabled()) LOGGER.debug(
+ "exploring type: {} name: {} method: {}",
+ _class.getSimpleName(), tn, m);
+ _types.put(tn, createTypeInfo(tn, new Accessor(m)));
+ }
+ }
+ for (Field f : c.getDeclaredFields()) {
+ String tn = getTypeName(f, _accessType);
+ if (tn != null) {
+ if (LOGGER.isDebugEnabled()) LOGGER.debug(
+ "exploring type: {} name: {} field: {}",
+ _class.getSimpleName(), tn, f);
+ _types.put(tn, createTypeInfo(tn, new Accessor(f)));
+ }
+ }
+ }
+ _explored = true;
+ }
+
+ public static final String getTypeName(Field f, XmlAccessType access) {
+ // ignore static, transient and xmltransient fields
+ if (Modifier.isTransient(f.getModifiers()) ||
+ Modifier.isStatic(f.getModifiers()) ||
+ f.getAnnotation(XmlTransient.class) != null ) {
+ return null;
+ }
+ // try to read annotation
+ String name = getTypeName(f.getAnnotations(), f.getName());
+ if (name != null) return name;
+ // no annotation present check accesstype
+ else if (access == XmlAccessType.NONE) { // none return name
+ return name;
+ } else if (access == XmlAccessType.FIELD) {
+ // return field name if no annotation present
+ return f.getName();
+ } else if (access == XmlAccessType.PUBLIC_MEMBER
+ && Modifier.isPublic(f.getModifiers())) { // look for public access
+ return f.getName();
+ }
+ // return annotated name ( if any )
+ return null;
+ }
+
+ public static final String getTypeName(Method m, XmlAccessType access) {
+ // ignore static, transient and xmltransient fields
+ if (Modifier.isStatic(m.getModifiers()) ||
+ m.getAnnotation(XmlTransient.class) != null ) {
+ return null;
+ }
+ // try to read annotation
+ String name = getTypeName(m.getAnnotations(), m.getName());
+ if (name != null) return name;
+ //check acces type
+ else if (access == XmlAccessType.NONE) { // none return name
+ return name;
+ } else if (access == XmlAccessType.PROPERTY) {
+ // return bean property name if no annotation present
+ return getBeanPropertyName(m);
+ } else if (access == XmlAccessType.PUBLIC_MEMBER
+ && Modifier.isPublic(m.getModifiers())) { // look for public access
+ return getBeanPropertyName(m);
+ }
+ return null;
+ }
+
+ private static String getBeanPropertyName(Method m){
+ try
+ {
+ Class<?> clazz=m.getDeclaringClass();
+ BeanInfo info = Introspector.getBeanInfo(clazz);
+ PropertyDescriptor[] props = info.getPropertyDescriptors();
+ for (PropertyDescriptor pd : props)
+ {
+ if (m.equals(pd.getReadMethod())) return pd.getName();
+ }
+ }
+ catch (IntrospectionException e)
+ {
+ LOGGER.error("Could not read bean property name for method = {}",
+ m.getName(), e);
+ }
+ return null;
+ }
+
+ public static TypeInfo createRoot(String name, Class<?> clz) {
+ // root is always a composite type
+ // FIXME assert its a JAXB type
+ XmlRootElement root = clz.getAnnotation(XmlRootElement.class);
+ if (root == null) throw new IllegalArgumentException("Not a JAXB type: " + clz);
+ if (name == null) name = getRootName(clz);
+ return new TypeInfo(name, clz, null);
+ }
+
+ public static TypeInfo createTypeInfo(String name, Accessor accessor) {
+ if (accessor.getAccessibleObject().getAnnotation(XmlElementWrapper.class) != null) {
+ //XmlElementWrapperType
+ return new WrapperTypeInfo(name, accessor);
+ } else if (Collection.class.isAssignableFrom(accessor.getType())) {
+ // collection type
+ return new IteratableTypeInfo(name, accessor);
+ }
+ return new TypeInfo(name, accessor.getType(), accessor);
+ }
+
+ public static String getRootName(Class<?> cls) {
+ XmlRootElement root = cls.getAnnotation(XmlRootElement.class);
+ if (root == null) return null;
+ String rootName = root.name();
+ if (DEFAULT_NAME.equals(rootName)) {
+ String clsName = cls.getSimpleName();
+ rootName = Character.toLowerCase(clsName.charAt(0)) + clsName.substring(1);
+ }
+ return rootName;
+ }
+
+ protected static String getTypeName(Annotation[] annotations, String dflt) {
+ String name = null;
+ for (Annotation a : annotations) {
+ if (a.annotationType() == XmlAttribute.class) {
+ name = ((XmlAttribute)a).name();
+ } else if (a.annotationType() == XmlElement.class) {
+ name = ((XmlElement)a).name();
+ } else if (a.annotationType() == XmlElementRef.class) {
+ name = ((XmlElementRef)a).name();
+ } else if (a.annotationType() == XmlElementWrapper.class) {
+ name = ((XmlElementWrapper)a).name();
+ // break the loop as we don't want name to be overwritten by XmlElement
+ break;
+ } else if (a.annotationType() == XmlType.class) {
+ name = ((XmlType)a).name();
+ } else if (a.annotationType() == XmlTransient.class) {
+ // transient type
+ return null;
+ }
+ }
+ if (DEFAULT_NAME.equals(name)) return dflt;
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return " TypeInfo [_name=" + _name + ", _class=" + _class
+ + ", _accessType=" + _accessType + ", _accessor=" + _accessor
+ + ", _types=" + _types + ", _explored=" + _explored + " ] ";
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+/*package*/ interface Visitor {
+
+ boolean visit(LogicalExpression exp) throws QueryException;
+
+ boolean visit(CompareExpression exp) throws QueryException;
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import javax.xml.bind.annotation.XmlElement;
+
+public class WrapperTypeInfo extends TypeInfo {
+
+ protected WrapperTypeInfo(String name, Accessor accessor) {
+ super(name, accessor.getType(), accessor);
+ }
+
+ @Override
+ public Object retrieve(Object target, String[] query, int index) throws QueryException {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("retrieve collection: {}/{}", index, query.length);
+ }
+ if (index >= query.length) return null;
+ explore();
+ TypeInfo child = getChild(query[index]);
+ if (child == null) return null;
+ if (query.length == index+1) { // skipping this node
+ return target;
+ }else { // if list of list go to next node to get value
+ return child.retrieve(target, query, index+1);
+ }
+ }
+
+ @Override
+ public synchronized void explore() {
+ if (_explored) return;
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("exploring wrapper type: {} gtype: {}", _class,
+ _accessor.getGenericType());
+ }
+ String tn = null;
+ AccessibleObject accessibleObject = _accessor.getAccessibleObject();
+ XmlElement xmlElement = accessibleObject.getAnnotation(XmlElement.class);
+ if (accessibleObject instanceof Field) {
+ Field f = (Field) accessibleObject;
+ tn = DEFAULT_NAME.equals(xmlElement.name())?f.getName() : xmlElement.name();
+ }else if (accessibleObject instanceof Method) {
+ Method m = (Method) accessibleObject;
+ tn = DEFAULT_NAME.equals(xmlElement.name())?m.getName() : xmlElement.name();
+ }
+ this._types.put(tn, new IteratableTypeInfo(tn, this._accessor));
+ _explored = true;
+ }
+
+}
--- /dev/null
+
+options {
+ STATIC = false;
+}
+
+PARSER_BEGIN(FiqlParser)
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.util.regex.*;
+
+/*package*/ class FiqlParser {
+ public static Expression parse(String query) throws ParseException {
+ FiqlParser parser = new FiqlParser(new java.io.StringReader(query));
+ return parser.START();
+ }
+}
+
+PARSER_END(FiqlParser)
+
+/* whitespace */
+SKIP :
+{
+ " " | "\t"
+}
+
+TOKEN : {
+ <#ALPHA : ( ["a"-"z", "A"-"Z", "0"-"9"] )+ >
+}
+
+TOKEN : {
+ <NUM : ("+"|"-")?(["0"-"9"])+"."(["0"-"9"])* >
+ |
+ <LPAREN : "(" >
+ |
+ <RPAREN : ")" >
+}
+
+/* comparision ops */
+TOKEN : {
+ <RE : ("=") >
+ |
+ <EQ : ("==" | "=eq=") >
+ |
+ <NE : ("!=" | "=ne=") >
+ |
+ <LT : ("=lt=" | "<") >
+ |
+ <LE : ("=le=" | "<=") >
+ |
+ <GT : ("=gt=" | ">") >
+ |
+ <GE : ("=ge=" | ">=") >
+}
+
+/* ops */
+TOKEN : {
+ <AND : (";" | "and") >
+ |
+ <OR : ("," | "or") >
+}
+
+/* strings */
+TOKEN : {
+ <STRING : ( ~["\"", "'", "(", ")", ";", ",", "=", "<", ">", "!", "~", " "] )+ >
+ |
+ <DQ_STRING : ( "\"" ( ~["\""] )* "\"" ) >
+ |
+ <SQ_STRING : ( "'" ( ~["'"] )* "'" ) >
+}
+
+/* Root production */
+Expression START() :
+{
+ Expression e;
+}
+{
+ e = EXPR()
+ <EOF>
+ {
+ return e;
+ }
+}
+
+Expression EXPR():
+{
+ ExpressionBuilder builder = new ExpressionBuilder();
+ Expression t;
+}
+{
+ t = TERM() { builder.withTerm(t); }
+ (
+ (<AND> t = TERM()) { builder.withAnd().withTerm(t); }
+ |
+ (<OR> t = TERM() ) { builder.withOr().withTerm(t); }
+ )*
+ {
+ return builder.build();
+ }
+}
+
+Expression TERM() :
+{
+ Token selector, arg;
+ Expression exp;
+ CompareExpression.OP op;
+}
+{
+ selector = <STRING>
+ (
+ ( <EQ> {op=CompareExpression.OP.EQ;} |
+ <RE> {op=CompareExpression.OP.RE;} |
+ <NE> {op=CompareExpression.OP.NE;} |
+ <LT> {op=CompareExpression.OP.LT;} |
+ <LE> {op=CompareExpression.OP.LE;} |
+ <GT> {op=CompareExpression.OP.GT;} |
+ <GE> {op=CompareExpression.OP.GE;}
+ )
+ ( arg = <STRING> | arg = <DQ_STRING> | arg = <SQ_STRING> | arg = <NUM>)
+ ) { return new CompareExpression(op, selector.image, arg.image); }
+ |
+ (
+ <LPAREN> exp = EXPR() <RPAREN>
+ ) { return exp; }
+}
--- /dev/null
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.opendaylight.controller.northbound.commons.types.StringList;
+
+/**
+ */
+
+@XmlRootElement(name="book")
+public class BookBean {
+
+ @XmlElement(name="name")
+ private String _name; // simple type
+
+ private String _isbn; // method annotation
+
+ @XmlElement(name="author")
+ private PersonBean _author; // composite type
+
+ @XmlElementWrapper//for XMLWrapper iterative composite types
+ @XmlElement(name="review")
+ private final List<ReviewBean> reviews = new ArrayList<ReviewBean>();
+
+ @XmlElement
+ private List<String> soldBy; //Iterative Type
+
+ @XmlElementWrapper(name="test")
+ @XmlElement
+ private final List<StringList> testList = new ArrayList<StringList>(); //XMLWrapper list of list
+
+ @XmlElementWrapper(name="parent")
+ @XmlElement(name="child")
+ private final List<WrapperList> wrapperList = new ArrayList<WrapperList>(); // XMLWrapper of XMLWrapper
+
+ public BookBean(){}
+
+ public BookBean(String name, String id, PersonBean person) {
+ _name = name;
+ _isbn = id;
+ _author = person;
+ soldBy = new ArrayList<String>();
+ }
+
+ public BookBean addReview(ReviewBean review) {
+ reviews.add(review);
+ return this;
+ }
+
+ public void setSellerInfo(List<String> sellers) {
+ soldBy = new ArrayList<String>(sellers);
+ }
+
+ public void addWrapperList(WrapperList list){
+ wrapperList.add(list);
+ }
+
+ public void addToTestList(StringList testList){
+ this.testList.add(testList);
+ }
+ public String getName() {
+ return "1"+_name;
+ }
+
+ @XmlElement(name="isbn")
+ public String get_isbn() {
+ return "pre"+_isbn;
+ }
+
+ public PersonBean getauthor() {
+ return _author;
+ }
+
+ @Override
+ public String toString() {
+ return "BookBean [_name=" + _name + ", _isbn=" + _isbn + ", _author="
+ + _author + ", reviews=" + reviews + ", soldBy=" + soldBy
+ + ", testList=" + testList + ", wrapperList=" + wrapperList + "]";
+ }
+
+}
+
+class WrapperList {
+ @XmlElementWrapper(name="items")
+ @XmlElement
+ public List<String> item = new ArrayList<String>();
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.northbound.commons.query.CompareExpression.OP;
+
+public class ExpresssionTest {
+
+ private static final List<PersonBean> people = new ArrayList<PersonBean>();
+ private static final ArrayList<BookBean> books = new ArrayList<BookBean>();
+
+ public static void p(String msg) {
+ //System.out.println("======= " + msg);
+ }
+
+ public static boolean matches(Expression exp, final PersonBean person) throws Exception {
+
+ boolean result = exp.accept(new Visitor() {
+ @Override
+ public boolean visit(LogicalExpression le) throws QueryException {
+ p("=== LE " + le.getOperator() + "|" + le.getFirst() + "|" + le.getSecond());
+ return (le.getOperator() == LogicalExpression.OP.AND) ?
+ le.getFirst().accept(this) && le.getSecond().accept(this) :
+ le.getFirst().accept(this) || le.getSecond().accept(this);
+ }
+
+ @Override
+ public boolean visit(CompareExpression ce) {
+ p("=== CE " + ce.getOperator() + "|" + ce.getSelector() + "|" + ce.getArgument());
+ if (person == null) {
+ return false;
+ }
+ try {
+ // check if the selector matches any of the fields
+ Field field = PersonBean.class.getDeclaredField(ce.getSelector());
+ if (field == null) {
+ p("No field found by name : " + ce.getSelector());
+ return false;
+ }
+ Object value = field.get(person);
+ if (value instanceof String) {
+ p("Comparing [" + ce.getArgument() + "] "+ ce.getOperator() + " [" + value.toString() + "]");
+ if (ce.getOperator() == OP.EQ) {
+ return ce.getArgument().equals(value.toString());
+ } else if (ce.getOperator() == OP.RE) {
+ return Pattern.matches(ce.getArgument(), value.toString());
+ } else if (ce.getOperator() == OP.NE) {
+ return !ce.getArgument().equals(value.toString());
+ } else {
+ p("Comparator : " + ce.getOperator() + " cannot apply to Strings");
+ return false;
+ }
+ } else {
+ // assume its a #
+ int valToMatch = Integer.parseInt(ce.getArgument());
+ int actualValue = (Integer)value;
+ p("Comparing: " + valToMatch + " " + ce.getOperator() + " " + actualValue);
+ switch(ce.getOperator()) {
+ case EQ :
+ case RE :
+ return actualValue == valToMatch;
+ case NE :
+ return actualValue != valToMatch;
+ case GT :
+ return actualValue > valToMatch;
+ case GE :
+ return actualValue >= valToMatch;
+ case LT :
+ return actualValue < valToMatch;
+ case LE :
+ return actualValue <= valToMatch;
+ default:
+ p("Unrecognized compare operator: " + ce.getOperator());
+ return false;
+ }
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ });
+ p("RESULT: " + result);
+ return result;
+ }
+
+ @BeforeClass
+ public static void load() {
+ System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug");
+
+ people.add(new PersonBean(100, "John", "Doe", "San Jose"));
+ people.add(new PersonBean(200, "Foo", "Bar", "San Francisco"));
+ people.add(new PersonBean(300, "A", "B", "San Francisco"));
+ people.add(new PersonBean(400, "X", "Y", "New York"));
+
+ books.add(new BookBean("Book1", "A001", people.get(0)));
+ books.add(new BookBean("Book2", "A002", people.get(1)));
+ books.add(new BookBean("Book3", "A003", people.get(2)));
+
+ ReviewBean review1 = new ReviewBean("cool", people.get(2));
+ ReviewBean review2 = new ReviewBean("kewl", people.get(3));
+ ReviewBean review3 = new ReviewBean("+++", people.get(0));
+ ReviewBean review4 = new ReviewBean("---", people.get(1));
+
+ books.get(0).addReview(review1).addReview(review2).addReview(review3).addReview(review4);
+ books.get(1).addReview(review1).addReview(review2).addReview(review3).addReview(review4);
+ books.get(2).addReview(review1).addReview(review2).addReview(review3).addReview(review4);
+ }
+
+ @Test
+ public void testCXFQueries() throws Exception {
+ // following queries copied from apache cxf
+ Assert.assertFalse(matches(parseQuery("id=gt=100;name=Fred"), null));
+ Assert.assertFalse(matches(parseQuery("id=gt=100;name==Fred"), null));
+ Assert.assertFalse(matches(parseQuery("id=lt=123"), null));
+ Assert.assertFalse(matches(parseQuery("date=le=2010-03-11"), null));
+ Assert.assertFalse(matches(parseQuery("time=le=2010-03-11T18:00:00"), null));
+ Assert.assertFalse(matches(parseQuery("name==CXF;version=ge=2.2"), null));
+ Assert.assertFalse(matches(parseQuery("(age=lt=25,age=gt=35);city==London"), null));
+ Assert.assertFalse(matches(parseQuery("date=lt=2000-01-01;date=gt=1999-01-01;(sub==math,sub==physics)"), null));
+ }
+
+ public Expression parseQuery(String query) throws Exception {
+ p("PARSING query: " + query);
+ // FiqlParser is a parser generated by javacc
+ Expression exp = FiqlParser.parse(query);
+ p(exp.toString());
+ return exp;
+ }
+
+ public int find(String query) throws Exception {
+ int found = 0;
+ Expression exp = parseQuery(query);
+ TypeInfo.createRoot("person", PersonBean.class);
+ for (PersonBean person : people) {
+ if (matches(exp, person)) found++;
+ }
+ return found;
+ }
+
+ @Test
+ public void testPeopleQueries() throws Exception {
+ Assert.assertTrue(find("id==200") == 1);
+ Assert.assertTrue(find("id!=100;(city='San.*')") == 2);
+ Assert.assertTrue(find("id>200;(city='San.*')") == 1);
+ Assert.assertTrue(find("city='San.*'") == 3);
+ }
+
+ @Test
+ public void testTypeTree() throws Exception {
+ TypeInfo bookType = TypeInfo.createRoot("book", BookBean.class);
+ Assert.assertEquals("John", bookType.retrieve(books.get(0),
+ "book.author.firstName".split("\\."), 1));
+ Object result = bookType.retrieve(books.get(0),
+ "book.reviews.review.comment".split("\\."), 1);
+ Assert.assertTrue( result instanceof List);
+ List<Object> commentList = (List<Object>) result;
+ Assert.assertTrue(commentList.contains("cool"));
+ }
+
+ @Test
+ public void testQueryAPI() throws Exception {
+ QueryContext qc = new QueryContextImpl();
+
+ // find all books written by author with firstName "John"
+ Query q1 = qc.createQuery("book.author.firstName==John", BookBean.class);
+ Collection<BookBean> r1 = q1.find(books);
+ p("Filtered books: " + r1.size());
+ Assert.assertEquals(1, r1.size());
+
+ // find all books reviewed by people in a city "San*"
+ Query q2 = qc.createQuery("book.reviews.review.reviewer.city=San.*", BookBean.class);
+ Collection<BookBean> r2 = q2.find(books);
+
+ p("Filtered books: " + r2.size());
+ Assert.assertEquals(3, r2.size());
+
+ // find all books reviewed by people in a city "San*"
+ Query q3 = qc.createQuery("book==foo", BookBean.class);
+ Collection<BookBean> r3 = q3.find(books);
+ Assert.assertEquals(0, r3.size());
+ }
+
+ @Test
+ public void testFilter() throws Exception {
+ Library library = new Library((List)books.clone());
+ QueryContext qc = new QueryContextImpl();
+ // find all books written by author with firstName "John"
+ Query q1 = qc.createQuery("book.author.firstName==John", Library.class);
+ int sizeBefore = library.getList().size();
+ System.out.println(q1.filter(library, BookBean.class));
+ Assert.assertEquals(1, library.getList().size());
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name="library")
+public class Library {
+
+ @XmlElement(name="book")
+ private final List<BookBean> _list;
+
+ public Library(List<BookBean> list) {
+ _list = list;
+ }
+
+ public List<BookBean> getList() {
+ return _list;
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name="person")
+
+public class PersonBean {
+
+ @XmlElement
+ public String firstName;
+ @XmlElement
+ public String lastName;
+ @XmlElement
+ public String city;
+ @XmlElement
+ public int id;
+
+ @XmlElementWrapper(name="emails") // ElementWrapper iteratable type
+ @XmlElement
+ public List<String> email;
+
+ public PersonBean(){}
+ public PersonBean(int n, String f, String l, String c) {
+ firstName = f;
+ lastName = l;
+ city = c;
+ id = n;
+ }
+
+ public void setEmail(List<String> emails){
+ email = emails;
+ }
+ @Override
+ public String toString() {
+ return "PersonBean [firstName=" + firstName + ", lastName=" + lastName
+ + ", city=" + city + ", id=" + id + "]";
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.northbound.commons.types.StringList;
+
+public class QueryContextTest {
+
+ protected static final List<PersonBean> people = new ArrayList<PersonBean>();
+ protected static final List<BookBean> books = new ArrayList<BookBean>();
+
+ public static void p(String msg) {
+ System.out.println("=== " + msg);
+ }
+
+ @BeforeClass
+ public static void load() {
+ people.add(new PersonBean(100, "John", "Doe", "San Jose"));
+ people.add(new PersonBean(200, "Foo", "Bar", "San Francisco"));
+ people.add(new PersonBean(300, "A", "B", "San Francisco"));
+ people.add(new PersonBean(400, "X", "Y", "New York"));
+
+ books.add(new BookBean("Book1", "A001", people.get(0)));
+ books.add(new BookBean("Book2", "A002", people.get(1)));
+ books.add(new BookBean("Book3", "A003", people.get(2)));
+
+ ReviewBean review1 = new ReviewBean("cool", people.get(2));
+ ReviewBean review2 = new ReviewBean("kewl", people.get(3));
+
+ books.get(0).addReview(review1).addReview(review2);
+ books.get(1).addReview(review1);
+ books.get(2).addReview(review2).addReview(review1);
+
+ }
+
+ @Test
+ public void testQueryContext() {
+ QueryContext queryContext = new QueryContextImpl();
+ Assert.assertNotNull(queryContext);
+ }
+
+ @Test
+ public void testSimpleQuery() throws QueryException {
+ QueryContext queryContext = new QueryContextImpl();
+ Query<PersonBean> query = queryContext.createQuery(
+ "person.id==200", PersonBean.class);
+ Assert.assertNotNull(query);
+
+ List<PersonBean> found = query.find(people);
+ Assert.assertNotNull(found);
+ Assert.assertTrue(found.size() == 1);
+ Assert.assertEquals("Foo", found.get(0).firstName);
+ }
+
+ @Test
+ public void testAndQuery() throws QueryException {
+ QueryContext queryContext = new QueryContextImpl();
+ Query<PersonBean> query = queryContext.createQuery(
+ "person.id!=200;(person.city='San.*')", PersonBean.class);
+ Assert.assertNotNull(query);
+
+ List<PersonBean> found = query.find(people);
+ Assert.assertNotNull(found);
+ Assert.assertTrue(found.size() == 2);
+ Assert.assertEquals("John", found.get(0).firstName);
+ Assert.assertEquals("A", found.get(1).firstName);
+ }
+
+ @Test
+ public void testOrQuery() throws QueryException {
+ QueryContext queryContext = new QueryContextImpl();
+ Query<PersonBean> query = queryContext.createQuery(
+ "person.id==200,(person.city='San.*')", PersonBean.class);
+ Assert.assertNotNull(query);
+
+ List<PersonBean> found = query.find(people);
+ Assert.assertNotNull(found);
+ Assert.assertTrue(found.size() == 3);
+ Assert.assertEquals("John", found.get(0).firstName);
+ Assert.assertEquals("Foo", found.get(1).firstName);
+ Assert.assertEquals("A", found.get(2).firstName);
+ }
+
+ @Test
+ public void testXmlElementWrapper() throws QueryException {
+ List<String> emails = new ArrayList<String>();
+ emails.add("john@cisco.com");
+ emails.add("john@gmail.com");
+ people.get(0).setEmail(emails);
+
+ p(toXml(people.get(0)));
+ QueryContext queryContext = new QueryContextImpl();
+ Query<PersonBean> query = queryContext.createQuery(
+ "person.emails.email==john@cisco.com", PersonBean.class);
+ Assert.assertNotNull(query);
+
+ List<PersonBean> found = query.find(people);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1,found.size());
+ Assert.assertEquals("John", found.get(0).firstName);
+ }
+
+ @Test
+ public void testXmlWrapperOfWrapper() throws QueryException{
+ WrapperList wrapper = new WrapperList();
+ wrapper.item.add("Test1");
+ wrapper.item.add("Test2");
+
+ books.get(0).addWrapperList(wrapper);
+ books.get(1).addWrapperList(wrapper);
+
+ System.out.println(toXml(books.get(0)));
+ QueryContext queryContext = new QueryContextImpl();
+ Query<BookBean> query = queryContext.createQuery(
+ "book.parent.child.items.item==Test1", BookBean.class);
+ Assert.assertNotNull(query);
+ }
+
+ @Test
+ public void testXmlElementWrapperListofList() throws QueryException {
+ // create Stringlist
+ List<String> testList = new ArrayList<String>();
+ testList.add("A");
+ testList.add("B");
+ StringList itemList = new StringList(testList);
+ books.get(0).addToTestList(itemList);
+
+ System.out.println(toXml(books.get(0)));
+ QueryContext queryContext = new QueryContextImpl();
+ Query<BookBean> query = queryContext.createQuery(
+ "book.test.testList.item==A", BookBean.class);
+ Assert.assertNotNull(query);
+ }
+
+ @Test
+ public void testPrimitiveIteratableTypes() throws QueryException {
+ // Load data for this test
+ List<String> sellers = new ArrayList<String>();
+ sellers.add("Amazon");
+
+ books.get(0).setSellerInfo(sellers);
+ sellers.add("Barners & Nobles");
+ books.get(1).setSellerInfo(sellers);
+ sellers.add("Borders");
+ sellers.remove("Amazon");
+ sellers.add("BookShop");
+ books.get(2).setSellerInfo(sellers);
+
+ System.out.println(toXml(books.get(0)));
+
+ QueryContext queryContext = new QueryContextImpl();
+ Query<BookBean> query = queryContext.createQuery(
+ "book.soldBy==Amazon", BookBean.class);
+ Assert.assertNotNull(query);
+
+ List<BookBean> found = query.find(books);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(2,found.size());
+ Assert.assertEquals("John", found.get(0).getauthor().firstName);
+
+ query = queryContext.createQuery(
+ "book.soldBy!=Amazon", BookBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(books);
+ System.out.println("books" +found);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1,found.size());
+ Assert.assertEquals("A", found.get(0).getauthor().firstName);
+ }
+
+ @Test
+ public void testCompositeIteratableTypes() throws QueryException {
+ QueryContext queryContext = new QueryContextImpl();
+ Query<BookBean> query = queryContext.createQuery("book.reviews.review.reviewer.firstName==X",
+ BookBean.class);
+ Assert.assertNotNull(query);
+
+ List<BookBean> found = query.find(books);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(2, found.size());
+ Assert.assertEquals("John", found.get(0).getauthor().firstName);
+
+ query = queryContext.createQuery("book.reviews.review.comment==kewl",
+ BookBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(books);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(2, found.size());
+ p("Book 0" + found.get(0));
+ Assert.assertEquals("John", found.get(0).getauthor().firstName);
+
+ query = queryContext.createQuery("book.reviews.review.reviewer.id>300",
+ BookBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(books);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(2, found.size());
+ p("Book 0" + found.get(0));
+ Assert.assertEquals("John", found.get(0).getauthor().firstName);
+
+ query = queryContext.createQuery("book.reviews.review.reviewer.firstName!=X",
+ BookBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(books);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1, found.size());
+ p("Book 0" + found.get(0));
+ Assert.assertEquals("Foo", found.get(0).getauthor().firstName);
+ }
+
+ @Test
+ public void testXMLAccessorType() {
+ //Assert.fail("implement");
+ }
+
+ @Test
+ public void testMethodAnnotation() throws QueryException {
+ System.out.println(toXml(books.get(0)));
+ QueryContext queryContext = new QueryContextImpl();
+ Query<BookBean> query = queryContext.createQuery(
+ "book.isbn==preA003", BookBean.class);
+ Assert.assertNotNull(query);
+
+ List<BookBean> found = query.find(books);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1,found.size());
+ Assert.assertEquals("A", found.get(0).getauthor().firstName);
+ }
+
+ public static String toXml(Object element) {
+ try {
+ JAXBContext jc = JAXBContext.newInstance(element.getClass());
+ Marshaller marshaller = jc.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ marshaller.marshal(element, baos);
+ return baos.toString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+
+ @Test
+ public void testXMLElementWrapperForCompositeTypes(){
+ //Assert.fail("implement");
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.util.Date;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ */
+@XmlRootElement(name="review")
+public class ReviewBean {
+ @XmlElement(name="date")
+ private Date _publishedDate;
+ @XmlElement(name="comment")
+ private String _comment;
+ @XmlElement(name="reviewer")
+ private PersonBean _reviewer;
+ @XmlElement
+ private int _upVotes;
+ @XmlElement
+ private int _downVotes;
+ public ReviewBean(){}
+
+ public ReviewBean(String comment, PersonBean user) {
+ _comment = comment;
+ _reviewer = user;
+ _publishedDate = new Date();
+ }
+
+ public void vote(int up, int down) {
+ _upVotes += up;
+ _downVotes += down;
+ }
+
+ @Override
+ public String toString() {
+ return "ReviewBean <publishedDate>" + _publishedDate + "</publishedDate> <comment>"
+ + _comment + "</comment> <reviewer>" + _reviewer + "</reviewer> <upVotes>" + _upVotes
+ + "</upVotes> <downVotes>" + _downVotes + "</downVotes>";
+ }
+}
--- /dev/null
+package org.opendaylight.controller.northbound.commons.query;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class XMLAccessorTypeTest {
+
+ @Test
+ public void testPublicAccessType() throws Exception {
+ // create bean
+ List<PublicAccessBean> testList = new ArrayList<PublicAccessBean>();
+ testList.add(new PublicAccessBean("John", "Scott", "private", 1,
+ "transient", "elem1"));
+ testList.add(new PublicAccessBean("Foo", "Bar", "private1", 2,
+ "transient1", "elem2"));
+ QueryContextTest.p(QueryContextTest.toXml(testList.get(0)));
+
+ QueryContext queryContext = new QueryContextImpl();
+ Assert.assertNotNull(queryContext);
+ // search for public field
+ Query<PublicAccessBean> query = queryContext.createQuery(
+ "publicbean.firstName==Foo", PublicAccessBean.class);
+ Assert.assertNotNull(query);
+
+ List<PublicAccessBean> found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1, found.size());
+ Assert.assertEquals("Foo", found.get(0).firstName);
+
+ // search for public getter
+ query = queryContext.createQuery("publicbean.privateGetterField<2",
+ PublicAccessBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1, found.size());
+ Assert.assertEquals("John", found.get(0).firstName);
+
+ // test for transient field
+ query = queryContext.createQuery("publicbean.transientField='trans*'",
+ PublicAccessBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(0, found.size());
+
+ // test for private field
+ query = queryContext.createQuery("publicbean.privateField==private",
+ PublicAccessBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(0, found.size());
+
+ // test for XML Element
+ query = queryContext.createQuery("publicbean.element==elem1",
+ PublicAccessBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1, found.size());
+ Assert.assertEquals("John", found.get(0).firstName);
+ }
+
+ @Test
+ public void testFieldAccessType() throws QueryException {
+ // create bean
+ List<FieldAccessBean> testList = new ArrayList<FieldAccessBean>();
+ testList.add(new FieldAccessBean("John", "Scott", "private", 1, "elem1"));
+ testList.add(new FieldAccessBean("Foo", "Bar", "private1", 2, "elem2"));
+
+ QueryContextTest.p(QueryContextTest.toXml(testList.get(0)));
+ QueryContext queryContext = new QueryContextImpl();
+ Assert.assertNotNull(queryContext);
+ // test private field
+ Query<FieldAccessBean> query = queryContext.createQuery(
+ "field.privateField==private", FieldAccessBean.class);
+ Assert.assertNotNull(query);
+
+ List<FieldAccessBean> found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1, found.size());
+ Assert.assertEquals("John", found.get(0).firstName);
+
+ // test public field
+ query = queryContext.createQuery("field.firstName==Foo",
+ FieldAccessBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1, found.size());
+ Assert.assertEquals("Foo", found.get(0).firstName);
+
+ // test annotated field
+ query = queryContext.createQuery("field.element==elem2",
+ FieldAccessBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1, found.size());
+ Assert.assertEquals("Foo", found.get(0).firstName);
+
+ // test annotated method
+ query = queryContext.createQuery("field.privateGetterField==11",
+ FieldAccessBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1, found.size());
+ Assert.assertEquals("John", found.get(0).firstName);
+ }
+
+ @Test
+ public void testPropertyAccessType() throws QueryException {
+ // create bean
+ List<PropertyAccessBean> testList = new ArrayList<PropertyAccessBean>();
+ testList.add(new PropertyAccessBean("John", "Scott", "private", 1, "elem1",
+ "transient1"));
+ testList.add(new PropertyAccessBean("Foo", "Bar", "private1", 2, "elem2",
+ "transient2"));
+
+ QueryContextTest.p(QueryContextTest.toXml(testList.get(0)));
+ QueryContext queryContext = new QueryContextImpl();
+ Assert.assertNotNull(queryContext);
+ // test public getter public field
+ Query<PropertyAccessBean> query = queryContext.createQuery(
+ "property.firstName==John", PropertyAccessBean.class);
+ Assert.assertNotNull(query);
+
+ List<PropertyAccessBean> found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1, found.size());
+ Assert.assertEquals("John", found.get(0).firstName);
+
+ // test public field no getter
+ query = queryContext.createQuery("property.lastName==Bar",
+ PropertyAccessBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(0, found.size());
+
+ // test annotated field
+ query = queryContext.createQuery("property.element==elem2",
+ PropertyAccessBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1, found.size());
+ Assert.assertEquals("Foo", found.get(0).firstName);
+
+ // test annotated method
+ query = queryContext.createQuery("property.field==private",
+ PropertyAccessBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1, found.size());
+ Assert.assertEquals("John", found.get(0).firstName);
+
+ // test transient method
+ query = queryContext.createQuery("property.transientField==transient1",
+ PropertyAccessBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(0, found.size());
+ }
+
+ @Test
+ public void testNoneAccessType() throws QueryException {
+ // create bean
+ List<NoneAccessBean> testList = new ArrayList<NoneAccessBean>();
+ testList.add(new NoneAccessBean("John", "Scott", "private"));
+ testList.add(new NoneAccessBean("Foo", "Bar", "private1"));
+
+ QueryContextTest.p(QueryContextTest.toXml(testList.get(0)));
+ QueryContext queryContext = new QueryContextImpl();
+ Assert.assertNotNull(queryContext);
+ // test annotated field
+ Query<NoneAccessBean> query = queryContext.createQuery(
+ "test.firstName==John", NoneAccessBean.class);
+ Assert.assertNotNull(query);
+
+ List<NoneAccessBean> found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1, found.size());
+ Assert.assertEquals("John", found.get(0).getFirstName());
+ // test unannotated field
+ query = queryContext
+ .createQuery("test.lastName==Bar", NoneAccessBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(0, found.size());
+ // test annotated method
+ query = queryContext.createQuery("test.testField==private",
+ NoneAccessBean.class);
+ Assert.assertNotNull(query);
+
+ found = query.find(testList);
+ Assert.assertNotNull(found);
+ Assert.assertEquals(1, found.size());
+ Assert.assertEquals("John", found.get(0).getFirstName());
+
+ }
+
+}
+
+// default ( public memeber )
+@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
+@XmlRootElement(name = "publicbean")
+class PublicAccessBean {
+
+ public String firstName;
+ public String lastName;
+ private String privateField;
+ private int privateGetterField;
+ @XmlTransient
+ public String transientField;
+ @XmlElement(name = "element")
+ private String xmlElem;
+
+ public PublicAccessBean() {
+ }
+
+ public PublicAccessBean(String firstName, String lastName,
+ String privateField, int privateGetterField, String transientField,
+ String xmlElem) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.privateField = privateField;
+ this.privateGetterField = privateGetterField;
+ this.transientField = transientField;
+ this.xmlElem = xmlElem;
+ }
+
+ public int getPrivateGetterField() {
+ return privateGetterField;
+ }
+
+ public void setPrivateGetterField(int field) {
+ this.privateGetterField = field;
+ }
+}
+
+// default ( public memeber )
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "field")
+class FieldAccessBean {
+
+ public String firstName;
+ public String lastName;
+ private String privateField;
+ private int test;
+ @XmlElement(name = "element")
+ private String xmlElem;
+
+ public FieldAccessBean() {
+ }
+
+ public FieldAccessBean(String firstName, String lastName,
+ String privateField, int privateGetterField, String xmlElem) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.privateField = privateField;
+ this.xmlElem = xmlElem;
+ this.test = privateGetterField;
+ }
+
+ public String getPrivateField() {
+ return privateField;
+ }
+
+ @XmlElement(name = "privateGetterField")
+ public int getPrivateGetterField() {
+ return test + 10;
+ }
+}
+
+// default ( public memeber )
+@XmlAccessorType(XmlAccessType.PROPERTY)
+@XmlRootElement(name = "property")
+class PropertyAccessBean {
+
+ public String firstName;
+ public String lastName;
+ private String privateField;
+ private int privateGetterField;
+ @XmlElement(name = "element")
+ private String xmlElem;
+ private String transientField;
+
+ public PropertyAccessBean() {
+ }
+
+ public PropertyAccessBean(String firstName, String lastName,
+ String privateField, int privateGetterField, String xmlElem,
+ String transientField) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.privateField = privateField;
+ this.privateGetterField = privateGetterField;
+ this.xmlElem = xmlElem;
+ this.transientField = transientField;
+ }
+
+ public int getPrivateGetterField() {
+ return privateGetterField;
+ }
+
+ @XmlElement(name = "field")
+ public String getPrivateField() {
+ return privateField;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ @XmlTransient
+ public String getTransientField() {
+ return transientField;
+ }
+}
+
+// default ( public memeber )
+@XmlAccessorType(XmlAccessType.NONE)
+@XmlRootElement(name = "test")
+class NoneAccessBean {
+ @XmlElement
+ private String firstName;
+ public String lastName;
+ private String testField;
+
+ public NoneAccessBean() {
+ }
+
+ public NoneAccessBean(String firstName, String lastName, String testField) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.testField = testField;
+ }
+
+ @XmlElement(name = "testField")
+ public String getTestField() {
+ return testField;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+}
--- /dev/null
+<configuration scan="true">
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n
+ </pattern>
+ </encoder>
+ </appender>
+
+
+ <logger name="org.opendaylight.controller.northbound.commons.query" level="INFO"/>
+
+ <root level="error">
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration>
org.opendaylight.controller.northbound.commons,
org.opendaylight.controller.northbound.commons.exception,
org.opendaylight.controller.northbound.commons.utils,
+ org.opendaylight.controller.northbound.commons.query,
org.opendaylight.controller.sal.authorization,
org.opendaylight.controller.connectionmanager,
org.opendaylight.controller.sal.connection,
org.slf4j,
javax.ws.rs,
+ javax.ws.rs.ext,
javax.ws.rs.core,
javax.xml.bind.annotation,
javax.xml.bind,
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.ext.ContextResolver;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.query.QueryContext;
import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
import org.opendaylight.controller.sal.authorization.Privilege;
import org.opendaylight.controller.sal.connection.ConnectionConstants;
@Path("/")
public class ConnectionManagerNorthbound {
private String username;
+ private QueryContext queryContext;
+ @Context
+ public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
+ if (queryCtxResolver != null) {
+ queryContext = queryCtxResolver.getContext(QueryContext.class);
+ }
+ }
@Context
public void setSecurityContext(SecurityContext context) {
if (context != null && context.getUserPrincipal() != null) username = context.getUserPrincipal().getName();
@ResponseCode(code = 406, condition = "Invalid Controller IP Address passed."),
@ResponseCode(code = 503, condition = "Connection Manager Service not available")})
- public Nodes getNodes(@DefaultValue("") @QueryParam("controller") String controllerAddress) {
+ public Nodes getNodes(@DefaultValue("") @QueryParam("controller") String controllerAddress,
+ @QueryParam("_q") String queryString) {
if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.READ, this)) {
throw new UnauthorizedException("User is not authorized to perform this operation on container");
}
} else {
nodeSet = connectionManager.getLocalNodes();
}
- return new Nodes(nodeSet);
+ Nodes nodes = new Nodes(nodeSet);
+ if (queryString != null) {
+ queryContext.createQuery(queryString, Nodes.class)
+ .filter(nodes, Node.class);
+ }
+ return nodes;
}
/**
org.opendaylight.controller.northbound.commons,
org.opendaylight.controller.northbound.commons.exception,
org.opendaylight.controller.northbound.commons.utils,
+ org.opendaylight.controller.northbound.commons.query,
com.sun.jersey.spi.container.servlet,
javax.ws.rs,
+ javax.ws.rs.ext,
javax.ws.rs.core,
javax.xml.bind.annotation,
javax.xml.bind,
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.ext.ContextResolver;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
import org.opendaylight.controller.northbound.commons.exception.ResourceForbiddenException;
import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.query.QueryContext;
import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
import org.opendaylight.controller.sal.authorization.Privilege;
import org.opendaylight.controller.sal.authorization.UserLevel;
@Path("/")
public class ContainerManagerNorthbound {
private String username;
+ private QueryContext queryContext;
+
+ @Context
+ public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
+ if (queryCtxResolver != null) {
+ queryContext = queryCtxResolver.getContext(QueryContext.class);
+ }
+ }
@Context
public void setSecurityContext(SecurityContext context) {
@StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"),
@ResponseCode(code = 401, condition = "User is not authorized to perform this operation"),
@ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
- public ContainerConfigs viewAllContainers() {
+ public ContainerConfigs viewAllContainers(@QueryParam("_q") String queryString) {
handleNetworkAuthorization(getUserName());
IContainerManager containerManager = getContainerManager();
-
- return new ContainerConfigs(containerManager.getContainerConfigList());
+ ContainerConfigs result = new ContainerConfigs(
+ containerManager.getContainerConfigList());
+ if (queryString != null) {
+ queryContext.createQuery(queryString, ContainerConfigs.class)
+ .filter(result, ContainerConfig.class);
+ }
+ return result;
}
/**
@StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"),
@ResponseCode(code = 404, condition = "The container is not found"),
@ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
- public FlowSpecConfigs viewContainerFlowSpecs(@PathParam(value = "container") String container) {
+ public FlowSpecConfigs viewContainerFlowSpecs(@PathParam(value = "container") String container,
+ @QueryParam("_q") String queryString) {
handleContainerAuthorization(container, getUserName());
handleForbiddenOnDefault(container);
handleContainerNotExists(container);
IContainerManager containerManager = getContainerManager();
-
- return new FlowSpecConfigs(containerManager.getContainerFlows(container));
+ FlowSpecConfigs result = new FlowSpecConfigs(
+ containerManager.getContainerFlows(container));
+ if (queryString != null) {
+ queryContext.createQuery(queryString, FlowSpecConfigs.class)
+ .filter(result, ContainerFlowConfig.class);
+ }
+ return result;
}
/**
import java.util.HashSet;
import java.util.Set;
+
import javax.ws.rs.core.Application;
+import org.opendaylight.controller.northbound.commons.query.QueryContextProvider;
+
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
/**
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(ContainerManagerNorthbound.class);
classes.add(JacksonJaxbJsonProvider.class);
+ classes.add(QueryContextProvider.class);
return classes;
}
}
org.opendaylight.controller.northbound.commons,
org.opendaylight.controller.northbound.commons.exception,
org.opendaylight.controller.northbound.commons.utils,
+ org.opendaylight.controller.northbound.commons.query,
org.opendaylight.controller.sal.authorization,
javax.ws.rs,
+ javax.ws.rs.ext,
javax.ws.rs.core,
javax.xml.bind.annotation,
javax.xml.bind,
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.ext.ContextResolver;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.query.QueryContext;
import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
import org.opendaylight.controller.sal.authorization.Privilege;
import org.opendaylight.controller.sal.core.Property;
public class ControllerManagerNorthbound {
private String username;
+ private QueryContext queryContext;
+
+ @Context
+ public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
+ if (queryCtxResolver != null) {
+ queryContext = queryCtxResolver.getContext(QueryContext.class);
+ }
+ }
@Context
public void setSecurityContext(SecurityContext context) {
@ResponseCode(code = 404, condition = "The containerName or property is not found"),
@ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
public ControllerProperties getControllerProperties(@PathParam("containerName") String containerName,
- @QueryParam("propertyName") String propertyName) {
+ @QueryParam("propertyName") String propertyName,
+ @QueryParam("_q") String queryString) {
if (!isValidContainer(containerName)) {
throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
throw new ResourceNotFoundException("Unable to find property with name: " + propertyName);
}
properties.add(property);
-
- return new ControllerProperties(properties);
+ ControllerProperties result = new ControllerProperties(properties);
+ if (queryString != null) {
+ queryContext.createQuery(queryString, ControllerProperties.class)
+ .filter(result, Property.class);
+ }
+ return result;
}
org.opendaylight.controller.northbound.commons,
org.opendaylight.controller.northbound.commons.exception,
org.opendaylight.controller.northbound.commons.utils,
+ org.opendaylight.controller.northbound.commons.query,
org.opendaylight.controller.sal.authorization,
org.opendaylight.controller.usermanager,
com.sun.jersey.spi.container.servlet,
org.apache.catalina.filters,
javax.ws.rs,
+ javax.ws.rs.ext,
javax.ws.rs.core,
javax.xml.bind.annotation,
javax.xml.bind,
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.ext.ContextResolver;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.query.QueryContext;
import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
import org.opendaylight.controller.sal.authorization.Privilege;
import org.opendaylight.controller.sal.core.Node;
private String username;
+ private QueryContext queryContext;
+ @Context
+ public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
+ if (queryCtxResolver != null) {
+ queryContext = queryCtxResolver.getContext(QueryContext.class);
+ }
+ }
+
@Context
public void setSecurityContext(SecurityContext context) {
if (context != null && context.getUserPrincipal() != null) {
@StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"),
@ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
@ResponseCode(code = 404, condition = "The containerName is not found"),
- @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
- public FlowConfigs getStaticFlows(@PathParam("containerName") String containerName) {
+ @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable"),
+ @ResponseCode(code = 400, condition = "Incorrect query syntex")})
+ public FlowConfigs getStaticFlows(@PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
throw new UnauthorizedException("User is not authorized to perform this operation on container "
+ containerName);
}
- List<FlowConfig> flowConfigs = getStaticFlowsInternal(containerName, null);
- return new FlowConfigs(flowConfigs);
+ FlowConfigs result = new FlowConfigs(getStaticFlowsInternal(containerName, null));
+ if (queryString != null) {
+ queryContext.createQuery(queryString, FlowConfigs.class)
+ .filter(result, FlowConfig.class);
+ }
+ return result;
}
/**
@ResponseCode(code = 404, condition = "The containerName or nodeId is not found"),
@ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
public FlowConfigs getStaticFlows(@PathParam("containerName") String containerName,
- @PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId) {
+ @PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
+ @QueryParam("_q") String queryString) {
if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
throw new UnauthorizedException("User is not authorized to perform this operation on container "
+ containerName);
if (node == null) {
throw new ResourceNotFoundException(nodeId + " : " + RestMessages.NONODE.toString());
}
- List<FlowConfig> flows = getStaticFlowsInternal(containerName, node);
- return new FlowConfigs(flows);
+ FlowConfigs flows = new FlowConfigs(getStaticFlowsInternal(containerName, node));
+ if (queryString != null) {
+ queryContext.createQuery(queryString, FlowConfigs.class)
+ .filter(flows, FlowConfig.class);
+ }
+ return flows;
}
/**
com.sun.jersey.spi.container.servlet,
org.opendaylight.controller.northbound.commons,
org.opendaylight.controller.northbound.commons.exception,
+ org.opendaylight.controller.northbound.commons.query,
org.opendaylight.controller.northbound.commons.utils,
org.opendaylight.controller.sal.authorization,
org.opendaylight.controller.sal.packet.address,
javax.ws.rs,
javax.ws.rs.core,
+ javax.ws.rs.ext,
javax.xml.bind.annotation,
javax.xml.bind,
org.slf4j,
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.ext.ContextResolver;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.query.QueryContext;
import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
import org.opendaylight.controller.sal.authorization.Privilege;
import org.opendaylight.controller.sal.core.Node;
public class HostTrackerNorthbound {
private String username;
+ private QueryContext queryContext;
+
+ @Context
+ public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
+ if (queryCtxResolver != null) {
+ queryContext = queryCtxResolver.getContext(QueryContext.class);
+ }
+ }
@Context
public void setSecurityContext(SecurityContext context) {
return hostTracker;
}
- private Hosts convertHosts(Set<HostNodeConnector> hostNodeConnectors) {
+ private Set<HostConfig> convertHosts(Set<HostNodeConnector> hostNodeConnectors) {
if(hostNodeConnectors == null) {
return null;
}
for(HostNodeConnector hnc : hostNodeConnectors) {
hosts.add(HostConfig.convert(hnc));
}
- return new Hosts(hosts);
+ return hosts;
}
/**
@ResponseCode(code = 200, condition = "Operation successful"),
@ResponseCode(code = 404, condition = "The containerName is not found"),
@ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
- public Hosts getActiveHosts(@PathParam("containerName") String containerName) {
+ public Hosts getActiveHosts(@PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
throw new UnauthorizedException("User is not authorized to perform this operation on container "
+ containerName);
}
IfIptoHost hostTracker = getIfIpToHostService(containerName);
- return convertHosts(hostTracker.getAllHosts());
+ Hosts hosts = new Hosts(convertHosts(hostTracker.getAllHosts()));
+ if (queryString != null) {
+ queryContext.createQuery(queryString, Hosts.class)
+ .filter(hosts, HostConfig.class);
+ }
+ return hosts;
}
/**
@ResponseCode(code = 404, condition = "The containerName is not found"),
@ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
public Hosts getInactiveHosts(
- @PathParam("containerName") String containerName) {
+ @PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
throw new UnauthorizedException("User is not authorized to perform this operation on container "
+ containerName);
}
IfIptoHost hostTracker = getIfIpToHostService(containerName);
- return convertHosts(hostTracker.getInactiveStaticHosts());
+ Hosts hosts = new Hosts(convertHosts(hostTracker.getInactiveStaticHosts()));
+ if (queryString != null) {
+ queryContext.createQuery(queryString, Hosts.class)
+ .filter(hosts, HostConfig.class);
+ }
+ return hosts;
}
/**
org.opendaylight.controller.northbound.commons,
org.opendaylight.controller.northbound.commons.exception,
org.opendaylight.controller.northbound.commons.utils,
+ org.opendaylight.controller.northbound.commons.query,
org.opendaylight.controller.sal.authorization,
org.slf4j,
javax.ws.rs,
+ javax.ws.rs.ext,
javax.ws.rs.core,
javax.xml.bind.annotation,
javax.xml.bind,
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.ext.ContextResolver;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.query.QueryContext;
import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
import org.opendaylight.controller.sal.authorization.Privilege;
import org.opendaylight.controller.sal.utils.GlobalConstants;
public class StaticRoutingNorthbound {
private String username;
+ private QueryContext queryContext;
+
+ @Context
+ public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
+ if (queryCtxResolver != null) {
+ queryContext = queryCtxResolver.getContext(QueryContext.class);
+ }
+ }
@Context
public void setSecurityContext(SecurityContext context) {
@ResponseCode(code = 200, condition = "Operation successful"),
@ResponseCode(code = 404, condition = "The containerName passed was not found") })
public StaticRoutes getStaticRoutes(
- @PathParam("containerName") String containerName) {
+ @PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
if(!NorthboundUtils.isAuthorized(getUserName(), containerName,
Privilege.WRITE, this)){
UnauthorizedException("User is not authorized to perform this operation on container "
+ containerName);
}
- return new StaticRoutes(getStaticRoutesInternal(containerName));
+ StaticRoutes result = new StaticRoutes(getStaticRoutesInternal(containerName));
+ if (queryString != null) {
+ queryContext.createQuery(queryString, StaticRoutes.class)
+ .filter(result, StaticRoute.class);
+ }
+ return result;
}
/**
org.opendaylight.controller.northbound.commons,
org.opendaylight.controller.northbound.commons.exception,
org.opendaylight.controller.northbound.commons.utils,
+ org.opendaylight.controller.northbound.commons.query,
javax.ws.rs,
+ javax.ws.rs.ext,
javax.ws.rs.core,
javax.xml.bind.annotation,
javax.xml.bind,
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.ext.ContextResolver;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.query.QueryContext;
import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
import org.opendaylight.controller.sal.authorization.Privilege;
import org.opendaylight.controller.sal.core.Node;
public class StatisticsNorthbound {
private String username;
+ private QueryContext queryContext;
+ @Context
+ public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
+ if (queryCtxResolver != null) {
+ queryContext = queryCtxResolver.getContext(QueryContext.class);
+ }
+ }
@Context
public void setSecurityContext(SecurityContext context) {
if (context != null && context.getUserPrincipal() != null) username = context.getUserPrincipal().getName();
@ResponseCode(code = 404, condition = "The containerName is not found"),
@ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
public AllFlowStatistics getFlowStatistics(
- @PathParam("containerName") String containerName) {
+ @PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
if (!NorthboundUtils.isAuthorized(
getUserName(), containerName, Privilege.READ, this)) {
throw new UnauthorizedException(
FlowStatistics stat = new FlowStatistics(node, flowStats);
statistics.add(stat);
}
- return new AllFlowStatistics(statistics);
+ AllFlowStatistics result = new AllFlowStatistics(statistics);
+ if (queryString != null) {
+ queryContext.createQuery(queryString, AllFlowStatistics.class)
+ .filter(result, FlowStatistics.class);
+ }
+ return result;
}
/**
@ResponseCode(code = 404, condition = "The containerName is not found"),
@ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
public AllPortStatistics getPortStatistics(
- @PathParam("containerName") String containerName) {
+ @PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
if (!NorthboundUtils.isAuthorized(
getUserName(), containerName, Privilege.READ, this)) {
PortStatistics portStat = new PortStatistics(node, stat);
statistics.add(portStat);
}
- return new AllPortStatistics(statistics);
+
+ AllPortStatistics result = new AllPortStatistics(statistics);
+ if (queryString != null) {
+ queryContext.createQuery(queryString, AllPortStatistics.class)
+ .filter(result, PortStatistics.class);
+ }
+ return result;
}
/**
@ResponseCode(code = 404, condition = "The containerName is not found"),
@ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
public AllTableStatistics getTableStatistics(
- @PathParam("containerName") String containerName) {
+ @PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
throw new UnauthorizedException("User is not authorized to perform this operation on container "
TableStatistics tableStat = new TableStatistics(node, stat);
statistics.add(tableStat);
}
- return new AllTableStatistics(statistics);
+ AllTableStatistics allstats = new AllTableStatistics(statistics);
+ if (queryString != null) {
+ queryContext.createQuery(queryString, AllTableStatistics.class)
+ .filter(allstats, TableStatistics.class);
+ }
+ return allstats;
}
/**
org.opendaylight.controller.switchmanager,
org.opendaylight.controller.northbound.commons,
org.opendaylight.controller.northbound.commons.exception,
+ org.opendaylight.controller.northbound.commons.query,
org.opendaylight.controller.northbound.commons.utils,
com.sun.jersey.spi.container.servlet,
org.opendaylight.controller.sal.authorization,
org.opendaylight.controller.usermanager,
javax.ws.rs,
javax.ws.rs.core,
+ javax.ws.rs.ext,
javax.xml.bind,
javax.xml.bind.annotation,
org.slf4j,
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.ext.ContextResolver;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.query.QueryContext;
import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
import org.opendaylight.controller.sal.authorization.Privilege;
import org.opendaylight.controller.sal.core.NodeConnector;
protected static final Logger logger = LoggerFactory.getLogger(SubnetsNorthbound.class);
private String username;
+ private QueryContext queryContext;
+
+ @Context
+ public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
+ if (queryCtxResolver != null) {
+ queryContext = queryCtxResolver.getContext(QueryContext.class);
+ }
+ }
@Context
public void setSecurityContext(SecurityContext context) {
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@StatusCodes({ @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
@ResponseCode(code = 404, condition = "The containerName passed was not found"),
- @ResponseCode(code = 503, condition = "Service unavailable") })
+ @ResponseCode(code = 503, condition = "Service unavailable"),
+ @ResponseCode(code = 400, condition = "Incorrect query syntex") })
@TypeHint(SubnetConfigs.class)
- public SubnetConfigs listSubnets(@PathParam("containerName") String containerName) {
+ public SubnetConfigs listSubnets(@PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
handleContainerDoesNotExist(containerName);
if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
if (switchManager == null) {
throw new ServiceUnavailableException("SwitchManager " + RestMessages.SERVICEUNAVAILABLE.toString());
}
- return new SubnetConfigs(switchManager.getSubnetsConfigList());
+ List<SubnetConfig> subnets = switchManager.getSubnetsConfigList();
+ if (queryString != null) {
+ subnets = queryContext.createQuery(queryString, SubnetConfig.class)
+ .find(subnets);
+
+ }
+ return new SubnetConfigs(subnets);
}
/**
org.opendaylight.controller.northbound.commons.exception,
org.opendaylight.controller.northbound.commons.utils,
org.opendaylight.controller.sal.authorization,
+ org.opendaylight.controller.northbound.commons.query,
javax.ws.rs,
+ javax.ws.rs.ext,
javax.ws.rs.core,
javax.xml.bind.annotation,
javax.xml.bind,
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.ext.ContextResolver;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.query.QueryContext;
import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
import org.opendaylight.controller.sal.authorization.Privilege;
import org.opendaylight.controller.sal.core.Node;
public class SwitchNorthbound {
private String username;
+ private QueryContext queryContext;
+
+ @Context
+ public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
+ if (queryCtxResolver != null) {
+ queryContext = queryCtxResolver.getContext(QueryContext.class);
+ }
+ }
@Context
public void setSecurityContext(SecurityContext context) {
@StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"),
@ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
@ResponseCode(code = 404, condition = "The containerName is not found"),
- @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
- public Nodes getNodes(@PathParam("containerName") String containerName) {
+ @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable"),
+ @ResponseCode(code = 400, condition = "Incorrect query syntex") })
+ public Nodes getNodes(@PathParam("containerName") String containerName, @QueryParam("_q") String queryString) {
if (!isValidContainer(containerName)) {
throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
NodeProperties nodeProps = new NodeProperties(node, props);
res.add(nodeProps);
}
-
- return new Nodes(res);
+ Nodes result = new Nodes(res);
+ if (queryString != null) {
+ queryContext.createQuery(queryString, Nodes.class)
+ .filter(result, NodeProperties.class);
+ }
+ return result;
}
/**
@StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"),
@ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
@ResponseCode(code = 404, condition = "The containerName is not found"),
- @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+ @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable"),
+ @ResponseCode(code = 400, condition = "Incorrect query syntex") })
public NodeConnectors getNodeConnectors(@PathParam("containerName") String containerName,
- @PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId) {
+ @PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
+ @QueryParam("_q") String queryString) {
if (!isValidContainer(containerName)) {
throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
NodeConnectorProperties ncProps = new NodeConnectorProperties(nc, props);
res.add(ncProps);
}
-
- return new NodeConnectors(res);
+ NodeConnectors result = new NodeConnectors(res);
+ if (queryString != null) {
+ queryContext.createQuery(queryString, NodeConnectors.class)
+ .filter(result, NodeConnectorProperties.class);
+ }
+ return result;
}
/**
org.opendaylight.controller.northbound.commons,
org.opendaylight.controller.northbound.commons.exception,
org.opendaylight.controller.northbound.commons.utils,
+ org.opendaylight.controller.northbound.commons.query,
org.opendaylight.controller.sal.core,
org.opendaylight.controller.sal.packet,
org.opendaylight.controller.sal.authorization,
com.sun.jersey.spi.container.servlet,
com.fasterxml.jackson.annotation,
javax.ws.rs,
+ javax.ws.rs.ext,
javax.ws.rs.core,
javax.xml.bind,
javax.xml.bind.annotation,
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.ext.ContextResolver;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.query.QueryContext;
import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
import org.opendaylight.controller.sal.authorization.Privilege;
import org.opendaylight.controller.sal.core.Edge;
public class TopologyNorthboundJAXRS {
private String username;
+ private QueryContext queryContext;
+ @Context
+ public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
+ if (queryCtxResolver != null) {
+ queryContext = queryCtxResolver.getContext(QueryContext.class);
+ }
+ }
@Context
public void setSecurityContext(SecurityContext context) {
if (context != null && context.getUserPrincipal() != null) {
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@TypeHint(Topology.class)
@StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
- public Topology getTopology(@PathParam("containerName") String containerName) {
+ public Topology getTopology(@PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
throw new UnauthorizedException("User is not authorized to perform this operation on container "
}
Map<Edge, Set<Property>> topo = topologyManager.getEdges();
- if (topo != null) {
- List<EdgeProperties> res = new ArrayList<EdgeProperties>();
- for (Map.Entry<Edge, Set<Property>> entry : topo.entrySet()) {
- EdgeProperties el = new EdgeProperties(entry.getKey(), entry.getValue());
- res.add(el);
- }
- return new Topology(res);
+ if (topo == null) {
+ return null;
+ }
+ List<EdgeProperties> res = new ArrayList<EdgeProperties>();
+ for (Map.Entry<Edge, Set<Property>> entry : topo.entrySet()) {
+ EdgeProperties el = new EdgeProperties(entry.getKey(), entry.getValue());
+ res.add(el);
}
+ Topology result = new Topology(res);
- return null;
+ if (queryString != null) {
+ queryContext.createQuery(queryString, Topology.class)
+ .filter(result, EdgeProperties.class);
+ }
+ return result;
}
/**
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@TypeHint(TopologyUserLinks.class)
@StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
- public TopologyUserLinks getUserLinks(@PathParam("containerName") String containerName) {
+ public TopologyUserLinks getUserLinks(@PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
throw new UnauthorizedException("User is not authorized to perform this operation on container "
}
ConcurrentMap<String, TopologyUserLinkConfig> userLinks = topologyManager.getUserLinks();
- if ((userLinks != null) && (userLinks.values() != null)) {
- List<TopologyUserLinkConfig> res = new ArrayList<TopologyUserLinkConfig>(userLinks.values());
- return new TopologyUserLinks(res);
+ if ((userLinks == null) || (userLinks.values() == null)) {
+ return null;
}
-
- return null;
+ TopologyUserLinks result = new TopologyUserLinks(
+ new ArrayList<TopologyUserLinkConfig>(userLinks.values()));
+ if (queryString != null) {
+ queryContext.createQuery(queryString, TopologyUserLinks.class)
+ .filter(result, TopologyUserLinkConfig.class);
+ }
+ return result;
}
/**