[OLINGO-545] Count, Skip, Top System Query Options and Server-Driven Paging added to TecSvc

Signed-off-by: Michael Bolz <michael.bolz@sap.com>
This commit is contained in:
Christian Holzer 2015-02-23 09:48:03 +01:00 committed by Michael Bolz
parent 394d0f8169
commit 2ebdea806c
20 changed files with 734 additions and 71 deletions

View File

@ -61,7 +61,24 @@ public class FilterSystemQueryITCase extends AbstractBaseTestITCase {
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
}
@Test
public void testBooleanLiteral() {
ODataRetrieveResponse<ODataEntitySet> response = sendRequest(ES_ALL_PRIM, "PropertyBoolean eq false");
assertEquals(2, response.getBody().getEntities().size());
ODataEntity oDataEntity = response.getBody().getEntities().get(0);
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
oDataEntity = response.getBody().getEntities().get(1);
assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
response = sendRequest(ES_ALL_PRIM, "PropertyBoolean eq true");
assertEquals(1, response.getBody().getEntities().size());
oDataEntity = response.getBody().getEntities().get(0);
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
}
@Test
public void testDateLiteral() {
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "PropertyDate eq 2012-12-03");

View File

@ -0,0 +1,309 @@
/*
* 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.fit.tecsvc.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.net.URI;
import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.client.api.ODataClient;
import org.apache.olingo.client.api.communication.ODataClientErrorException;
import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
import org.apache.olingo.client.api.uri.QueryOption;
import org.apache.olingo.client.core.ODataClientFactory;
import org.apache.olingo.commons.api.domain.CommonODataEntity;
import org.apache.olingo.commons.api.domain.CommonODataEntitySet;
import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.fit.AbstractBaseTestITCase;
import org.apache.olingo.fit.tecsvc.TecSvcConst;
import org.junit.Test;
public class SystemQueryOptionITCas extends AbstractBaseTestITCase {
private static final String PROPERTY_INT16 = "PropertyInt16";
private static final String ES_SERVER_SIDE_PAGING = "ESServerSidePaging";
private static final String ES_ALL_PRIM = "ESAllPrim";
private static final String SERVICE_URI = TecSvcConst.BASE_URI;
@Test
public void testCountSimple() {
CommonODataClient<?> client = getClient();
URI uri = client.newURIBuilder(SERVICE_URI)
.appendEntitySetSegment(ES_ALL_PRIM)
.addQueryOption(QueryOption.COUNT, "true")
.build();
ODataRetrieveResponse<CommonODataEntitySet> response = client.getRetrieveRequestFactory()
.getEntitySetRequest(uri)
.execute();
assertEquals(Integer.valueOf(3), response.getBody().getCount());
assertEquals(3, response.getBody().getEntities().size());
}
@Test
public void testServerSidePagingCount() {
CommonODataClient<?> client = getClient();
URI uri = client.newURIBuilder(SERVICE_URI)
.appendEntitySetSegment(ES_SERVER_SIDE_PAGING)
.addQueryOption(QueryOption.COUNT, "true")
.build();
ODataRetrieveResponse<CommonODataEntitySet> response = client.getRetrieveRequestFactory()
.getEntitySetRequest(uri)
.execute();
assertEquals(10, response.getBody().getEntities().size());
assertEquals(Integer.valueOf(503), response.getBody().getCount());
}
@Test
public void testTopSimple() {
CommonODataClient<?> client = getClient();
URI uri = client.newURIBuilder(SERVICE_URI)
.appendEntitySetSegment(ES_SERVER_SIDE_PAGING)
.addQueryOption(QueryOption.TOP, new Integer(5).toString())
.build();
ODataRetrieveResponse<CommonODataEntitySet> response = client.getRetrieveRequestFactory()
.getEntitySetRequest(uri)
.execute();
assertEquals(5, response.getBody().getEntities().size());
for (int i = 0; i < 5; i++) {
CommonODataEntity entity = response.getBody().getEntities().get(i);
assertEquals(new Integer(i + 1).toString(), entity.getProperty(PROPERTY_INT16).getValue().toString());
}
}
@Test
public void testSkipSimple() {
CommonODataClient<?> client = getClient();
URI uri = client.newURIBuilder(SERVICE_URI)
.appendEntitySetSegment(ES_SERVER_SIDE_PAGING)
.addQueryOption(QueryOption.SKIP, new Integer(5).toString())
.build();
ODataRetrieveResponse<CommonODataEntitySet> response = client.getRetrieveRequestFactory()
.getEntitySetRequest(uri)
.execute();
assertEquals(10, response.getBody().getEntities().size());
for (int i = 0; i < 10; i++) {
CommonODataEntity entity = response.getBody().getEntities().get(i);
assertEquals(new Integer(i + 6).toString(), entity.getProperty(PROPERTY_INT16).getValue().toString());
}
}
@Test
public void testTopNothing() {
CommonODataClient<?> client = getClient();
URI uri = client.newURIBuilder(SERVICE_URI)
.appendEntitySetSegment(ES_SERVER_SIDE_PAGING)
.addQueryOption(QueryOption.TOP, new Integer(20).toString())
.addQueryOption(QueryOption.SKIP, new Integer(503).toString())
.build();
ODataRetrieveResponse<CommonODataEntitySet> response = client.getRetrieveRequestFactory()
.getEntitySetRequest(uri)
.execute();
assertEquals(0, response.getBody().getEntities().size());
}
@Test
public void testSkipNothing() {
CommonODataClient<?> client = getClient();
URI uri = client.newURIBuilder(SERVICE_URI)
.appendEntitySetSegment(ES_SERVER_SIDE_PAGING)
.addQueryOption(QueryOption.SKIP, new Integer(10000).toString())
.build();
ODataRetrieveResponse<CommonODataEntitySet> response = client.getRetrieveRequestFactory()
.getEntitySetRequest(uri)
.execute();
assertEquals(0, response.getBody().getEntities().size());
}
@Test
public void testFilterWithTopSkipOrderByAndServerSidePaging() {
CommonODataClient<?> client = getClient();
URI uri = client.newURIBuilder(SERVICE_URI)
.appendEntitySetSegment(ES_SERVER_SIDE_PAGING)
.filter("PropertyInt16 le 105") // 1, 2, ... , 105
.orderBy("PropertyInt16 desc") // 105, 104, ..., 2, 1
.addQueryOption(QueryOption.COUNT, Boolean.TRUE.toString()) // 105
.addQueryOption(QueryOption.SKIP, new Integer(3).toString()) // 102, 101, ..., 2, 1
.addQueryOption(QueryOption.TOP, new Integer(43).toString()) // 102, 101, ...., 59
.build();
ODataRetrieveResponse<CommonODataEntitySet> response = client.getRetrieveRequestFactory()
.getEntitySetRequest(uri)
.execute();
assertEquals(Integer.valueOf(105), response.getBody().getCount());
assertEquals(10, response.getBody().getEntities().size());
int id = 102;
// Check first 10 entities
for (int i = 0; i < 10; i++) {
CommonODataEntity entity = response.getBody().getEntities().get(i);
assertEquals(new Integer(id).toString(), entity.getProperty(PROPERTY_INT16).getValue().toString());
id--;
}
// Get 3 * 10 = 30 Entities and check the key
for (int j = 0; j < 3; j++) {
response = client.getRetrieveRequestFactory().getEntitySetRequest(response.getBody().getNext()).execute();
assertEquals(Integer.valueOf(105), response.getBody().getCount());
assertEquals(10, response.getBody().getEntities().size());
for (int i = 0; i < 10; i++) {
CommonODataEntity entity = response.getBody().getEntities().get(i);
assertEquals(new Integer(id).toString(), entity.getProperty(PROPERTY_INT16).getValue().toString());
id--;
}
}
// Get the last 3 items
response = client.getRetrieveRequestFactory().getEntitySetRequest(response.getBody().getNext()).execute();
assertEquals(Integer.valueOf(105), response.getBody().getCount());
assertEquals(3, response.getBody().getEntities().size());
for (int i = 0; i < 3; i++) {
CommonODataEntity entity = response.getBody().getEntities().get(i);
assertEquals(new Integer(id).toString(), entity.getProperty(PROPERTY_INT16).getValue().toString());
id--;
}
// Make sure that the body no not contain a next link
assertEquals(null, response.getBody().getNext());
}
@Test
public void testNextLinkFormat() {
CommonODataClient<?> client = getClient();
URI uri = client.newURIBuilder(SERVICE_URI)
.appendEntitySetSegment(ES_SERVER_SIDE_PAGING)
.build();
ODataRetrieveResponse<CommonODataEntitySet> response = client.getRetrieveRequestFactory()
.getEntitySetRequest(uri)
.execute();
// Check initial next link format
URI nextLink = response.getBody().getNext();
assertEquals("http://localhost:9080/odata-server-tecsvc/odata.svc/ESServerSidePaging?%24skiptoken=1", nextLink
.toASCIIString());
// Check subsequent next links
response = client.getRetrieveRequestFactory()
.getEntitySetRequest(nextLink)
.execute();
nextLink = response.getBody().getNext();
assertEquals("http://localhost:9080/odata-server-tecsvc/odata.svc/ESServerSidePaging?%24skiptoken=2", nextLink
.toASCIIString());
}
@Test
public void testNextLinkFormatWithQueryOptions() {
CommonODataClient<?> client = getClient();
URI uri = client.newURIBuilder(SERVICE_URI)
.appendEntitySetSegment(ES_SERVER_SIDE_PAGING)
.addQueryOption(QueryOption.COUNT, Boolean.TRUE.toString())
.build();
ODataRetrieveResponse<CommonODataEntitySet> response = client.getRetrieveRequestFactory()
.getEntitySetRequest(uri)
.execute();
// Check initial next link format
URI nextLink = response.getBody().getNext();
assertEquals("http://localhost:9080/odata-server-tecsvc/odata.svc/ESServerSidePaging?%24count=true&%24skiptoken=1",
nextLink.toASCIIString());
int token = 1;
while (nextLink != null) {
token++;
// Check subsequent next links
response = client.getRetrieveRequestFactory()
.getEntitySetRequest(nextLink)
.execute();
nextLink = response.getBody().getNext();
if(nextLink != null) {
assertEquals(
"http://localhost:9080/odata-server-tecsvc/odata.svc/ESServerSidePaging?%24count=true&%24skiptoken=" + token,
nextLink.toASCIIString());
}
}
assertEquals(50 + 1, token);
}
@Test
@SuppressWarnings("unused")
public void testNegativeSkip() {
CommonODataClient<?> client = getClient();
URI uri = client.newURIBuilder(SERVICE_URI)
.appendEntitySetSegment(ES_ALL_PRIM)
.addQueryOption(QueryOption.SKIP, new Integer(-5).toString())
.build();
try {
ODataRetrieveResponse<CommonODataEntitySet> response = client.getRetrieveRequestFactory()
.getEntitySetRequest(uri)
.execute();
fail();
} catch (ODataClientErrorException e) {
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), e.getStatusLine().getStatusCode());
}
}
@Test
@SuppressWarnings("unused")
public void testNegativeTop() {
CommonODataClient<?> client = getClient();
URI uri = client.newURIBuilder(SERVICE_URI)
.appendEntitySetSegment(ES_ALL_PRIM)
.addQueryOption(QueryOption.TOP, new Integer(-5).toString())
.build();
try {
ODataRetrieveResponse<CommonODataEntitySet> response = client.getRetrieveRequestFactory()
.getEntitySetRequest(uri)
.execute();
fail();
} catch (ODataClientErrorException e) {
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), e.getStatusLine().getStatusCode());
}
}
@Override
protected CommonODataClient<?> getClient() {
ODataClient odata = ODataClientFactory.getV4();
odata.getConfiguration().setDefaultPubFormat(ODataFormat.JSON);
return odata;
}
}

View File

@ -53,7 +53,8 @@ import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
import org.apache.olingo.server.tecsvc.data.DataProvider;
import org.apache.olingo.server.tecsvc.processor.expression.FilterSystemQueryHandler;
import org.apache.olingo.server.tecsvc.processor.queryoptions.SystemQueryOptions;
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.ServerSidePagingHandler;
/**
* Technical Processor for entity-related functionality.
@ -82,8 +83,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
entitySet.getEntities().addAll(entitySetInitial.getEntities());
// Apply system query options
FilterSystemQueryHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, edmEntitySet);
FilterSystemQueryHandler.applyOrderByOption(uriInfo.getOrderByOption(), entitySet, edmEntitySet);
SystemQueryOptions.applySystemQueryOptions(entitySet, edmEntitySet, uriInfo);
ServerSidePagingHandler.applyServerSidePaging(entitySet, request.getRawRequestUri(), uriInfo);
final ODataFormat format = ODataFormat.fromContentType(requestedContentType);
ODataSerializer serializer = odata.createSerializer(format);

View File

@ -149,18 +149,13 @@ public abstract class TechnicalProcessor implements Processor {
&& resourcePaths.get(navigationCount) instanceof UriResourceNavigation) {
navigationCount++;
}
return (UriResourceNavigation) resourcePaths.get(--navigationCount);
}
protected void validateOptions(final UriInfoResource uriInfo) throws ODataApplicationException {
if (uriInfo.getCountOption() != null
|| !uriInfo.getCustomQueryOptions().isEmpty()
|| uriInfo.getIdOption() != null
|| uriInfo.getSearchOption() != null
|| uriInfo.getSkipOption() != null
|| uriInfo.getSkipTokenOption() != null
|| uriInfo.getTopOption() != null) {
if (uriInfo.getIdOption() != null
|| uriInfo.getSearchOption() != null) {
throw new ODataApplicationException("Not all of the specified options are supported.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}

View File

@ -0,0 +1,41 @@
/*
* 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.tecsvc.processor.queryoptions;
import org.apache.olingo.commons.api.data.EntitySet;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.CountHandler;
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.FilterHandler;
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.OrderByHandler;
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.SkipHandler;
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.TopHandler;
public class SystemQueryOptions {
public static void applySystemQueryOptions(final EntitySet entitySet, final EdmEntitySet edmEntitySet,
final UriInfo uriInfo) throws ODataApplicationException {
FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, edmEntitySet);
CountHandler.applyCountSystemQueryOption(uriInfo.getCountOption(), entitySet);
OrderByHandler.applyOrderByOption(uriInfo.getOrderByOption(), entitySet, edmEntitySet);
SkipHandler.applySkipSystemQueryHandler(uriInfo.getSkipOption(), entitySet);
TopHandler.applyTopSystemQueryOption(uriInfo.getTopOption(), entitySet);
}
}

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.tecsvc.processor.expression;
package org.apache.olingo.server.tecsvc.processor.queryoptions.expression;
import java.util.List;
import java.util.Locale;
@ -39,12 +39,12 @@ import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitEx
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
import org.apache.olingo.server.tecsvc.processor.expression.operand.UntypedOperand;
import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
import org.apache.olingo.server.tecsvc.processor.expression.operation.BinaryOperator;
import org.apache.olingo.server.tecsvc.processor.expression.operation.MethodCallOperator;
import org.apache.olingo.server.tecsvc.processor.expression.operation.UnaryOperator;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.TypedOperand;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.UntypedOperand;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.VisitorOperand;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operation.BinaryOperator;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operation.MethodCallOperator;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operation.UnaryOperator;
public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand> {

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.tecsvc.processor.expression;
package org.apache.olingo.server.tecsvc.processor.queryoptions.expression;
import org.apache.olingo.commons.api.ODataRuntimeException;

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.tecsvc.processor.expression.operand;
package org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand;
import java.math.BigDecimal;
import java.util.Locale;
@ -35,7 +35,7 @@ import org.apache.olingo.commons.core.edm.primitivetype.EdmInt64;
import org.apache.olingo.commons.core.edm.primitivetype.EdmSByte;
import org.apache.olingo.commons.core.edm.primitivetype.EdmSingle;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.tecsvc.processor.expression.primitive.EdmNull;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.primitive.EdmNull;
public class TypedOperand extends VisitorOperand {

View File

@ -16,13 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.tecsvc.processor.expression.operand;
package org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand;
import java.util.Locale;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean;
import org.apache.olingo.commons.core.edm.primitivetype.EdmByte;
import org.apache.olingo.commons.core.edm.primitivetype.EdmDate;
import org.apache.olingo.commons.core.edm.primitivetype.EdmDateTimeOffset;
@ -38,7 +39,7 @@ import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
import org.apache.olingo.commons.core.edm.primitivetype.EdmTime;
import org.apache.olingo.commons.core.edm.primitivetype.EdmTimeOfDay;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.tecsvc.processor.expression.primitive.EdmNull;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.primitive.EdmNull;
public class UntypedOperand extends VisitorOperand {
@ -88,6 +89,11 @@ public class UntypedOperand extends VisitorOperand {
return new TypedOperand(newValue, EdmString.getInstance());
}
// Boolean
if ((newValue = tryCast(literal, EdmBoolean.getInstance())) != null) {
return new TypedOperand(newValue, EdmBoolean.getInstance());
}
// Date
if ((newValue = tryCast(literal, EdmDateTimeOffset.getInstance())) != null) {
return new TypedOperand(newValue, EdmDateTimeOffset.getInstance());

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.tecsvc.processor.expression.operand;
package org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand;
import java.math.BigDecimal;
import java.math.BigInteger;

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.tecsvc.processor.expression.operation;
package org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operation;
import java.math.BigDecimal;
import java.math.BigInteger;
@ -39,9 +39,9 @@ import org.apache.olingo.commons.core.edm.primitivetype.EdmSByte;
import org.apache.olingo.commons.core.edm.primitivetype.EdmSingle;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
import org.apache.olingo.server.tecsvc.processor.expression.primitive.EdmNull;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.TypedOperand;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.VisitorOperand;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.primitive.EdmNull;
public class BinaryOperator {
private static final int FACTOR_SECOND_INT = 1000;

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.tecsvc.processor.expression.operation;
package org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operation;
import java.math.BigDecimal;
import java.math.BigInteger;
@ -40,8 +40,8 @@ import org.apache.olingo.commons.core.edm.primitivetype.EdmInt32;
import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
import org.apache.olingo.commons.core.edm.primitivetype.EdmTimeOfDay;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.TypedOperand;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.VisitorOperand;
public class MethodCallOperator {

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.tecsvc.processor.expression.operation;
package org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operation;
import java.math.BigDecimal;
@ -27,8 +27,8 @@ import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean;
import org.apache.olingo.commons.core.edm.primitivetype.EdmDuration;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.TypedOperand;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.VisitorOperand;
public class UnaryOperator {
final private TypedOperand operand;

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.tecsvc.processor.expression.primitive;
package org.apache.olingo.server.tecsvc.processor.queryoptions.expression.primitive;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.core.edm.primitivetype.SingletonPrimitiveType;

View File

@ -0,0 +1,31 @@
/*
* 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.tecsvc.processor.queryoptions.options;
import org.apache.olingo.commons.api.data.EntitySet;
import org.apache.olingo.server.api.uri.queryoption.CountOption;
public class CountHandler {
public static void applyCountSystemQueryOption(final CountOption countOption, final EntitySet entitySet) {
if(countOption != null && countOption.getValue()) {
entitySet.setCount(entitySet.getEntities().size());
}
}
}

View File

@ -0,0 +1,82 @@
/*
* 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.tecsvc.processor.queryoptions.options;
import java.util.Iterator;
import java.util.Locale;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntitySet;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.ExpressionVisitorImpl;
/*
* 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.
*/
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.TypedOperand;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.VisitorOperand;
public class FilterHandler {
public static void applyFilterSystemQuery(FilterOption filterOption, EntitySet entitySet, EdmEntitySet edmEntitySet)
throws ODataApplicationException {
if (filterOption == null) {
return;
}
try {
final Iterator<Entity> iter = entitySet.getEntities().iterator();
while (iter.hasNext()) {
final VisitorOperand operand = filterOption.getExpression()
.accept(new ExpressionVisitorImpl(iter.next(), edmEntitySet));
final TypedOperand typedOperand = operand.asTypedOperand();
if (!(typedOperand.is(EdmBoolean.getInstance())
&& Boolean.TRUE.equals(typedOperand.getTypedValue(Boolean.class)))) {
iter.remove();
}
}
} catch (ExpressionVisitException e) {
throw new ODataApplicationException("Exception in filter evaluation",
HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
}
}
}

View File

@ -16,55 +16,25 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.tecsvc.processor.expression;
package org.apache.olingo.server.tecsvc.processor.queryoptions.options;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Locale;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntitySet;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
import org.apache.olingo.server.api.uri.queryoption.OrderByItem;
import org.apache.olingo.server.api.uri.queryoption.OrderByOption;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
public class FilterSystemQueryHandler {
public static void applyFilterSystemQuery(FilterOption filterOption, EntitySet entitySet, EdmEntitySet edmEntitySet)
throws ODataApplicationException {
if (filterOption == null) {
return;
}
try {
final Iterator<Entity> iter = entitySet.getEntities().iterator();
while (iter.hasNext()) {
final VisitorOperand operand = filterOption.getExpression()
.accept(new ExpressionVisitorImpl(iter.next(), edmEntitySet));
final TypedOperand typedOperand = operand.asTypedOperand();
if (!(typedOperand.is(EdmBoolean.getInstance())
&& Boolean.TRUE.equals(typedOperand.getTypedValue(Boolean.class)))) {
iter.remove();
}
}
} catch (ExpressionVisitException e) {
throw new ODataApplicationException("Exception in filter evaluation",
HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
}
}
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.ExpressionVisitorImpl;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.FilterRuntimeException;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.TypedOperand;
public class OrderByHandler {
public static void applyOrderByOption(final OrderByOption orderByOption, final EntitySet entitySet,
final EdmEntitySet edmEntitySet) throws ODataApplicationException {

View File

@ -0,0 +1,110 @@
/*
* 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.tecsvc.processor.queryoptions.options;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;
import org.apache.olingo.commons.api.data.EntitySet;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.commons.core.Encoder;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.queryoption.SkipTokenOption;
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
public class ServerSidePagingHandler {
private static final int MAX_PAGE_SIZE = 10;
public static void
applyServerSidePaging(final EntitySet entitySet, final String rawRequestUri, final UriInfo uriInfo)
throws ODataApplicationException {
if (shouldApplyServerSidePaging(entitySet)) {
final int maxPageSize = getMaxPageSize();
final int page = getPage(uriInfo.getSkipTokenOption());
final int itemsToSkip = maxPageSize * page;
if (itemsToSkip <= entitySet.getEntities().size()) {
SkipHandler.popAtMost(entitySet, itemsToSkip);
final int remainingItems = entitySet.getEntities().size();
TopHandler.reduceToSize(entitySet, maxPageSize);
// Determine if a new next Link has to be provided
if (remainingItems > maxPageSize) {
entitySet.setNext(createNextLink(uriInfo, rawRequestUri, page + 1));
}
} else {
throw new ODataApplicationException("Invalid skiptoken", HttpStatusCode.BAD_REQUEST.getStatusCode(),
Locale.ROOT);
}
}
}
private static URI createNextLink(final UriInfo uriInfo, final String rawRequestUri, final Integer page)
throws ODataApplicationException {
try {
// Remove skip token
String nextlink = rawRequestUri;
// Remove a may existing skiptoken, make sure that the query part is not empty
if (rawRequestUri.contains("?")) {
nextlink = rawRequestUri.replaceAll("(\\$|%24)skiptoken=.+&?", "").replaceAll("(\\?|&)$", "");
}
// Add a question mark or an ampersand, depending of the current query part
if (!nextlink.contains("?")) {
nextlink = nextlink + "?";
} else {
nextlink = nextlink + "&";
}
// Append the new nextlink
return new URI(nextlink + Encoder.encode(SystemQueryOptionKind.SKIPTOKEN.toString()) + "="
+ Encoder.encode(page.toString()));
} catch (URISyntaxException e) {
throw new ODataApplicationException("Exception while constructing next link",
HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
}
}
private static int getPage(SkipTokenOption skipTokenOption) throws ODataApplicationException {
if (skipTokenOption != null) {
try {
return Integer.parseInt(skipTokenOption.getValue());
} catch (NumberFormatException e) {
throw new ODataApplicationException("Invalid skip token", HttpStatusCode.BAD_REQUEST.getStatusCode(),
Locale.ROOT);
}
} else {
return 0;
}
}
private static boolean shouldApplyServerSidePaging(final EntitySet entitySet) {
return true;
}
private static int getMaxPageSize() {
// TODO Consider odata.maxpagesize preference?
return MAX_PAGE_SIZE;
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.tecsvc.processor.queryoptions.options;
import java.util.Iterator;
import java.util.Locale;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntitySet;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.queryoption.SkipOption;
public class SkipHandler {
public static void applySkipSystemQueryHandler(final SkipOption skipOption, final EntitySet entitySet)
throws ODataApplicationException {
if (skipOption != null) {
if (skipOption.getValue() >= 0) {
popAtMost(entitySet, skipOption.getValue());
} else {
throw new ODataApplicationException("Skip value must be positive", HttpStatusCode.BAD_REQUEST.getStatusCode(),
Locale.ROOT);
}
}
}
static void popAtMost(final EntitySet entitySet, final int n) {
final Iterator<Entity> iter = entitySet.getEntities().iterator();
int i = 0;
while (iter.hasNext() && i < n) {
iter.next();
iter.remove();
i++;
}
}
}

View File

@ -0,0 +1,47 @@
/*
* 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.tecsvc.processor.queryoptions.options;
import java.util.Locale;
import org.apache.olingo.commons.api.data.EntitySet;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.queryoption.TopOption;
public class TopHandler {
public static void applyTopSystemQueryOption(final TopOption topOption, final EntitySet entitySet)
throws ODataApplicationException {
if (topOption != null) {
if (topOption.getValue() >= 0) {
reduceToSize(entitySet, topOption.getValue());
} else {
throw new ODataApplicationException("Top value must be positive", HttpStatusCode.BAD_REQUEST.getStatusCode(),
Locale.ROOT);
}
}
}
static void reduceToSize(final EntitySet entitySet, final int n) {
while (entitySet.getEntities().size() > n) {
entitySet.getEntities().remove(entitySet.getEntities().size() - 1);
}
}
}