Author: kwall
Date: Sun Apr 17 09:06:13 2016
New Revision: 1739559
URL: http://svn.apache.org/viewvc?rev=1739559&view=rev
Log:
QPID-7177: [Java Broker] Configured Object search - add DATE_ADD, TO_STRING
* DATE_ADD takes a ISO 8601 format duration e.g. -PT10H (minus ten hours)
* TO_STRING can format objects using an optional printf style formatting. For
dates an optional timezone may be included too.
Added:
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/EvaluationException.java
Modified:
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectExpressionFactory.java
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectQuery.java
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ParseException.java
qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectQueryTest.java
Modified:
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectExpressionFactory.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectExpressionFactory.java?rev=1739559&r1=1739558&r2=1739559&view=diff
==============================================================================
---
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectExpressionFactory.java
(original)
+++
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectExpressionFactory.java
Sun Apr 17 09:06:13 2016
@@ -29,10 +29,15 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.TimeZone;
import javax.xml.bind.DatatypeConverter;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.Duration;
import org.apache.qpid.filter.Expression;
+import org.apache.qpid.filter.SelectorParsingException;
import org.apache.qpid.server.model.ConfiguredObject;
public class ConfiguredObjectExpressionFactory
@@ -40,7 +45,20 @@ public class ConfiguredObjectExpressionF
private static final String PARENT_ATTR = "$parent";
private static Set<String> SPECIAL_ATTRIBUTES = new
HashSet<>(Arrays.asList(PARENT_ATTR));
+ private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
+ private static final DatatypeFactory DATATYPE_FACTORY;
+ static
+ {
+ try
+ {
+ DATATYPE_FACTORY = DatatypeFactory.newInstance();
+ }
+ catch (DatatypeConfigurationException e)
+ {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
enum FilterFunction
{
@@ -83,8 +101,7 @@ public class ConfiguredObjectExpressionF
}
},
- TO_DATE
- {
+ TO_DATE {
@Override
ConfiguredObjectExpression asExpression(final List<Expression>
args)
{
@@ -110,13 +127,100 @@ public class ConfiguredObjectExpressionF
}
catch (IllegalArgumentException e)
{
- throw new IllegalArgumentException(TO_DATE
- + " requires an
ISO-8601 format date or date/time.", e);
+ throw new IllegalArgumentException(TO_DATE + "
requires an ISO-8601 format date or date/time.", e);
}
}
};
}
+ },
+
+ DATE_ADD {
+ @Override
+ ConfiguredObjectExpression asExpression (final List<Expression>
args)
+ {
+ if (args == null || args.size() != 2)
+ {
+ throw new IllegalArgumentException(DATE_ADD.name() + "
requires two arguments.");
+ }
+
+ return new ConfiguredObjectExpression()
+ {
+ @Override
+ public Object evaluate(final ConfiguredObject<?> object)
+ {
+ Object date = args.get(0).evaluate(object);
+ Object period = args.get(1).evaluate(object);
+ if (!(date instanceof Date) || !(period instanceof
String))
+ {
+ throw new
IllegalArgumentException(String.format("%s requires a (Date, String) not a"
+ +
" (%s,%s)",
+
DATE_ADD,
+
date.getClass().getSimpleName(),
+
period.getClass().getSimpleName()));
+ }
+ try
+ {
+ Date copy = new Date(((Date) date).getTime());
+ final Duration duration =
DATATYPE_FACTORY.newDuration((String) period);
+ duration.addTo(copy);
+ return copy;
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IllegalArgumentException(DATE_ADD + "
requires an ISO-8601 format duration.", e);
+ }
+ }
+ };
+ }
+ },
+
+ TO_STRING {
+ @Override
+ ConfiguredObjectExpression asExpression(final List<Expression>
args)
+ {
+ if (args == null || (args.size() == 0 || args.size() > 3))
+ {
+ throw new IllegalArgumentException(TO_STRING.name() + "
requires (Object[,{printf format specifier},[{timezone name}]]).");
+ }
+
+ return new ConfiguredObjectExpression()
+ {
+ @Override
+ public Object evaluate(final ConfiguredObject<?> object)
+ {
+ Object obj = args.get(0).evaluate(object);
+ Object format = args.size() > 1 ?
args.get(1).evaluate(object) : null;
+ Object timezoneName = args.size() > 2 ?
args.get(2).evaluate(object) : null;
+ if (obj instanceof Date)
+ {
+ final Calendar cal = timezoneName == null ?
Calendar.getInstance(UTC) : Calendar.getInstance(TimeZone.getTimeZone(
+ (String) timezoneName));
+ cal.setTime((Date) obj);
+ if (format == null)
+ {
+ return DatatypeConverter.printDateTime(cal);
+ }
+ else
+ {
+ return String.format((String)format, cal);
+ }
+ }
+ else
+ {
+ // TODO If obj itself is another configured object
perhaps we should just use its name or id? The CO.toString value probably isn't
too useful.
+ if (format == null)
+ {
+ return String.valueOf(obj);
+ }
+ else
+ {
+ return String.format((String)format, obj);
+ }
+ }
+ }
+ };
+ }
};
abstract ConfiguredObjectExpression asExpression( List<Expression>
args );
@@ -146,12 +250,20 @@ public class ConfiguredObjectExpressionF
{
try
{
- FilterFunction function =
FilterFunction.valueOf(functionName.toUpperCase());
+ FilterFunction function = null;
+ try
+ {
+ function = FilterFunction.valueOf(functionName.toUpperCase());
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ParseException("Unknown function name : '" +
functionName + "'");
+ }
return function.asExpression(args);
}
catch(IllegalArgumentException e)
{
- throw new ParseException("Unknown function name " + functionName);
+ throw new ParseException("Function parameter mismatch : '" +
functionName + "'", e);
}
}
Modified:
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectQuery.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectQuery.java?rev=1739559&r1=1739558&r2=1739559&view=diff
==============================================================================
---
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectQuery.java
(original)
+++
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectQuery.java
Sun Apr 17 09:06:13 2016
@@ -93,7 +93,7 @@ public final class ConfiguredObjectQuery
}
catch (ParseException | TokenMgrError e)
{
- throw new SelectorParsingException("Unable to parse select
clause");
+ throw new SelectorParsingException("Unable to parse select
clause", e);
}
}
else
@@ -142,7 +142,7 @@ public final class ConfiguredObjectQuery
}
catch (RuntimeException e)
{
- LOGGER.debug("Error while evaluating object against where
clause", e);
+ throw new EvaluationException("Error while evaluating
object against where clause", e);
}
}
Added:
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/EvaluationException.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/EvaluationException.java?rev=1739559&view=auto
==============================================================================
---
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/EvaluationException.java
(added)
+++
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/EvaluationException.java
Sun Apr 17 09:06:13 2016
@@ -0,0 +1,30 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.management.plugin.servlet.query;
+
+public class EvaluationException extends RuntimeException
+{
+ public EvaluationException(final String s, final RuntimeException e)
+ {
+ super(s,e);
+ }
+}
Modified:
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ParseException.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ParseException.java?rev=1739559&r1=1739558&r2=1739559&view=diff
==============================================================================
---
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ParseException.java
(original)
+++
qpid/java/trunk/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/query/ParseException.java
Sun Apr 17 09:06:13 2016
@@ -77,6 +77,10 @@ public class ParseException extends Exce
super(message);
}
+ public ParseException(String message, Throwable t) {
+ super(message, t);
+ }
+
/**
* This is the last token that has been consumed successfully. If
Modified:
qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectQueryTest.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectQueryTest.java?rev=1739559&r1=1739558&r2=1739559&view=diff
==============================================================================
---
qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectQueryTest.java
(original)
+++
qpid/java/trunk/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/query/ConfiguredObjectQueryTest.java
Sun Apr 17 09:06:13 2016
@@ -26,7 +26,6 @@ import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
-import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -39,6 +38,7 @@ import javax.xml.bind.DatatypeConverter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import org.apache.qpid.filter.SelectorParsingException;
import org.apache.qpid.server.model.ConfiguredObject;
import org.apache.qpid.test.utils.QpidTestCase;
@@ -47,12 +47,11 @@ public class ConfiguredObjectQueryTest e
private static final String NUMBER_ATTR = "numberAttr";
private static final String DATE_ATTR = "dateAttr";
+ private final List<ConfiguredObject<?>> _objects = new ArrayList<>();
private ConfiguredObjectQuery _query;
- public void testSingleResultNoClauses() throws Exception
+ public void testNoClauses_SingleResult() throws Exception
{
- final List<ConfiguredObject<?>> objects = new ArrayList<>();
-
final UUID objectUuid = UUID.randomUUID();
final String objectName = "obj1";
@@ -62,9 +61,9 @@ public class ConfiguredObjectQueryTest e
put(ConfiguredObject.NAME, objectName);
}});
- objects.add(obj1);
+ _objects.add(obj1);
- _query = new ConfiguredObjectQuery(objects, null, null);
+ _query = new ConfiguredObjectQuery(_objects, null, null);
final List<String> headers = _query.getHeaders();
assertEquals("Unexpected headers",
Lists.newArrayList(ConfiguredObject.ID, ConfiguredObject.NAME), headers);
@@ -76,10 +75,8 @@ public class ConfiguredObjectQueryTest e
assertEquals("Unexpected row", Lists.newArrayList(objectUuid,
objectName), row);
}
- public void testTwoResultNoClauses() throws Exception
+ public void testNoClauses_TwoResult() throws Exception
{
- final List<ConfiguredObject<?>> objects = new ArrayList<>();
-
final UUID object1Uuid = UUID.randomUUID();
final String object1Name = "obj1";
@@ -98,10 +95,10 @@ public class ConfiguredObjectQueryTest e
put(ConfiguredObject.NAME, object2Name);
}});
- objects.add(obj1);
- objects.add(obj2);
+ _objects.add(obj1);
+ _objects.add(obj2);
- _query = new ConfiguredObjectQuery(objects, null, null);
+ _query = new ConfiguredObjectQuery(_objects, null, null);
List<List<Object>> results = _query.getResults();
assertEquals("Unexpected number of results", 2, results.size());
@@ -114,10 +111,63 @@ public class ConfiguredObjectQueryTest e
assertEquals("Unexpected row", Lists.newArrayList(object2Uuid,
object2Name), row2);
}
- public void testQuery_StringEquality() throws Exception
+ public void testSelectClause() throws Exception
{
- final List<ConfiguredObject<?>> objects = new ArrayList<>();
+ final UUID objectUuid = UUID.randomUUID();
+
+ ConfiguredObject obj = createCO(new HashMap<String, Object>()
+ {{
+ put(ConfiguredObject.ID, objectUuid);
+ put(NUMBER_ATTR, 1234);
+ }});
+
+ _objects.add(obj);
+
+ _query = new ConfiguredObjectQuery(_objects,
+ String.format("%s,%s",
ConfiguredObject.ID, NUMBER_ATTR),
+ null);
+
+ List<List<Object>> results = _query.getResults();
+ assertEquals("Unexpected number of results", 1, results.size());
+
+ final List<String> headers = _query.getHeaders();
+ assertEquals("Unexpected headers",
Lists.newArrayList(ConfiguredObject.ID, NUMBER_ATTR), headers);
+
+ final Iterator<List<Object>> iterator = results.iterator();
+ List<Object> row = iterator.next();
+ assertEquals("Unexpected row", Lists.newArrayList(objectUuid, 1234),
row);
+ }
+
+ public void testSelectClause_ColumnAliases() throws Exception
+ {
+ final UUID objectUuid = UUID.randomUUID();
+
+ ConfiguredObject obj = createCO(new HashMap<String, Object>()
+ {{
+ put(ConfiguredObject.ID, objectUuid);
+ put(ConfiguredObject.NAME, "myObj");
+ put(NUMBER_ATTR, 1234);
+ }});
+
+ _objects.add(obj);
+ _query = new ConfiguredObjectQuery(_objects,
+ String.format("%s,CONCAT(%s,%s) AS
alias", ConfiguredObject.ID, ConfiguredObject.NAME, NUMBER_ATTR),
+ null);
+
+ List<List<Object>> results = _query.getResults();
+ assertEquals("Unexpected number of results", 1, results.size());
+
+ final List<String> headers = _query.getHeaders();
+ assertEquals("Unexpected headers",
Lists.newArrayList(ConfiguredObject.ID, "alias"), headers);
+
+ final Iterator<List<Object>> iterator = results.iterator();
+ List<Object> row = iterator.next();
+ assertEquals("Unexpected row", Lists.newArrayList(objectUuid,
"myObj1234"), row);
+ }
+
+ public void testQuery_StringEquality() throws Exception
+ {
final UUID objectUuid = UUID.randomUUID();
final String objectName = "obj2";
@@ -133,10 +183,10 @@ public class ConfiguredObjectQueryTest e
put(ConfiguredObject.NAME, objectName);
}});
- objects.add(nonMatch);
- objects.add(match);
+ _objects.add(nonMatch);
+ _objects.add(match);
- _query = new ConfiguredObjectQuery(objects, null, String.format("name
= '%s'", objectName));
+ _query = new ConfiguredObjectQuery(_objects, null, String.format("name
= '%s'", objectName));
final List<String> headers = _query.getHeaders();
assertEquals("Unexpected headers",
Lists.newArrayList(ConfiguredObject.ID, ConfiguredObject.NAME), headers);
@@ -151,8 +201,6 @@ public class ConfiguredObjectQueryTest e
public void testQuery_DateInequality() throws Exception
{
- final List<ConfiguredObject<?>> objects = new ArrayList<>();
-
final long now = System.currentTimeMillis();
final UUID objectUuid = UUID.randomUUID();
final long oneDayInMillis = TimeUnit.MILLISECONDS.convert(1,
TimeUnit.DAYS);
@@ -171,10 +219,10 @@ public class ConfiguredObjectQueryTest e
put(DATE_ATTR, tomorrow);
}});
- objects.add(nonMatch);
- objects.add(match);
+ _objects.add(nonMatch);
+ _objects.add(match);
- _query = new ConfiguredObjectQuery(objects,
+ _query = new ConfiguredObjectQuery(_objects,
String.format("%s,%s",
ConfiguredObject.ID, DATE_ATTR),
String.format("%s > NOW()",
DATE_ATTR));
@@ -188,11 +236,10 @@ public class ConfiguredObjectQueryTest e
public void testQuery_DateEquality() throws Exception
{
- final List<ConfiguredObject<?>> objects = new ArrayList<>();
-
final long now = System.currentTimeMillis();
final Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(now);
+ String nowIso8601Str = DatatypeConverter.printDateTime(calendar);
final UUID objectUuid = UUID.randomUUID();
@@ -208,12 +255,40 @@ public class ConfiguredObjectQueryTest e
put(DATE_ATTR, new Date(now));
}});
- objects.add(nonMatch);
- objects.add(match);
+ _objects.add(nonMatch);
+ _objects.add(match);
+
+ _query = new ConfiguredObjectQuery(_objects,
+ String.format("%s,%s",
ConfiguredObject.ID, DATE_ATTR),
+ String.format("%s = TO_DATE('%s')",
DATE_ATTR,
+ nowIso8601Str));
+
+ List<List<Object>> results = _query.getResults();
+ assertEquals("Unexpected number of results", 1, results.size());
+
+ final Iterator<List<Object>> iterator = results.iterator();
+ List<Object> row = iterator.next();
+ assertEquals("Unexpected row", objectUuid, row.get(0));
+ }
+
+ public void testQuery_DateExpressions() throws Exception
+ {
+ final UUID objectUuid = UUID.randomUUID();
+
+ ConfiguredObject match = createCO(new HashMap<String, Object>()
+ {{
+ put(ConfiguredObject.ID, objectUuid);
+ put(DATE_ATTR, new Date(0));
+ }});
+
+ _objects.add(match);
- _query = new ConfiguredObjectQuery(objects,
+ _query = new ConfiguredObjectQuery(_objects,
String.format("%s,%s",
ConfiguredObject.ID, DATE_ATTR),
- String.format("%s = TO_DATE('%s')",
DATE_ATTR, DatatypeConverter.printDateTime(calendar)));
+ String.format("%s =
DATE_ADD(TO_DATE('%s'), '%s')",
+ DATE_ATTR,
+
"1970-01-01T10:00:00Z",
+ "-PT10H"));
List<List<Object>> results = _query.getResults();
assertEquals("Unexpected number of results", 1, results.size());
@@ -223,6 +298,72 @@ public class ConfiguredObjectQueryTest e
assertEquals("Unexpected row", objectUuid, row.get(0));
}
+ public void testDateToString() throws Exception
+ {
+ final UUID objectUuid = UUID.randomUUID();
+
+ ConfiguredObject match = createCO(new HashMap<String, Object>()
+ {{
+ put(ConfiguredObject.ID, objectUuid);
+ put(DATE_ATTR, new Date(0));
+ }});
+
+ _objects.add(match);
+
+ _query = new ConfiguredObjectQuery(_objects,
+ String.format("%s, TO_STRING(%s)",
ConfiguredObject.ID, DATE_ATTR),
+ null);
+
+ List<List<Object>> results = _query.getResults();
+ assertEquals("Unexpected number of results", 1, results.size());
+
+ final Iterator<List<Object>> iterator = results.iterator();
+ List<Object> row = iterator.next();
+ assertEquals("Unexpected row", Lists.newArrayList(objectUuid,
"1970-01-01T00:00:00Z"), row);
+ }
+
+ public void testDateToFormattedString() throws Exception
+ {
+ final UUID objectUuid = UUID.randomUUID();
+
+ ConfiguredObject match = createCO(new HashMap<String, Object>()
+ {{
+ put(ConfiguredObject.ID, objectUuid);
+ put(DATE_ATTR, new Date(0));
+ }});
+
+ _objects.add(match);
+
+ _query = new ConfiguredObjectQuery(_objects,
+ String.format("%s,
TO_STRING(%s,'%s', 'UTC')",
+ ConfiguredObject.ID,
+ DATE_ATTR,
+ "%1$tF %1$tZ"),
+ null);
+
+ List<List<Object>> results = _query.getResults();
+ assertEquals("Unexpected number of results", 1, results.size());
+
+ final Iterator<List<Object>> iterator = results.iterator();
+ List<Object> row = iterator.next();
+ assertEquals("Unexpected row", Lists.newArrayList(objectUuid,
"1970-01-01 UTC"), row);
+ }
+
+ public void testFunctionActualParameterMismatch() throws Exception
+ {
+ try
+ {
+ _query = new ConfiguredObjectQuery(_objects,
+ "TO_STRING() /*Too few
arguments*/ ",
+ null);
+ fail("Exception not thrown");
+ }
+ catch (SelectorParsingException e)
+ {
+ // PASS
+ }
+ }
+
private ConfiguredObject createCO(final HashMap<String, Object> map)
{
ConfiguredObject object = mock(ConfiguredObject.class);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]