[OLINGO-801] better enum and alias support in technical service

This commit is contained in:
Michael Bolz 2015-10-22 10:04:49 +02:00
parent 4134b2e82c
commit 23fb86a870
10 changed files with 156 additions and 108 deletions

View File

@ -19,6 +19,7 @@
package org.apache.olingo.fit.tecsvc.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.net.URI;
import java.util.LinkedHashMap;
@ -41,6 +42,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
private static final String ES_COMP_ALL_PRIM = "ESCompAllPrim";
private static final String ES_TWO_KEY_NAV = "ESTwoKeyNav";
private static final String ES_ALL_PRIM = "ESAllPrim";
private static final String ES_MIX_ENUM_DEF_COLL_COMP = "ESMixEnumDefCollComp";
@Test
public void timeOfDayLiteral() {
@ -184,6 +186,9 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
clientEntity = result.getBody().getEntities().get(1);
assertShortOrInt(1, clientEntity.getProperty("PropertyInt16").getPrimitiveValue().toValue());
assertEquals("2", clientEntity.getProperty("PropertyString").getPrimitiveValue().toValue());
result = sendRequest(ES_MIX_ENUM_DEF_COLL_COMP, "PropertyEnumString has Namespace1_Alias.ENString'String1'");
assertTrue(result.getBody().getEntities().isEmpty());
}
@Test
@ -994,7 +999,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
result = sendRequest(ES_ALL_PRIM, "'Test1' ne 'Test'");
assertEquals(3, result.getBody().getEntities().size());
}
@Test
public void castException() {
fail("ESAllPrim", "PropertyInt16 eq '1'", HttpStatusCode.BAD_REQUEST);
@ -1004,7 +1009,6 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
fail("ESAllPrim", "PropertyInt16 eq duration'PT4S'", HttpStatusCode.BAD_REQUEST);
}
@Test
public void stringFunctionWithoutStringParameters() {
fail("ESServerSidePaging", "contains(PropertyInt16, 3) eq 'hallo'", HttpStatusCode.BAD_REQUEST);

View File

@ -91,15 +91,15 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
}
@Override
public void countEntityCollection(final ODataRequest request, final ODataResponse response, final UriInfo
uriInfo) throws ODataApplicationException, ODataLibraryException {
public void countEntityCollection(final ODataRequest request, final ODataResponse response,
final UriInfo uriInfo) throws ODataApplicationException, ODataLibraryException {
validateOptions(uriInfo.asUriInfoResource());
final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo); // including checks
getEdmEntitySet(uriInfo); // including checks
final EntityCollection entitySetInitial = readEntityCollection(uriInfo);
EntityCollection entitySet = new EntityCollection();
entitySet.getEntities().addAll(entitySetInitial.getEntities());
FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, edmEntitySet);
FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, uriInfo, serviceMetadata.getEdm());
response.setContent(odata.createFixedFormatSerializer().count(
entitySet.getEntities().size()));
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
@ -430,7 +430,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
final ExpandSystemQueryOptionHandler expandHandler = new ExpandSystemQueryOptionHandler();
final Entity entitySerialization = expandHandler.transformEntityGraphToTree(entity, edmEntitySet, expand);
expandHandler.applyExpandQueryOptions(entitySerialization, edmEntitySet, expand);
expandHandler.applyExpandQueryOptions(entitySerialization, edmEntitySet, expand, uriInfo,
serviceMetadata.getEdm());
final SerializerResult serializerResult = isReference ?
serializeReference(entity, edmEntitySet, requestedFormat) :
@ -480,9 +481,9 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
entitySet.getEntities().addAll(entitySetInitial.getEntities());
// Apply system query options
FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, edmEntitySet);
FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, uriInfo, serviceMetadata.getEdm());
CountHandler.applyCountSystemQueryOption(uriInfo.getCountOption(), entitySet);
OrderByHandler.applyOrderByOption(uriInfo.getOrderByOption(), entitySet, edmEntitySet);
OrderByHandler.applyOrderByOption(uriInfo.getOrderByOption(), entitySet, uriInfo, serviceMetadata.getEdm());
SkipHandler.applySkipSystemQueryHandler(uriInfo.getSkipOption(), entitySet);
TopHandler.applyTopSystemQueryOption(uriInfo.getTopOption(), entitySet);
@ -505,7 +506,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
final EntityCollection entitySetSerialization = expandHandler.transformEntitySetGraphToTree(entitySet,
edmEntitySet,
expand);
expandHandler.applyExpandQueryOptions(entitySetSerialization, edmEntitySet, expand);
expandHandler.applyExpandQueryOptions(entitySetSerialization, edmEntitySet, expand, uriInfo,
serviceMetadata.getEdm());
final CountOption countOption = uriInfo.getCountOption();
String id;

