Repository: olingo-odata4
Updated Branches:
  refs/heads/master 824c174d7 -> 6553e9508


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6553e950/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ApplyParserTest.java
----------------------------------------------------------------------
diff --git 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ApplyParserTest.java
 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ApplyParserTest.java
new file mode 100644
index 0000000..87a4281
--- /dev/null
+++ 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ApplyParserTest.java
@@ -0,0 +1,676 @@
+/*
+ * 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.olingo.server.core.uri.parser;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.edmx.EdmxReference;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriInfoKind;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceKind;
+import org.apache.olingo.server.api.uri.queryoption.ApplyItem;
+import org.apache.olingo.server.api.uri.queryoption.ApplyOption;
+import org.apache.olingo.server.api.uri.queryoption.apply.Aggregate;
+import org.apache.olingo.server.api.uri.queryoption.apply.AggregateExpression;
+import 
org.apache.olingo.server.api.uri.queryoption.apply.AggregateExpression.StandardMethod;
+import org.apache.olingo.server.api.uri.queryoption.apply.BottomTop;
+import org.apache.olingo.server.api.uri.queryoption.apply.BottomTop.Method;
+import org.apache.olingo.server.api.uri.queryoption.apply.Compute;
+import org.apache.olingo.server.api.uri.queryoption.apply.ComputeExpression;
+import org.apache.olingo.server.api.uri.queryoption.apply.Concat;
+import org.apache.olingo.server.api.uri.queryoption.apply.CustomFunction;
+import org.apache.olingo.server.api.uri.queryoption.apply.Expand;
+import org.apache.olingo.server.api.uri.queryoption.apply.Filter;
+import org.apache.olingo.server.api.uri.queryoption.apply.GroupBy;
+import org.apache.olingo.server.api.uri.queryoption.apply.GroupByItem;
+import org.apache.olingo.server.api.uri.queryoption.apply.Identity;
+import org.apache.olingo.server.api.uri.queryoption.apply.Search;
+import 
org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
+import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
+import org.apache.olingo.server.core.uri.UriInfoImpl;
+import org.apache.olingo.server.core.uri.testutil.ExpandValidator;
+import org.apache.olingo.server.core.uri.testutil.FilterValidator;
+import org.apache.olingo.server.core.uri.testutil.ResourceValidator;
+import org.apache.olingo.server.core.uri.testutil.TestUriValidator;
+import org.apache.olingo.server.core.uri.testutil.TestValidator;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
+import org.apache.olingo.server.tecsvc.provider.ComplexTypeProvider;
+import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
+import org.apache.olingo.server.tecsvc.provider.EntityTypeProvider;
+import org.apache.olingo.server.tecsvc.provider.FunctionProvider;
+import org.apache.olingo.server.tecsvc.provider.PropertyProvider;
+import org.junit.Test;
+
+/** Tests of the $apply parser inspired by the ABNF test cases. */
+public class ApplyParserTest {
+
+  private static final OData odata = OData.newInstance();
+  private static final Edm edm = odata.createServiceMetadata(
+      new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
+
+  @Test
+  public void aggregate() throws Exception {
+    parse("ESTwoKeyNav", "aggregate(PropertyInt16 with sum as s)")
+        .is(Aggregate.class)
+        .goAggregate(0).isStandardMethod(StandardMethod.SUM).isAlias("s")
+        .goExpression().goPath().first().isPrimitiveProperty("PropertyInt16", 
PropertyProvider.nameInt16, false);
+    parse("ESTwoKeyNav", "aggregate(PropertyInt16 with min as m)")
+        .goAggregate(0).isStandardMethod(StandardMethod.MIN).isAlias("m");
+    parse("ESTwoKeyNav", "aggregate(PropertyInt16 with max as m)")
+        .goAggregate(0).isStandardMethod(StandardMethod.MAX).isAlias("m");
+    parse("ESTwoKeyNav", "aggregate(PropertyInt16 with average as a)")
+        .goAggregate(0).isStandardMethod(StandardMethod.AVERAGE).isAlias("a");
+    parse("ESTwoKeyNav", "aggregate(PropertyInt16 with countdistinct as c)")
+        
.goAggregate(0).isStandardMethod(StandardMethod.COUNT_DISTINCT).isAlias("c");
+    parse("ESTwoKeyNav", "aggregate(PropertyInt16 with custom.aggregate as c)")
+        .is(Aggregate.class)
+        .goAggregate(0).isCustomMethod(new FullQualifiedName("custom", 
"aggregate")).isAlias("c");
+
+    parseEx("ESTwoKeyNav", "aggregate()")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    parseEx("ESTwoKeyNav", "aggregate(PropertyInt16)")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    parseEx("ESTwoKeyNav", "aggregate(PropertyInt16 with sum)")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    parseEx("ESTwoKeyNav", "aggregate(PropertyInt16 as s)")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    parseEx("ESTwoKeyNav", "aggregate(PropertyInt16 with SUM as s)")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    parseEx("ESTwoKeyNav", "aggregate(PropertyString with countdistinct as 
PropertyInt16)")
+        .isExSemantic(UriParserSemanticException.MessageKeys.IS_PROPERTY);
+  }
+
+  @Test
+  public void aggregateExpression() throws Exception {
+    parse("ESTwoKeyNav", "aggregate(PropertyInt16 mul 
PropertyComp/PropertyInt16 with sum as s)")
+        .is(Aggregate.class)
+        .goAggregate(0).isStandardMethod(StandardMethod.SUM)
+        .goExpression().isBinary(BinaryOperatorKind.MUL)
+        .left().goPath().first().isPrimitiveProperty("PropertyInt16", 
PropertyProvider.nameInt16, false)
+        .goUpFilterValidator().root()
+        .right().goPath().first().isComplexProperty("PropertyComp", 
ComplexTypeProvider.nameCTPrimComp, false)
+        .n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, 
false);
+
+    parse("ESTwoKeyNav",
+        "aggregate(NavPropertyETKeyNavMany(PropertyInt16 mul 
NavPropertyETTwoKeyNavOne/PropertyInt16 with sum as s))")
+        .goAggregate(0)
+        .goInlineAggregateExpression().isStandardMethod(StandardMethod.SUM)
+        .goUpAggregate()
+        .goPath().first().isNavProperty("NavPropertyETKeyNavMany", 
EntityTypeProvider.nameETKeyNav, true);
+
+    parseEx("ESTwoKeyNav", "aggregate((PropertyInt16 mul 2 with sum as s))")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+  }
+
+  @Test
+  public void aggregateCount() throws Exception {
+    parse("ESTwoKeyNav", "aggregate($count as count)")
+        .is(Aggregate.class)
+        .goAggregate(0).goPath().first().isCount();
+
+    parseEx("ESTwoKeyNav", 
"aggregate($count)").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    parseEx("ESTwoKeyNav", "aggregate($count with sum as count)")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+  }
+
+  @Test
+  public void aggregateFrom() throws Exception {
+    parse("ESTwoKeyNav", "aggregate(PropertyInt16 with sum as s from 
CollPropertyComp with average)")
+        .goAggregate(0).isStandardMethod(StandardMethod.SUM)
+        .goFrom(0).isStandardMethod(StandardMethod.AVERAGE)
+        .goExpression().goPath().first()
+        .isComplexProperty("CollPropertyComp", 
ComplexTypeProvider.nameCTPrimComp, true);
+    parse("ESTwoKeyNav",
+        "aggregate(PropertyInt16 with sum as s from CollPropertyComp with 
average from CollPropertyString with max)")
+        .goAggregate(0).isStandardMethod(StandardMethod.SUM)
+        .goFrom(0).isStandardMethod(StandardMethod.AVERAGE)
+        .goUpAggregate().goFrom(1).isStandardMethod(StandardMethod.MAX);
+    parse("ESTwoKeyNav", "aggregate(customAggregate as a from CollPropertyComp 
with average)")
+        .goAggregate(0).goFrom(0).isStandardMethod(StandardMethod.AVERAGE);
+
+    parseEx("ESTwoKeyNav", "aggregate(PropertyInt16 as a from CollPropertyComp 
with average)")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    parseEx("ESTwoKeyNav", "aggregate(PropertyInt16 with sum from 
CollPropertyComp with average)")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+  }
+
+  @Test
+  public void identity() throws Exception {
+    parse("ESTwoKeyNav", "identity").is(Identity.class);
+  }
+
+  @Test
+  public void compute() throws Exception {
+    parse("ESTwoKeyNav", "compute(PropertyInt16 mul 
NavPropertyETKeyNavOne/PropertyInt16 as p)")
+        .is(Compute.class)
+        
.goCompute(0).isAlias("p").goExpression().isBinary(BinaryOperatorKind.MUL)
+        .left().isMember().goPath().isPrimitiveProperty("PropertyInt16", 
PropertyProvider.nameInt16, false);
+    parse("ESTwoKeyNav", "compute(PropertyInt16 mul 2 as p,day(now()) as d)")
+        .goCompute(0).isAlias("p")
+        .goUp().goCompute(1).isAlias("d")
+        .goExpression().isMethod(MethodKind.DAY, 
1).goParameter(0).isMethod(MethodKind.NOW, 0);
+
+    parseEx("ESTwoKeyNav", "compute(PropertyInt16)")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    parseEx("ESTwoKeyNav", "compute(PropertyComp as c)")
+        
.isExSemantic(UriParserSemanticException.MessageKeys.ONLY_FOR_PRIMITIVE_TYPES);
+  }
+
+  @Test
+  public void concat() throws Exception {
+    parse("ESTwoKeyNav", 
"concat(topcount(2,PropertyInt16),bottomcount(2,PropertyInt16))")
+        .is(Concat.class)
+        .goConcat(0).goBottomTop().isMethod(Method.TOP_COUNT)
+        .goUp().goUp()
+        
.goConcat(1).goBottomTop().isMethod(Method.BOTTOM_COUNT).goNumber().isLiteral("2");
+  }
+
+  @Test
+  public void expand() throws Exception {
+    parse("ESTwoKeyNav", "expand(NavPropertyETKeyNavMany,filter(PropertyInt16 
gt 2))")
+        .is(Expand.class).goExpand()
+        .goPath().first().isNavProperty("NavPropertyETKeyNavMany", 
EntityTypeProvider.nameETKeyNav, true)
+        .goUpExpandValidator().isFilterSerialized("<<PropertyInt16> gt <2>>");
+    parse("ESTwoKeyNav",
+        
"expand(NavPropertyETKeyNavMany,expand(NavPropertyETTwoKeyNavMany,filter(PropertyInt16
 gt 2)))")