View File

@ -27,6 +27,7 @@ import java.util.Set;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Link;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmBindingTarget;
import org.apache.olingo.commons.api.edm.EdmElement;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
@ -35,6 +36,7 @@ import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
import org.apache.olingo.commons.api.edm.EdmNavigationPropertyBinding;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfoResource;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceNavigation;
import org.apache.olingo.server.api.uri.queryoption.CountOption;
@ -53,29 +55,28 @@ import org.apache.olingo.server.tecsvc.processor.queryoptions.options.TopHandler
public class ExpandSystemQueryOptionHandler {
public void applyExpandQueryOptions(final EntityCollection entitySet, final EdmEntitySet edmEntitySet,
final ExpandOption expandOption) throws ODataApplicationException {
final ExpandOption expandOption, final UriInfoResource uriInfo, final Edm edm) throws ODataApplicationException {
if (expandOption == null) {
return;
}
for (final Entity entity : entitySet.getEntities()) {
applyExpandOptionToEntity(entity, edmEntitySet, expandOption);
applyExpandOptionToEntity(entity, edmEntitySet, expandOption, uriInfo, edm);
}
}
public void applyExpandQueryOptions(final Entity entity, final EdmEntitySet edmEntitySet,
final ExpandOption expandOption)
throws ODataApplicationException {
final ExpandOption expandOption, final UriInfoResource uriInfo, final Edm edm) throws ODataApplicationException {
if (expandOption == null) {
return;
}
applyExpandOptionToEntity(entity, edmEntitySet, expandOption);
applyExpandOptionToEntity(entity, edmEntitySet, expandOption, uriInfo, edm);
}
private void applyExpandOptionToEntity(final Entity entity, final EdmBindingTarget edmBindingTarget,
final ExpandOption expandOption) throws ODataApplicationException {
final ExpandOption expandOption, final UriInfoResource uriInfo, final Edm edm) throws ODataApplicationException {
final EdmEntityType entityType = edmBindingTarget.getEntityType();
for (ExpandItem item : expandOption.getExpandItems()) {
@ -103,7 +104,7 @@ public class ExpandSystemQueryOptionHandler {
}
}
for(EdmNavigationProperty navigationProperty: navigationProperties) {
for (EdmNavigationProperty navigationProperty: navigationProperties) {
final String navPropertyName = navigationProperty.getName();
final EdmBindingTarget targetEdmEntitySet = edmBindingTarget.getRelatedBindingTarget(navPropertyName);
@ -116,7 +117,8 @@ public class ExpandSystemQueryOptionHandler {
item.getCountOption(),
item.getSkipOption(),
item.getTopOption(),
item.getExpandOption());
item.getExpandOption(),
uriInfo, edm);
}
}
}
@ -125,11 +127,12 @@ public class ExpandSystemQueryOptionHandler {
private void applyOptionsToEntityCollection(final EntityCollection entitySet,
final EdmBindingTarget edmBindingTarget,
final FilterOption filterOption, final OrderByOption orderByOption, final CountOption countOption,
final SkipOption skipOption, final TopOption topOption, final ExpandOption expandOption)
final SkipOption skipOption, final TopOption topOption, final ExpandOption expandOption,
final UriInfoResource uriInfo, final Edm edm)
throws ODataApplicationException {
FilterHandler.applyFilterSystemQuery(filterOption, entitySet, edmBindingTarget);
OrderByHandler.applyOrderByOption(orderByOption, entitySet, edmBindingTarget);
FilterHandler.applyFilterSystemQuery(filterOption, entitySet, uriInfo, edm);
OrderByHandler.applyOrderByOption(orderByOption, entitySet, uriInfo, edm);
CountHandler.applyCountSystemQueryOption(countOption, entitySet);
SkipHandler.applySkipSystemQueryHandler(skipOption, entitySet);
TopHandler.applyTopSystemQueryOption(topOption, entitySet);
@ -137,7 +140,7 @@ public class ExpandSystemQueryOptionHandler {
// Apply nested expand system query options to remaining entities
if (expandOption != null) {
for (final Entity entity : entitySet.getEntities()) {
applyExpandOptionToEntity(entity, edmBindingTarget, expandOption);
applyExpandOptionToEntity(entity, edmBindingTarget, expandOption, uriInfo, edm);
}
}
}

View File

@ -23,8 +23,9 @@ import java.util.Locale;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.EdmBindingTarget;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmEnumType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.http.HttpStatusCode;
@ -48,16 +49,19 @@ import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operati
public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand> {
final private Entity entity;
private final Entity entity;
private final UriInfoResource uriInfo;
private final Edm edm;
public ExpressionVisitorImpl(final Entity entity, final EdmBindingTarget bindingTarget) {
public ExpressionVisitorImpl(final Entity entity, final UriInfoResource uriInfo, final Edm edm) {
this.entity = entity;
this.uriInfo = uriInfo;
this.edm = edm;
}
@Override
public VisitorOperand visitBinaryOperator(final BinaryOperatorKind operator, final VisitorOperand left,
final VisitorOperand right)
throws ExpressionVisitException, ODataApplicationException {
final VisitorOperand right) throws ExpressionVisitException, ODataApplicationException {
final BinaryOperator binaryOperator = new BinaryOperator(left, right);
@ -84,6 +88,9 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand>
case DIV:
case MOD:
return binaryOperator.arithmeticOperator(operator);
case HAS:
return binaryOperator.hasOperator();
default:
return throwNotImplemented();
}
@ -161,15 +168,13 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand>
@Override
public VisitorOperand visitLambdaExpression(final String lambdaFunction, final String lambdaVariable,
final Expression expression)
throws ExpressionVisitException, ODataApplicationException {
final Expression expression) throws ExpressionVisitException, ODataApplicationException {
return throwNotImplemented();
}
@Override
public VisitorOperand visitLiteral(final Literal literal) throws ExpressionVisitException, ODataApplicationException {
return new UntypedOperand(literal.getText());
return new UntypedOperand(literal.getText(), edm);
}
@Override
@ -204,12 +209,12 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand>
@Override
public VisitorOperand visitAlias(final String aliasName) throws ExpressionVisitException, ODataApplicationException {
return throwNotImplemented();
return new UntypedOperand(uriInfo.getValueForAlias(aliasName), edm);
}
@Override
public VisitorOperand visitTypeLiteral(final EdmType type) throws ExpressionVisitException,
ODataApplicationException {
public VisitorOperand visitTypeLiteral(final EdmType type)
throws ExpressionVisitException, ODataApplicationException {
return throwNotImplemented();
}
@ -221,9 +226,18 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand>
@Override
public VisitorOperand visitEnum(final EdmEnumType type, final List<String> enumValues)
throws ExpressionVisitException,
ODataApplicationException {
return throwNotImplemented();
throws ExpressionVisitException, ODataApplicationException {
Long result = null;
try {
for (final String enumValue : enumValues) {
final Long value = type.valueOfString(enumValue, null, null, null, null, null, Long.class);
result = result == null ? value : result | value;
}
} catch (final EdmPrimitiveTypeException e) {
throw new ODataApplicationException("Illegal enum value.",
HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT, e);
}
return new TypedOperand(result, type);
}
private VisitorOperand throwNotImplemented() throws ODataApplicationException {

View File

@ -19,6 +19,7 @@
package org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Locale;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
@ -54,36 +55,42 @@ public class TypedOperand extends VisitorOperand {
}
@Override
public TypedOperand asTypedOperand(final EdmPrimitiveType... asTypes) throws ODataApplicationException {
public TypedOperand asTypedOperand(final EdmPrimitiveType asType) throws ODataApplicationException {
if (is(primNull)) {
return this;
} else if (isNull()) {
return new TypedOperand(null, asTypes[0]);
return new TypedOperand(null, asType);
}
Object newValue = null;
for (EdmPrimitiveType asType : asTypes) {
// Use BigDecimal for unlimited precision
if (asType.equals(primDouble) || asType.equals(primSingle) || asType.equals(primDecimal)) {
try {
newValue = new BigDecimal(value.toString());
} catch (NumberFormatException e) {
// Nothing to do
}
} else {
// Use type conversion of EdmPrimitive types
try {
final String literal = getLiteral(value);
newValue = tryCast(literal, asType);
} catch (EdmPrimitiveTypeException e) {
// Nothing to do
}
// Use BigInteger for arbitrarily large whole numbers.
if (asType.equals(primSByte) || asType.equals(primByte)
|| asType.equals(primInt16) || asType.equals(primInt32) || asType.equals(primInt64)) {
if (value instanceof BigInteger) {
newValue = value;
} else if (value instanceof Byte || value instanceof Short
|| value instanceof Integer || value instanceof Long) {
newValue = BigInteger.valueOf(((Number) value).longValue());
}
if (newValue != null) {
return new TypedOperand(newValue, asType);
// Use BigDecimal for unlimited precision.
} else if (asType.equals(primDouble) || asType.equals(primSingle) || asType.equals(primDecimal)) {
try {
newValue = new BigDecimal(value.toString());
} catch (NumberFormatException e) {
// Nothing to do
}
} else {
// Use type conversion of EdmPrimitive types
try {
final String literal = getLiteral(value);
newValue = tryCast(literal, asType);
} catch (EdmPrimitiveTypeException e) {
// Nothing to do
}
}
if (newValue != null) {
return new TypedOperand(newValue, asType);
}
throw new ODataApplicationException("Cast failed", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
@ -93,11 +100,9 @@ public class TypedOperand extends VisitorOperand {
final TypedOperand other = otherOperand.asTypedOperand();
final EdmType oType = other.getType();
// In case of numberic values make sure that the EDM type is equals, check also the java type.
// So it is possible, that there is an conversation even if the same
// EdmType is provided.
// For example consider an Edm16 (internal Integer) and Edm16(internal
// Short)
// In case of numberic values make sure that the EDM type is equal, check also the java type.
// It is possible that there is an conversion even if the same EdmType is provided.
// For example consider an Edm.Int32 (internal Integer) and an Edm.Int16 (internal Short) value:
// shortInstance.equals(intInstance) will always be false!
if (type == oType && value != null && other.getValue() != null
&& value.getClass() == other.getValue().getClass()) {

View File

@ -20,15 +20,21 @@ package org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operan
import java.util.Locale;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmEnumType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmSchema;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException;
public class UntypedOperand extends VisitorOperand {
public UntypedOperand(final String literal) {
private final Edm edm;
public UntypedOperand(final String literal, final Edm edm) {
super(literal);
this.edm = edm;
}
@Override
@ -37,22 +43,18 @@ public class UntypedOperand extends VisitorOperand {
}
@Override
public TypedOperand asTypedOperand(final EdmPrimitiveType... types) throws ODataApplicationException {
public TypedOperand asTypedOperand(final EdmPrimitiveType type) throws ODataApplicationException {
final String literal = (String) value;
Object newValue = null;
// First try the null literal
// First try the null literal.
if ((newValue = tryCast(literal, primNull)) != null) {
return new TypedOperand(newValue, primNull);
}
// Than try the given types
for (EdmPrimitiveType type : types) {
newValue = tryCast(literal, type);
if (newValue != null) {
return new TypedOperand(newValue, type);
}
// Then try the given type.
if ((newValue = tryCast(literal, type)) != null) {
return new TypedOperand(newValue, type);
}
throw new ODataApplicationException("Cast failed", HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(),
@ -130,6 +132,17 @@ public class UntypedOperand extends VisitorOperand {
return new TypedOperand(newValue, primDouble);
}
// Enum
final EdmSchema schema = edm.getSchema(edm.getEntityContainer().getNamespace());
final String enumValue = schema.getAlias() != null && literal.startsWith(schema.getAlias()) ?
literal.replace(schema.getAlias(), schema.getNamespace()) :
literal;
for (final EdmEnumType enumType : schema.getEnumTypes()) {
if ((newValue = tryCast(enumValue, enumType)) != null) {
return new TypedOperand(newValue, enumType);
}
}
throw new ODataApplicationException("Could not determine type for literal " + literal,
HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
}

View File

@ -85,7 +85,7 @@ public abstract class VisitorOperand {
public abstract TypedOperand asTypedOperand() throws ODataApplicationException;
public abstract TypedOperand asTypedOperand(EdmPrimitiveType... types) throws ODataApplicationException;
public abstract TypedOperand asTypedOperand(EdmPrimitiveType type) throws ODataApplicationException;
public abstract EdmProperty getEdmProperty();

View File

@ -168,7 +168,15 @@ public class BinaryOperator {
return new TypedOperand(result, primBoolean);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public VisitorOperand hasOperator() throws ODataApplicationException {
final boolean result = isBinaryComparisonNecessary()
&& !left.getTypedValue(BigInteger.class).equals(BigInteger.ZERO)
&& left.getTypedValue(BigInteger.class).and(BigInteger.valueOf(right.getTypedValue(Number.class).longValue()))
.equals(BigInteger.valueOf(right.getTypedValue(Number.class).longValue()));
return new TypedOperand(result, primBoolean);
}
@SuppressWarnings("unchecked")
private boolean binaryComparison(final int... expect) {
int result;
@ -180,13 +188,14 @@ public class BinaryOperator {
result = left.getTypedValue(BigInteger.class).compareTo(right.getTypedValue(BigInteger.class));
} else if (left.isDecimalType()) {
result = left.getTypedValue(BigDecimal.class).compareTo(right.getTypedValue(BigDecimal.class));
} else if(left.getValue().getClass() == right.getValue().getClass() && left.getValue() instanceof Comparable) {
result = ((Comparable)left.getValue()).compareTo(right.getValue());
} else if(left.getValue().getClass() == right.getValue().getClass()
&& left.getValue() instanceof Comparable<?>) {
result = ((Comparable<Object>) left.getValue()).compareTo(right.getValue());
} else {
result = left.getValue().equals(right.getValue()) ? 0 : 1;
}
}
for (int expectedValue : expect) {
if (expectedValue == result) {
return true;

View File

@ -23,12 +23,13 @@ import java.util.Locale;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.edm.EdmBindingTarget;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfoResource;
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;
@ -37,16 +38,11 @@ import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand
public class FilterHandler {
protected static final OData oData;
protected static final EdmPrimitiveType primBoolean;
static {
oData = OData.newInstance();
primBoolean = oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean);
}
protected static final EdmPrimitiveType primBoolean =
OData.newInstance().createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean);
public static void applyFilterSystemQuery(final FilterOption filterOption, final EntityCollection entitySet,
final EdmBindingTarget edmEntitySet) throws ODataApplicationException {
final UriInfoResource uriInfo, final Edm edm) throws ODataApplicationException {
if (filterOption == null) {
return;
@ -57,16 +53,17 @@ public class FilterHandler {
while (iter.hasNext()) {
final VisitorOperand operand = filterOption.getExpression()
.accept(new ExpressionVisitorImpl(iter.next(), edmEntitySet));
.accept(new ExpressionVisitorImpl(iter.next(), uriInfo, edm));
final TypedOperand typedOperand = operand.asTypedOperand();
if(typedOperand.is(primBoolean)) {
if(Boolean.FALSE.equals(typedOperand.getTypedValue(Boolean.class))) {
if (typedOperand.is(primBoolean)) {
if (Boolean.FALSE.equals(typedOperand.getTypedValue(Boolean.class))) {
iter.remove();
}
} else {
throw new ODataApplicationException("Invalid filter expression. Filter expressions must return a value of "
+ "type Edm.Boolean", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
throw new ODataApplicationException(
"Invalid filter expression. Filter expressions must return a value of type Edm.Boolean",
HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
}
}

View File

@ -24,9 +24,10 @@ import java.util.Locale;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.edm.EdmBindingTarget;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfoResource;
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;
@ -35,43 +36,43 @@ import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand
public class OrderByHandler {
public static void applyOrderByOption(final OrderByOption orderByOption, final EntityCollection entitySet,
final EdmBindingTarget edmBindingTarget) throws ODataApplicationException {
final UriInfoResource uriInfo, final Edm edm) throws ODataApplicationException {
if (orderByOption == null) {
return;
}
try {
applyOrderByOptionInternal(orderByOption, entitySet, edmBindingTarget);
applyOrderByOptionInternal(orderByOption, entitySet, uriInfo, edm);
} catch (SystemQueryOptionsRuntimeException e) {
if (e.getCause() instanceof ODataApplicationException) {
// Throw the nested exception, to send the correct HTTP status code in the HTTP response
throw (ODataApplicationException) e.getCause();
} else {
throw new ODataApplicationException("Exception in orderBy evaluation", HttpStatusCode.INTERNAL_SERVER_ERROR
.getStatusCode(), Locale.ROOT);
throw new ODataApplicationException("Exception in orderBy evaluation",
HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
}
}
}
private static void applyOrderByOptionInternal(final OrderByOption orderByOption, final EntityCollection entitySet,
final EdmBindingTarget edmBindingTarget) throws ODataApplicationException {
final UriInfoResource uriInfo, final Edm edm) throws ODataApplicationException {
Collections.sort(entitySet.getEntities(), new Comparator<Entity>() {
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings("unchecked")
public int compare(final Entity e1, final Entity e2) {
// Evaluate the first order option for both entity
// If and only if the result of the previous order option is equals to 0
// evaluate the next order option until all options are evaluated or they are not equals
// Evaluate the first order option for both entities.
// If and only if the result of the previous order option is equal to 0
// evaluate the next order option until all options are evaluated or they are not equal.
int result = 0;
for (int i = 0; i < orderByOption.getOrders().size() && result == 0; i++) {
try {
final OrderByItem item = orderByOption.getOrders().get(i);
final TypedOperand op1 =
item.getExpression().accept(new ExpressionVisitorImpl(e1, edmBindingTarget)).asTypedOperand();
item.getExpression().accept(new ExpressionVisitorImpl(e1, uriInfo, edm)).asTypedOperand();
final TypedOperand op2 =
item.getExpression().accept(new ExpressionVisitorImpl(e2, edmBindingTarget)).asTypedOperand();
item.getExpression().accept(new ExpressionVisitorImpl(e2, uriInfo, edm)).asTypedOperand();
if (op1.isNull() || op2.isNull()) {
if (op1.isNull() && op2.isNull()) {
@ -84,7 +85,7 @@ public class OrderByHandler {
Object o2 = op2.getValue();
if (o1.getClass() == o2.getClass() && o1 instanceof Comparable) {
result = ((Comparable) o1).compareTo(o2);
result = ((Comparable<Object>) o1).compareTo(o2);
} else {
result = 0;
}