+        
.is(Expand.class).goExpand().goExpand().isFilterSerialized("<<PropertyInt16> gt 
<2>>");
+    parse("ESTwoKeyNav",
+        
"expand(NavPropertyETKeyNavMany,expand(NavPropertyETTwoKeyNavMany,filter(PropertyInt16
 gt 2)),"
+        + "expand(NavPropertyETTwoKeyNavOne,expand(NavPropertyETKeyNavMany)))")
+        .is(Expand.class).goExpand().goExpand().next().goExpand()
+        .goPath().first().isNavProperty("NavPropertyETKeyNavMany", 
EntityTypeProvider.nameETKeyNav, true);
+  }
+
+  @Test
+  public void search() throws Exception {
+    parse("ESTwoKeyNav", "search(String)").isSearch("'String'");
+  }
+
+  @Test
+  public void filter() throws Exception {
+    parse("ESTwoKeyNav", "filter(PropertyInt16 gt 3)")
+        .is(Filter.class)
+        .goFilter().isBinary(BinaryOperatorKind.GT)
+        .left().isMember().goPath().isPrimitiveProperty("PropertyInt16", 
PropertyProvider.nameInt16, false);
+  }
+
+  @Test
+  public void bottomTop() throws Exception {
+    parse("ESTwoKeyNav", "topcount(2,PropertyInt16)")
+        .goBottomTop().isMethod(Method.TOP_COUNT)
+        
.goNumber().isLiteralType(odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.SByte))
+        .isLiteral("2");
+    parse("ESTwoKeyNav", "topsum(2,PropertyInt16)")
+        .goBottomTop().isMethod(Method.TOP_SUM)
+        
.goValue().isMember().goPath().first().isPrimitiveProperty("PropertyInt16", 
PropertyProvider.nameInt16, false);
+    parse("ESTwoKeyNav", 
"toppercent(2,PropertyInt16)").goBottomTop().isMethod(Method.TOP_PERCENT);
+
+    parse("ESTwoKeyNav", 
"bottomcount(2,PropertyInt16)").goBottomTop().isMethod(Method.BOTTOM_COUNT);
+    parse("ESTwoKeyNav", 
"bottomsum(2,PropertyInt16)").goBottomTop().isMethod(Method.BOTTOM_SUM);
+    parse("ESTwoKeyNav", 
"bottompercent(2,PropertyInt16)").goBottomTop().isMethod(Method.BOTTOM_PERCENT);
+
+    parseEx("ESTwoKeyNav", "bottompercent(1.2,PropertyInt16)")
+        
.isExSemantic(UriParserSemanticException.MessageKeys.TYPES_NOT_COMPATIBLE);
+    parseEx("ESTwoKeyNav", "bottompercent(2,PropertyString)")
+        
.isExSemantic(UriParserSemanticException.MessageKeys.TYPES_NOT_COMPATIBLE);
+  }
+
+  @Test
+  public void customFunction() throws Exception {
+    parse("ESBaseTwoKeyNav", 
"Namespace1_Alias.BFCESBaseTwoKeyNavRTESBaseTwoKey()")
+        
.isCustomFunction(FunctionProvider.nameBFCESBaseTwoKeyNavRTESBaseTwoKey);
+    parse("ESKeyNav(1)/CollPropertyComp", 
"Namespace1_Alias.BFCCollCTPrimCompRTESAllPrim()")
+        .isCustomFunction(FunctionProvider.nameBFCCollCTPrimCompRTESAllPrim);
+
+    parseEx("ESBaseTwoKeyNav", "BFCESBaseTwoKeyNavRTESBaseTwoKey()")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    parseEx("ESBaseTwoKeyNav", 
"Namespace1_Alias.BFCETBaseTwoKeyNavRTETTwoKeyNav()")
+        
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND);
+    parseEx("ESBaseTwoKeyNav", "Namespace1_Alias.BFCCollStringRTESTwoKeyNav()")
+        
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND);
+    parseEx("ESTwoKeyNav", "Namespace1_Alias.BFCESTwoKeyNavRTTwoKeyNav()")
+        
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_MUST_USE_COLLECTIONS);
+  }
+
+  @Test
+  public void groupBy() throws Exception {
+    parse("ESTwoKeyNav", "groupby((PropertyString))")
+        .is(GroupBy.class)
+        .goGroupBy(0).goPath().first().isPrimitiveProperty("PropertyString", 
PropertyProvider.nameString, false);
+    parse("ESTwoKeyNav", "groupby((NavPropertyETKeyNavOne/PropertyInt16))")
+        .is(GroupBy.class)
+        .goGroupBy(0).goPath().first().isNavProperty("NavPropertyETKeyNavOne", 
EntityTypeProvider.nameETKeyNav, false)
+        .n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, 
false);
+    parse("ESTwoKeyNav", 
"groupby((NavPropertyETKeyNavOne/PropertyInt16,PropertyString))")
+        .is(GroupBy.class)
+        .goGroupBy(1).goPath().first().isPrimitiveProperty("PropertyString", 
PropertyProvider.nameString, false);
+    parse("ESTwoKeyNav", 
"groupby((NavPropertyETKeyNavOne/PropertyInt16,NavPropertyETKeyNavOne/PropertyString))");
+    parse("ESTwoKeyNav",
+        
"groupby((NavPropertyETKeyNavOne/PropertyInt16,NavPropertyETKeyNavOne/PropertyString,PropertyString))")
+        .goGroupBy(2).goPath().first().isPrimitiveProperty("PropertyString", 
PropertyProvider.nameString, false);
+  }
+
+  @Test
+  public void groupByAggregate() throws Exception {
+    parse("ESTwoKeyNav", "groupby((PropertyInt16),aggregate(PropertyInt16 with 
sum as s))")
+        .goGroupByOption().goAggregate(0).isStandardMethod(StandardMethod.SUM)
+        .goExpression().goPath().first().isPrimitiveProperty("PropertyInt16", 
PropertyProvider.nameInt16, false);
+    parse("ESTwoKeyNav",
+        
"groupby((NavPropertyETKeyNavOne/PropertyInt16),aggregate(PropertyInt16 with 
average as a))")
+        
.goGroupByOption().goAggregate(0).isStandardMethod(StandardMethod.AVERAGE)
+        .goUp().goUp().goGroupBy(0).goPath()
+        .first().isNavProperty("NavPropertyETKeyNavOne", 
EntityTypeProvider.nameETKeyNav, false)
+        .n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, 
false);
+    parse("ESTwoKeyNav", "groupby((NavPropertyETKeyNavOne/PropertyInt16),"
+        + "aggregate(PropertyInt16 with sum as s,PropertyInt16 with average as 
a))")
+        
.goGroupByOption().goAggregate(1).isStandardMethod(StandardMethod.AVERAGE);
+    parse("ESTwoKeyNav", 
"groupby((PropertyInt16),aggregate(NavPropertyETKeyNavMany/$count as c))")
+        .goGroupByOption().goAggregate(0).goPath().at(1).isCount();
+    parse("ESTwoKeyNav", 
"groupby((PropertyString),aggregate(NavPropertyETKeyNavMany(PropertyInt16 with 
sum as s)))")
+        
.goGroupByOption().goAggregate(0).goInlineAggregateExpression().isStandardMethod(StandardMethod.SUM)
+        .goUpAggregate().goPath().first()
+        .isNavProperty("NavPropertyETKeyNavMany", 
EntityTypeProvider.nameETKeyNav, true);
+    parse("ESTwoKeyNav",
+        
"groupby((NavPropertyETKeyNavOne/PropertyInt16,NavPropertyETKeyNavOne/PropertyString),"
+        + "aggregate(PropertyInt16 with sum as s))")
+        .goGroupBy(1).goPath().at(1).isPrimitiveProperty("PropertyString", 
PropertyProvider.nameString, false);
+    parse("ESTwoKeyNav",
+        
"groupby((NavPropertyETKeyNavOne/PropertyInt16,NavPropertyETKeyNavOne/PropertyString),"
+        + "aggregate(PropertyInt16 with sum as s from 
NavPropertyETKeyNavOne/PropertyInt16 with average))")
+        
.goGroupByOption().goAggregate(0).goFrom(0).isStandardMethod(StandardMethod.AVERAGE);
+    parse("ESTwoKeyNav", 
"groupby((NavPropertyETKeyNavOne),aggregate(CollPropertyComp(PropertyInt16 with 
sum as s)))");
+    parse("ESTwoKeyNav",
+        "groupby((NavPropertyETTwoKeyNavOne/PropertyInt16),"
+        + "topcount(2,PropertyInt16)/aggregate(PropertyInt16 with sum as s))")
+        .goGroupByOption()
+        .at(0).goBottomTop().isMethod(Method.TOP_COUNT)
+        .goUp().at(1).goAggregate(0).isStandardMethod(StandardMethod.SUM);
+  }
+
+  @Test
+  public void groupByRollUp() throws Exception {
+    parse("ESTwoKeyNav",
+        
"groupby((rollup(NavPropertyETKeyNavOne/PropertyInt16,NavPropertyETKeyNavOne/PropertyString),"
+        + 
"rollup(NavPropertyETKeyNavOne/NavPropertyETTwoKeyNavOne/PropertyInt16,"
+        + 
"NavPropertyETTwoKeyNavOne/PropertyString),NavPropertyETTwoKeyNavOne/PropertyInt16),"
+        + "aggregate(PropertyInt16 with sum as s))")
+        .goGroupBy(1).goRollup(1).goPath()
+        .first().isNavProperty("NavPropertyETTwoKeyNavOne", 
EntityTypeProvider.nameETTwoKeyNav, false)
+        .n().isPrimitiveProperty("PropertyString", 
PropertyProvider.nameString, false);
+
+    parse("ESTwoKeyNav",
+        
"groupby((rollup($all,NavPropertyETKeyNavOne/PropertyInt16,NavPropertyETKeyNavOne/PropertyString),"
+        + "NavPropertyETTwoKeyNavOne/PropertyString),"
+        + "aggregate(PropertyInt16 with sum as s from 
NavPropertyETTwoKeyNavOne/PropertyInt16 with average "
+        + "from NavPropertyETTwoKeyNavOne/PropertyString with average))")
+        
.goGroupBy(0).isRollupAll().goUp().goGroupByOption().goAggregate(0).goFrom(1)
+        .isStandardMethod(StandardMethod.AVERAGE).goExpression().goPath().at(1)
+        .isPrimitiveProperty("PropertyString", PropertyProvider.nameString, 
false);
+  }
+
+  @Test
+  public void groupBySpecial() throws Exception {
+    parse("ESTwoKeyNav", 
"groupby((NavPropertyETTwoKeyNavOne/PropertyInt16),aggregate(customAggregate))")
+        .is(GroupBy.class)
+        .goGroupByOption().goAggregate(0)
+        .goPath().first().isUriPathInfoKind(UriResourceKind.primitiveProperty);
+
+    parse("ESTwoKeyNav",
+        "groupby((PropertyString),aggregate(NavPropertyETKeyNavMany/$count as 
c,"
+        + "NavPropertyETKeyNavMany(PropertyInt16 with sum as s)))")
+        .is(GroupBy.class)
+        
.goGroupByOption().goAggregate(0).isAlias("c").goPath().at(1).isCount();
+    parse("ESTwoKeyNav",
+        "groupby((PropertyString),aggregate(NavPropertyETKeyNavMany($count as 
c),"
+        + "NavPropertyETKeyNavMany(PropertyInt16 with sum as s)))")
+        .is(GroupBy.class)
+        .goGroupByOption().goAggregate(0).goInlineAggregateExpression()
+        .isAlias("c").goPath().first().isCount();
+    parse("ESTwoKeyNav",
+        "groupby((NavPropertyETKeyNavOne/PropertyString),"
+        + "aggregate(PropertyInt16 with sum as s,customAggregate))")
+        .is(GroupBy.class)
+        .goGroupByOption().goAggregate(1).isStandardMethod(null).isAlias(null)
+        .goPath().first().isUriPathInfoKind(UriResourceKind.primitiveProperty);
+    parse("ESTwoKeyNav",
+        
"groupby((PropertyString),aggregate(NavPropertyETKeyNavMany(PropertyInt16 with 
sum as s),"
+        + "NavPropertyETKeyNavMany/customAggregate))")
+        .is(GroupBy.class)
+        .goGroupByOption().goAggregate(1)
+        .goPath().at(1).isUriPathInfoKind(UriResourceKind.primitiveProperty);
+    parse("ESTwoKeyNav",
+        
"groupby((PropertyString),aggregate(NavPropertyETKeyNavMany(PropertyInt16 with 
sum as s),"
+        + "NavPropertyETKeyNavMany(PropertyInt16 with average as a)))")
+        .is(GroupBy.class)
+        .goGroupByOption().goAggregate(0).goInlineAggregateExpression()
+        .isStandardMethod(StandardMethod.SUM).isAlias("s")
+        .goUpAggregate().goUp().goAggregate(1).goInlineAggregateExpression()
+        .isStandardMethod(StandardMethod.AVERAGE).isAlias("a");
+  }
+
+  @Test
+  public void sequence() throws Exception {
+    parse("ESTwoKeyNav", "identity/identity/identity")
+        
.at(0).is(Identity.class).at(1).is(Identity.class).at(2).is(Identity.class);
+
+    parse("ESTwoKeyNav", "filter(PropertyInt16 le 1)/aggregate(PropertyInt16 
with sum as s)")
+        .at(0).is(Filter.class)
+        
.at(1).is(Aggregate.class).goAggregate(0).isStandardMethod(StandardMethod.SUM).isAlias("s");
+    parse("ESTwoKeyNav",
+        "groupby((NavPropertyETKeyNavOne),aggregate(PropertyInt16 with sum as 
s))/"
+        + "aggregate(s with average as a)")
+        
.at(1).goAggregate(0).isStandardMethod(StandardMethod.AVERAGE).isAlias("a");
+    parse("ESTwoKeyNav",
+        "filter(PropertyInt16 ge 1)/"
+        + 
"groupby((NavPropertyETKeyNavOne/PropertyString),aggregate(PropertyInt16 with 
sum as s))")
+        .at(0).is(Filter.class)
+        .at(1).is(GroupBy.class);
+    parse("ESTwoKeyNav",
+        
"groupby((NavPropertyETKeyNavOne/PropertyString),aggregate(PropertyInt16 with 
sum as s))/"
+        + "filter(s ge 
10)/concat(identity,groupby((NavPropertyETKeyNavOne/PropertyString),"
+        + "aggregate(s with sum as t)))")
+        .at(0).is(GroupBy.class)
+        .at(1).is(Filter.class)
+        .at(2).is(Concat.class).goConcat(0).is(Identity.class);
+    parse("ESTwoKeyNav",
+        
"groupby((NavPropertyETKeyNavOne/PropertyString),aggregate(PropertyInt16 with 
sum as s))/"
+        + "filter(s ge 
10)/groupby((rollup(NavPropertyETKeyNavOne/PropertyString,"
+        + 
"NavPropertyETKeyNavOne/PropertyCompAllPrim/PropertyDuration)),aggregate(s with 
sum as t))")
+        .at(0).is(GroupBy.class)
+        .at(1).is(Filter.class)
+        .at(2).is(GroupBy.class).goGroupBy(0).goRollup(1).goPath().at(2)
+        .isPrimitiveProperty("PropertyDuration", 
PropertyProvider.nameDuration, false);
+    parse("ESTwoKeyNav",
+        
"groupby((NavPropertyETKeyNavOne/PropertyString),aggregate(PropertyInt16 with 
sum as s))/"
+        + "concat(filter(s ge 
10),groupby((NavPropertyETKeyNavOne/PropertyString),"
+        + "aggregate(s with sum as t)))")
+        .at(0).is(GroupBy.class)
+        .at(1).is(Concat.class).goConcat(1).is(GroupBy.class);
+
+    parse("ESTwoKeyNav",
+        "filter(PropertyInt16 eq 1)/expand(NavPropertyETKeyNavMany,filter(not 
PropertyCompAllPrim/PropertyBoolean))/"
+        + "groupby((NavPropertyETKeyNavOne/PropertyInt16),"
+        + "aggregate(NavPropertyETKeyNavMany(PropertyInt16 with sum as s)))")
+        .at(0).is(Filter.class)
+        .at(1).is(Expand.class)
+        .at(2).is(GroupBy.class);
+  }
+
+  private ApplyValidator parse(final String path, final String apply)
+      throws UriParserException, UriValidationException {
+    final UriInfo uriInfo = new Parser(edm, odata).parseUri(path, "$apply=" + 
apply, null);
+    return new ApplyValidator(uriInfo.getApplyOption());
+  }
+
+  private TestUriValidator parseEx(final String path, final String apply) {
+    return new TestUriValidator().setEdm(edm).runEx(path, "$apply=" + apply);
+  }
+
+  private final class ApplyValidator implements TestValidator {
+
+    private final ApplyOption applyOption;
+    private final ApplyValidator previous;
+    private ApplyItem applyItem;
+
+    protected ApplyValidator(final ApplyOption applyOption) {
+      this(applyOption, null);
+    }
+
+    private ApplyValidator(final ApplyOption applyOption, final ApplyValidator 
previous) {
+      this.applyOption = applyOption;
+      this.previous = previous;
+      at(0);
+    }
+
+    public ApplyValidator at(final int index) {
+      assertTrue(index < applyOption.getApplyItems().size());
+      applyItem = applyOption.getApplyItems().get(index);
+      return this;
+    }
+
+    public ApplyValidator is(final Class<? extends ApplyItem> cls) {
+      assertNotNull(applyItem);
+      assertTrue(cls.isAssignableFrom(applyItem.getClass()));
+      return this;
+    }
+
+    public AggregateValidator goAggregate(final int index) {
+      is(Aggregate.class);
+      assertTrue(index < ((Aggregate) applyItem).getExpressions().size());
+      return new AggregateValidator(((Aggregate) 
applyItem).getExpressions().get(index), this);
+    }
+
+    public ExpandValidator goExpand() {
+      is(Expand.class);
+      return new ExpandValidator().setUpValidator(this).setExpand(((Expand) 
applyItem).getExpandOption());
+    }
+
+    public FilterValidator goFilter() {
+      is(Filter.class);
+      return new FilterValidator().setFilter(((Filter) 
applyItem).getFilterOption());
+    }
+
+    public BottomTopValidator goBottomTop() {
+      is(BottomTop.class);
+      return new BottomTopValidator((BottomTop) applyItem, this);
+    }
+
+    public ApplyValidator isCustomFunction(final FullQualifiedName function) {
+      is(CustomFunction.class);
+      assertEquals(function, ((CustomFunction) 
applyItem).getFunction().getFullQualifiedName());
+      return this;
+    }
+
+    public ApplyValidator isSearch(final String serializedSearch) {
+      is(Search.class);
+      assertEquals(serializedSearch, ((Search) 
applyItem).getSearchOption().getSearchExpression().toString());
+      return this;
+    }
+
+    public ApplyValidator goConcat(final int index) {
+      is(Concat.class);
+      assertTrue(index < ((Concat) applyItem).getApplyOptions().size());
+      return new ApplyValidator(((Concat) 
applyItem).getApplyOptions().get(index), this);
+    }
+
+    public ComputeValidator goCompute(final int index) {
+      is(Compute.class);
+      assertTrue(index < ((Compute) applyItem).getExpressions().size());
+      return new ComputeValidator(((Compute) 
applyItem).getExpressions().get(index), this);
+    }
+
+    public GroupByValidator goGroupBy(final int index) {
+      is(GroupBy.class);
+      assertTrue(index < ((GroupBy) applyItem).getGroupByItems().size());
+      return new GroupByValidator(((GroupBy) 
applyItem).getGroupByItems().get(index), this);
+    }
+
+    public ApplyValidator goGroupByOption() {
+      is(GroupBy.class);
+      assertNotNull(((GroupBy) applyItem).getApplyOption());
+      return new ApplyValidator(((GroupBy) applyItem).getApplyOption(), this);
+    }
+
+    public ApplyValidator goUp() {
+      return previous;
+    }
+  }
+
+  private final class AggregateValidator implements TestValidator {
+
+    private final AggregateExpression aggregateExpression;
+    private final TestValidator previous;
+
+    protected AggregateValidator(final AggregateExpression 
aggregateExpression, final TestValidator previous) {
+      this.aggregateExpression = aggregateExpression;
+      this.previous = previous;
+    }
+
+    public AggregateValidator isStandardMethod(final 
AggregateExpression.StandardMethod method) {
+      assertNotNull(aggregateExpression);
+      assertEquals(method, aggregateExpression.getStandardMethod());
+      return this;
+    }
+
+    public AggregateValidator isCustomMethod(final FullQualifiedName method) {
+      assertNotNull(aggregateExpression);
+      assertEquals(method, aggregateExpression.getCustomMethod());
+      return this;
+    }
+
+    public AggregateValidator isAlias(final String alias) {
+      assertNotNull(aggregateExpression);
+      assertEquals(alias, aggregateExpression.getAlias());
+      return this;
+    }
+
+    public FilterValidator goExpression() {
+      assertNotNull(aggregateExpression);
+      assertNotNull(aggregateExpression.getExpression());
+      return new FilterValidator().setValidator(this).setEdm(edm)
+          .setExpression(aggregateExpression.getExpression());
+    }
+
+    public ResourceValidator goPath() {
+      assertNotNull(aggregateExpression);
+      assertFalse(aggregateExpression.getPath().isEmpty());
+      UriInfoImpl resource = new UriInfoImpl().setKind(UriInfoKind.resource);
+      for (final UriResource segment : aggregateExpression.getPath()) {
+        resource.addResourcePart(segment);
+      }
+      return new 
ResourceValidator().setUpValidator(this).setEdm(edm).setUriInfoPath(resource);
+    }
+
+    public AggregateValidator goInlineAggregateExpression() {
+      return new 
AggregateValidator(aggregateExpression.getInlineAggregateExpression(), this);
+    }
+
+    public AggregateValidator goFrom(final int index) {
+      assertTrue(index < aggregateExpression.getFrom().size());
+      return new AggregateValidator(aggregateExpression.getFrom().get(index), 
this);
+    }
+
+    public AggregateValidator goUpAggregate() {
+      return (AggregateValidator) previous;
+    }
+
+    public ApplyValidator goUp() {
+      return (ApplyValidator) previous;
+    }
+  }
+
+  private final class BottomTopValidator implements TestValidator {
+
+    private final BottomTop item;
+    private final ApplyValidator previous;
+
+    private BottomTopValidator(final BottomTop item, final ApplyValidator 
previous) {
+      this.item = item;
+      this.previous = previous;
+    }
+
+    public BottomTopValidator isMethod(final BottomTop.Method method) {
+      assertEquals(method, item.getMethod());
+      return this;
+    }
+
+    public FilterValidator goNumber() {
+      assertNotNull(item.getNumber());
+      return new 
FilterValidator().setValidator(this).setEdm(edm).setExpression(item.getNumber());
+    }
+
+    public FilterValidator goValue() {
+      assertNotNull(item.getValue());
+      return new 
FilterValidator().setValidator(this).setEdm(edm).setExpression(item.getValue());
+    }
+
+    public ApplyValidator goUp() {
+      return previous;
+    }
+  }
+
+  private final class ComputeValidator implements TestValidator {
+
+    private final ComputeExpression item;
+    private final ApplyValidator previous;
+
+    private ComputeValidator(final ComputeExpression item, final 
ApplyValidator previous) {
+      this.item = item;
+      this.previous = previous;
+    }
+
+    public ComputeValidator isAlias(final String alias) {
+      assertEquals(alias, item.getAlias());
+      return this;
+    }
+
+    public FilterValidator goExpression() {
+      assertNotNull(item.getExpression());
+      return new 
FilterValidator().setValidator(this).setEdm(edm).setExpression(item.getExpression());
+    }
+
+    public ApplyValidator goUp() {
+      return previous;
+    }
+  }
+
+  private final class GroupByValidator implements TestValidator {
+
+    private final GroupByItem item;
+    private final TestValidator previous;
+
+    private GroupByValidator(final GroupByItem item, final TestValidator 
previous) {
+      this.item = item;
+      this.previous = previous;
+    }
+
+    public ResourceValidator goPath() {
+      assertFalse(item.getPath().isEmpty());
+      UriInfoImpl resource = new UriInfoImpl().setKind(UriInfoKind.resource);
+      for (final UriResource segment : item.getPath()) {
+        resource.addResourcePart(segment);
+      }
+      return new 
ResourceValidator().setUpValidator(this).setEdm(edm).setUriInfoPath(resource);
+    }
+
+    public GroupByValidator isRollupAll() {
+      assertTrue(item.isRollupAll());
+      return this;
+    }
+
+    public GroupByValidator goRollup(final int index) {
+      assertTrue(index < item.getRollup().size());
+      return new GroupByValidator(item.getRollup().get(index), this);
+    }
+
+    public ApplyValidator goUp() {
+      return (ApplyValidator) previous;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6553e950/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java
----------------------------------------------------------------------
diff --git 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java
 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java
index f64a711..789e65f 100644
--- 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java
+++ 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java
@@ -88,16 +88,17 @@ public class UriValidatorTest {
   private static final String QO_SKIP = "$skip=3";
   private static final String QO_SKIPTOKEN = "$skiptoken=123";
   private static final String QO_TOP = "$top=1";
+  private static final String QO_APPLY = "$apply=identity";
 
   private final String[][] urisWithValidSystemQueryOptions = {
       { URI_ALL, QO_FILTER }, { URI_ALL, QO_FORMAT }, { URI_ALL, QO_EXPAND }, 
{ URI_ALL, QO_COUNT },
       { URI_ALL, QO_ORDERBY }, { URI_ALL, QO_SEARCH }, { URI_ALL, QO_SELECT }, 
{ URI_ALL, QO_SKIP },
-      { URI_ALL, QO_SKIPTOKEN }, { URI_ALL, QO_TOP },
+      { URI_ALL, QO_SKIPTOKEN }, { URI_ALL, QO_TOP }, { URI_ALL, QO_APPLY },
 
       { URI_CROSSJOIN, QO_FILTER }, { URI_CROSSJOIN, QO_FORMAT },
       { URI_CROSSJOIN, QO_EXPAND }, { URI_CROSSJOIN, QO_COUNT }, { 
URI_CROSSJOIN, QO_ORDERBY },
       { URI_CROSSJOIN, QO_SEARCH }, { URI_CROSSJOIN, QO_SELECT }, { 
URI_CROSSJOIN, QO_SKIP },
-      { URI_CROSSJOIN, QO_SKIPTOKEN }, { URI_CROSSJOIN, QO_TOP },
+      { URI_CROSSJOIN, QO_SKIPTOKEN }, { URI_CROSSJOIN, QO_TOP }, { 
URI_CROSSJOIN, QO_APPLY },
 
       { URI_ENTITY_ID, QO_ID, QO_FORMAT }, { URI_ENTITY_ID, QO_ID }, { 
URI_ENTITY_ID, QO_ID, QO_EXPAND },
       { URI_ENTITY_ID, QO_ID, QO_SELECT },
@@ -109,7 +110,7 @@ public class UriValidatorTest {
       { URI_ENTITY_SET, QO_FILTER }, { URI_ENTITY_SET, QO_FORMAT }, { 
URI_ENTITY_SET, QO_EXPAND },
       { URI_ENTITY_SET, QO_COUNT }, { URI_ENTITY_SET, QO_ORDERBY }, { 
URI_ENTITY_SET, QO_SEARCH },
       { URI_ENTITY_SET, QO_SELECT }, { URI_ENTITY_SET, QO_SKIP }, { 
URI_ENTITY_SET, QO_SKIPTOKEN },
-      { URI_ENTITY_SET, QO_TOP },
+      { URI_ENTITY_SET, QO_TOP }, { URI_ENTITY_SET, QO_APPLY },
 
       { URI_ENTITY_SET_COUNT, QO_FILTER }, { URI_ENTITY_SET_COUNT, QO_SEARCH },
 
@@ -127,7 +128,7 @@ public class UriValidatorTest {
       { URI_PROPERTY_COMPLEX_COLLECTION, QO_EXPAND }, { 
URI_PROPERTY_COMPLEX_COLLECTION, QO_COUNT },
       { URI_PROPERTY_COMPLEX_COLLECTION, QO_ORDERBY }, { 
URI_PROPERTY_COMPLEX_COLLECTION, QO_SELECT },
       { URI_PROPERTY_COMPLEX_COLLECTION, QO_SKIP }, { 
URI_PROPERTY_COMPLEX_COLLECTION, QO_SKIPTOKEN },
-      { URI_PROPERTY_COMPLEX_COLLECTION, QO_TOP },
+      { URI_PROPERTY_COMPLEX_COLLECTION, QO_TOP }, { 
URI_PROPERTY_COMPLEX_COLLECTION, QO_APPLY },
 
       { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_FILTER },
 
@@ -149,12 +150,12 @@ public class UriValidatorTest {
       { URI_NAV_ENTITY_SET, QO_FILTER }, { URI_NAV_ENTITY_SET, QO_FORMAT }, { 
URI_NAV_ENTITY_SET, QO_EXPAND },
       { URI_NAV_ENTITY_SET, QO_COUNT }, { URI_NAV_ENTITY_SET, QO_ORDERBY },
       { URI_NAV_ENTITY_SET, QO_SEARCH }, { URI_NAV_ENTITY_SET, QO_SELECT }, { 
URI_NAV_ENTITY_SET, QO_SKIP },
-      { URI_NAV_ENTITY_SET, QO_SKIPTOKEN }, { URI_NAV_ENTITY_SET, QO_TOP },
+      { URI_NAV_ENTITY_SET, QO_SKIPTOKEN }, { URI_NAV_ENTITY_SET, QO_TOP }, { 
URI_NAV_ENTITY_SET, QO_APPLY },
 
       { URI_FI_ENTITY_SET, QO_FILTER }, { URI_FI_ENTITY_SET, QO_FORMAT }, { 
URI_FI_ENTITY_SET, QO_EXPAND },
       { URI_FI_ENTITY_SET, QO_COUNT }, { URI_FI_ENTITY_SET, QO_ORDERBY }, { 
URI_FI_ENTITY_SET, QO_SEARCH },
       { URI_FI_ENTITY_SET, QO_SELECT }, { URI_FI_ENTITY_SET, QO_SKIP }, { 
URI_FI_ENTITY_SET, QO_SKIPTOKEN },
-      { URI_FI_ENTITY_SET, QO_TOP },
+      { URI_FI_ENTITY_SET, QO_TOP }, { URI_FI_ENTITY_SET, QO_APPLY },
 
       { URI_FI_ENTITY, QO_FORMAT }, { URI_FI_ENTITY, QO_EXPAND }, { 
URI_FI_ENTITY, QO_SELECT },
       { URI_FI_ENTITY_SET_KEY, QO_FORMAT }, { URI_FI_ENTITY_SET_KEY, QO_EXPAND 
}, { URI_FI_ENTITY_SET_KEY, QO_SELECT },
@@ -170,22 +171,23 @@ public class UriValidatorTest {
 
       { URI_BATCH, QO_FILTER }, { URI_BATCH, QO_FORMAT }, { URI_BATCH, QO_ID 
}, { URI_BATCH, QO_EXPAND },
       { URI_BATCH, QO_COUNT }, { URI_BATCH, QO_ORDERBY }, { URI_BATCH, 
QO_SEARCH }, { URI_BATCH, QO_SELECT },
-      { URI_BATCH, QO_SKIP }, { URI_BATCH, QO_SKIPTOKEN }, { URI_BATCH, QO_TOP 
},
+      { URI_BATCH, QO_SKIP }, { URI_BATCH, QO_SKIPTOKEN }, { URI_BATCH, QO_TOP 
}, { URI_BATCH, QO_APPLY },
 
       { URI_CROSSJOIN, QO_ID },
 
       { URI_ENTITY_ID, QO_ID, QO_FILTER },
-      { URI_ENTITY_ID, QO_ID, QO_COUNT }, { URI_ENTITY_ID, QO_ORDERBY }, { 
URI_ENTITY_ID, QO_SEARCH },
+      { URI_ENTITY_ID, QO_ID, QO_COUNT }, { URI_ENTITY_ID, QO_ID, QO_ORDERBY 
}, { URI_ENTITY_ID, QO_ID, QO_SEARCH },
       { URI_ENTITY_ID, QO_ID, QO_SKIP }, { URI_ENTITY_ID, QO_ID, QO_SKIPTOKEN 
}, { URI_ENTITY_ID, QO_ID, QO_TOP },
+      { URI_ENTITY_ID, QO_ID, QO_APPLY },
 
       { URI_METADATA, QO_FILTER }, { URI_METADATA, QO_ID }, { URI_METADATA, 
QO_EXPAND },
       { URI_METADATA, QO_COUNT }, { URI_METADATA, QO_ORDERBY }, { 
URI_METADATA, QO_SEARCH },
       { URI_METADATA, QO_SELECT }, { URI_METADATA, QO_SKIP }, { URI_METADATA, 
QO_SKIPTOKEN },
-      { URI_METADATA, QO_TOP },
+      { URI_METADATA, QO_TOP }, { URI_METADATA, QO_APPLY },
 
       { URI_SERVICE, QO_FILTER }, { URI_SERVICE, QO_ID }, { URI_SERVICE, 
QO_EXPAND }, { URI_SERVICE, QO_COUNT },
       { URI_SERVICE, QO_ORDERBY }, { URI_SERVICE, QO_SEARCH }, { URI_SERVICE, 
QO_SELECT },
-      { URI_SERVICE, QO_SKIP }, { URI_SERVICE, QO_SKIPTOKEN }, { URI_SERVICE, 
QO_TOP },
+      { URI_SERVICE, QO_SKIP }, { URI_SERVICE, QO_SKIPTOKEN }, { URI_SERVICE, 
QO_TOP }, { URI_SERVICE, QO_APPLY },
 
       { URI_ENTITY_SET, QO_ID },
 
@@ -193,26 +195,29 @@ public class UriValidatorTest {
       { URI_ENTITY_SET_COUNT, QO_EXPAND }, { URI_ENTITY_SET_COUNT, QO_COUNT },
       { URI_ENTITY_SET_COUNT, QO_ORDERBY },
       { URI_ENTITY_SET_COUNT, QO_SELECT }, { URI_ENTITY_SET_COUNT, QO_SKIP }, 
{ URI_ENTITY_SET_COUNT, QO_SKIPTOKEN },
-      { URI_ENTITY_SET_COUNT, QO_TOP },
+      { URI_ENTITY_SET_COUNT, QO_TOP }, { URI_ENTITY_SET_COUNT, QO_APPLY },
 
       { URI_ENTITY, QO_FILTER }, { URI_ENTITY, QO_ID }, { URI_ENTITY, QO_COUNT 
}, { URI_ENTITY, QO_ORDERBY },
       { URI_ENTITY, QO_SEARCH }, { URI_ENTITY, QO_SKIP }, { URI_ENTITY, 
QO_SKIPTOKEN }, { URI_ENTITY, QO_TOP },
+      { URI_ENTITY, QO_APPLY },
 
       { URI_MEDIA_STREAM, QO_FILTER }, { URI_MEDIA_STREAM, QO_FORMAT }, { 
URI_MEDIA_STREAM, QO_ID },
       { URI_MEDIA_STREAM, QO_EXPAND }, { URI_MEDIA_STREAM, QO_COUNT }, { 
URI_MEDIA_STREAM, QO_ORDERBY },
       { URI_MEDIA_STREAM, QO_SEARCH }, { URI_MEDIA_STREAM, QO_SELECT }, { 
URI_MEDIA_STREAM, QO_SKIP },
-      { URI_MEDIA_STREAM, QO_SKIPTOKEN }, { URI_MEDIA_STREAM, QO_TOP },
+      { URI_MEDIA_STREAM, QO_SKIPTOKEN }, { URI_MEDIA_STREAM, QO_TOP }, { 
URI_MEDIA_STREAM, QO_APPLY },
 
       { URI_REFERENCES, QO_ID }, { URI_REFERENCES, QO_EXPAND }, { 
URI_REFERENCES, QO_SELECT },
+      { URI_REFERENCES, QO_APPLY },
 
       { URI_REFERENCE, QO_FILTER }, { URI_REFERENCE, QO_ID }, { URI_REFERENCE, 
QO_EXPAND },
       { URI_REFERENCE, QO_COUNT }, { URI_REFERENCE, QO_ORDERBY }, { 
URI_REFERENCE, QO_SEARCH },
       { URI_REFERENCE, QO_SELECT }, { URI_REFERENCE, QO_SKIP }, { 
URI_REFERENCE, QO_SKIPTOKEN },
-      { URI_REFERENCE, QO_TOP },
+      { URI_REFERENCE, QO_TOP }, { URI_REFERENCE, QO_APPLY },
 
       { URI_PROPERTY_COMPLEX, QO_FILTER }, { URI_PROPERTY_COMPLEX, QO_ID }, { 
URI_PROPERTY_COMPLEX, QO_COUNT },
       { URI_PROPERTY_COMPLEX, QO_ORDERBY }, { URI_PROPERTY_COMPLEX, QO_SEARCH 
},
       { URI_PROPERTY_COMPLEX, QO_SKIP }, { URI_PROPERTY_COMPLEX, QO_SKIPTOKEN 
}, { URI_PROPERTY_COMPLEX, QO_TOP },
+      { URI_PROPERTY_COMPLEX, QO_APPLY },
 
       { URI_PROPERTY_COMPLEX_COLLECTION, QO_ID }, { 
URI_PROPERTY_COMPLEX_COLLECTION, QO_SEARCH },
 
@@ -221,16 +226,17 @@ public class UriValidatorTest {
       { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_COUNT }, { 
URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_ORDERBY },
       { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_SEARCH }, { 
URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_SELECT },
       { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_SKIP }, { 
URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_SKIPTOKEN },
-      { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_TOP },
+      { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_TOP }, { 
URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_APPLY },
 
       { URI_PROPERTY_PRIMITIVE, QO_FILTER }, { URI_PROPERTY_PRIMITIVE, QO_ID 
}, { URI_PROPERTY_PRIMITIVE, QO_EXPAND },
       { URI_PROPERTY_PRIMITIVE, QO_COUNT }, { URI_PROPERTY_PRIMITIVE, 
QO_ORDERBY },
       { URI_PROPERTY_PRIMITIVE, QO_SEARCH }, { URI_PROPERTY_PRIMITIVE, 
QO_SELECT },
       { URI_PROPERTY_PRIMITIVE, QO_SKIP }, { URI_PROPERTY_PRIMITIVE, 
QO_SKIPTOKEN },
-      { URI_PROPERTY_PRIMITIVE, QO_TOP },
+      { URI_PROPERTY_PRIMITIVE, QO_TOP }, { URI_PROPERTY_PRIMITIVE, QO_APPLY },
 
       { URI_PROPERTY_PRIMITIVE_COLLECTION, QO_ID }, { 
URI_PROPERTY_PRIMITIVE_COLLECTION, QO_EXPAND },
       { URI_PROPERTY_PRIMITIVE_COLLECTION, QO_SEARCH }, { 
URI_PROPERTY_PRIMITIVE_COLLECTION, QO_SELECT },
+      { URI_PROPERTY_PRIMITIVE_COLLECTION, QO_APPLY },
 
       { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_FORMAT },
       { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_ID }, { 
URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_EXPAND },
@@ -238,20 +244,22 @@ public class UriValidatorTest {
       { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_ORDERBY }, { 
URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_SEARCH },
       { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_SELECT }, { 
URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_SKIP },
       { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_SKIPTOKEN }, { 
URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_TOP },
+      { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_APPLY },
 
       { URI_PROPERTY_PRIMITIVE_VALUE, QO_FILTER }, { 
URI_PROPERTY_PRIMITIVE_VALUE, QO_ID },
       { URI_PROPERTY_PRIMITIVE_VALUE, QO_EXPAND }, { 
URI_PROPERTY_PRIMITIVE_VALUE, QO_COUNT },
       { URI_PROPERTY_PRIMITIVE_VALUE, QO_ORDERBY }, { 
URI_PROPERTY_PRIMITIVE_VALUE, QO_SEARCH },
       { URI_PROPERTY_PRIMITIVE_VALUE, QO_SELECT }, { 
URI_PROPERTY_PRIMITIVE_VALUE, QO_SKIP },
       { URI_PROPERTY_PRIMITIVE_VALUE, QO_SKIPTOKEN }, { 
URI_PROPERTY_PRIMITIVE_VALUE, QO_TOP },
+      { URI_PROPERTY_PRIMITIVE_VALUE, QO_APPLY },
 
       { URI_SINGLETON, QO_FILTER }, { URI_SINGLETON, QO_ID }, { URI_SINGLETON, 
QO_COUNT },
       { URI_SINGLETON, QO_ORDERBY }, { URI_SINGLETON, QO_SEARCH }, { 
URI_SINGLETON, QO_SKIP },
-      { URI_SINGLETON, QO_SKIPTOKEN }, { URI_SINGLETON, QO_TOP },
+      { URI_SINGLETON, QO_SKIPTOKEN }, { URI_SINGLETON, QO_TOP }, { 
URI_SINGLETON, QO_APPLY },
 
       { URI_NAV_ENTITY, QO_FILTER }, { URI_NAV_ENTITY, QO_ID }, { 
URI_NAV_ENTITY, QO_COUNT },
       { URI_NAV_ENTITY, QO_ORDERBY }, { URI_NAV_ENTITY, QO_SEARCH }, { 
URI_NAV_ENTITY, QO_SKIP },
-      { URI_NAV_ENTITY, QO_SKIPTOKEN }, { URI_SINGLETON, QO_TOP },
+      { URI_NAV_ENTITY, QO_SKIPTOKEN }, { URI_NAV_ENTITY, QO_TOP }, { 
URI_NAV_ENTITY, QO_APPLY },
 
       { URI_NAV_ENTITY_SET, QO_ID },
 
@@ -262,7 +270,8 @@ public class UriValidatorTest {
       { URI_FI_ENTITY, QO_SKIPTOKEN }, { URI_FI_ENTITY, QO_TOP },
       { URI_FI_ENTITY_SET_KEY, QO_FILTER }, { URI_FI_ENTITY_SET_KEY, QO_ID }, 
{ URI_FI_ENTITY_SET_KEY, QO_COUNT },
       { URI_FI_ENTITY_SET_KEY, QO_ORDERBY }, { URI_FI_ENTITY_SET_KEY, 
QO_SEARCH },
-      { URI_FI_ENTITY_SET_KEY, QO_SKIP }, { URI_FI_ENTITY_SET_KEY, 
QO_SKIPTOKEN }, { URI_FI_ENTITY_SET_KEY, QO_TOP }
+      { URI_FI_ENTITY_SET_KEY, QO_SKIP }, { URI_FI_ENTITY_SET_KEY, 
QO_SKIPTOKEN }, { URI_FI_ENTITY_SET_KEY, QO_TOP },
+      { URI_FI_ENTITY_SET_KEY, QO_APPLY }
   };
 
   private final String[][] actionWithValidSystemQueryOptions = {
@@ -282,14 +291,14 @@ public class UriValidatorTest {
       { URI_ACTION_COLL_CT, QO_EXPAND }, { URI_ACTION_COLL_CT, QO_COUNT },
       { URI_ACTION_COLL_CT, QO_ORDERBY }, { URI_ACTION_COLL_CT, QO_SELECT },
       { URI_ACTION_COLL_CT, QO_SKIP }, { URI_ACTION_COLL_CT, QO_SKIPTOKEN },
-      { URI_ACTION_COLL_CT, QO_TOP },
+      { URI_ACTION_COLL_CT, QO_TOP }, { URI_ACTION_COLL_CT, QO_APPLY },
       // EntityReturnType
       { URI_ACTION_ENTITY, QO_FORMAT }, { URI_ACTION_ENTITY, QO_EXPAND }, { 
URI_ACTION_ENTITY, QO_SELECT },
       // EntityCollectionReturnType
       { URI_ACTION_ES, QO_FORMAT }, { URI_ACTION_ES, QO_FILTER },
       { URI_ACTION_ES, QO_COUNT }, { URI_ACTION_ES, QO_ORDERBY }, { 
URI_ACTION_ES, QO_SEARCH },
       { URI_ACTION_ES, QO_SELECT }, { URI_ACTION_ES, QO_SKIP }, { 
URI_ACTION_ES, QO_SKIPTOKEN },
-      { URI_ACTION_ES, QO_TOP }
+      { URI_ACTION_ES, QO_TOP }, { URI_ACTION_ES, QO_APPLY }
   };
 
   private final String[][] actionsWithNotValidSystemQueryOptions = {
@@ -298,26 +307,28 @@ public class UriValidatorTest {
       { URI_ACTION_NO_RETURN, QO_EXPAND }, { URI_ACTION_NO_RETURN, QO_COUNT },
       { URI_ACTION_NO_RETURN, QO_ORDERBY }, { URI_ACTION_NO_RETURN, QO_SEARCH 
},
       { URI_ACTION_NO_RETURN, QO_SELECT }, { URI_ACTION_NO_RETURN, QO_SKIP },
-      { URI_ACTION_NO_RETURN, QO_SKIPTOKEN }, { URI_ACTION_NO_RETURN, QO_TOP },
+      { URI_ACTION_NO_RETURN, QO_SKIPTOKEN }, { URI_ACTION_NO_RETURN, QO_TOP 
}, { URI_ACTION_NO_RETURN, QO_APPLY },
       // PrimReturnType
       { URI_ACTION_PRIM, QO_FILTER }, { URI_ACTION_PRIM, QO_ID },
       { URI_ACTION_PRIM, QO_EXPAND }, { URI_ACTION_PRIM, QO_COUNT },
       { URI_ACTION_PRIM, QO_ORDERBY }, { URI_ACTION_PRIM, QO_SEARCH },
       { URI_ACTION_PRIM, QO_SELECT }, { URI_ACTION_PRIM, QO_SKIP },
-      { URI_ACTION_PRIM, QO_SKIPTOKEN }, { URI_ACTION_PRIM, QO_TOP },
+      { URI_ACTION_PRIM, QO_SKIPTOKEN }, { URI_ACTION_PRIM, QO_TOP }, { 
URI_ACTION_PRIM, QO_APPLY },
       // PrimCollectionReturnType
       { URI_ACTION_COLL_PRIM, QO_ID }, { URI_ACTION_COLL_PRIM, QO_EXPAND },
-      { URI_ACTION_COLL_PRIM, QO_SEARCH }, { URI_ACTION_COLL_PRIM, QO_SELECT },
+      { URI_ACTION_COLL_PRIM, QO_SEARCH }, { URI_ACTION_COLL_PRIM, QO_SELECT 
}, { URI_ACTION_COLL_PRIM, QO_APPLY },
       // ComplexReturnType
       { URI_ACTION_CT, QO_FILTER }, { URI_ACTION_CT, QO_ID }, { URI_ACTION_CT, 
QO_COUNT },
       { URI_ACTION_CT, QO_ORDERBY }, { URI_ACTION_CT, QO_SEARCH },
       { URI_ACTION_CT, QO_SKIP }, { URI_ACTION_CT, QO_SKIPTOKEN }, { 
URI_ACTION_CT, QO_TOP },
+      { URI_ACTION_CT, QO_APPLY },
       // ComplexCollectionReturnType
       { URI_ACTION_COLL_CT, QO_ID }, { URI_ACTION_COLL_CT, QO_SEARCH },
       // EntityReturnType
       { URI_ACTION_ENTITY, QO_FILTER }, { URI_ACTION_ENTITY, QO_ID }, { 
URI_ACTION_ENTITY, QO_COUNT },
       { URI_ACTION_ENTITY, QO_ORDERBY }, { URI_ACTION_ENTITY, QO_SEARCH },
       { URI_ACTION_ENTITY, QO_SKIP }, { URI_ACTION_ENTITY, QO_SKIPTOKEN }, { 
URI_ACTION_ENTITY, QO_TOP },
+      { URI_ACTION_ENTITY, QO_APPLY },
       // EntityCollectionReturnType
       { URI_ACTION_ES, QO_ID }
   };

Reply via email to