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

View File

@ -91,15 +91,15 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
} }
@Override @Override
public void countEntityCollection(final ODataRequest request, final ODataResponse response, final UriInfo public void countEntityCollection(final ODataRequest request, final ODataResponse response,
uriInfo) throws ODataApplicationException, ODataLibraryException { final UriInfo uriInfo) throws ODataApplicationException, ODataLibraryException {
validateOptions(uriInfo.asUriInfoResource()); validateOptions(uriInfo.asUriInfoResource());
final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo); // including checks getEdmEntitySet(uriInfo); // including checks
final EntityCollection entitySetInitial = readEntityCollection(uriInfo); final EntityCollection entitySetInitial = readEntityCollection(uriInfo);
EntityCollection entitySet = new EntityCollection(); EntityCollection entitySet = new EntityCollection();
entitySet.getEntities().addAll(entitySetInitial.getEntities()); entitySet.getEntities().addAll(entitySetInitial.getEntities());
FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, edmEntitySet); FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, uriInfo, serviceMetadata.getEdm());
response.setContent(odata.createFixedFormatSerializer().count( response.setContent(odata.createFixedFormatSerializer().count(
entitySet.getEntities().size())); entitySet.getEntities().size()));
response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setStatusCode(HttpStatusCode.OK.getStatusCode());
@ -430,7 +430,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
final ExpandSystemQueryOptionHandler expandHandler = new ExpandSystemQueryOptionHandler(); final ExpandSystemQueryOptionHandler expandHandler = new ExpandSystemQueryOptionHandler();
final Entity entitySerialization = expandHandler.transformEntityGraphToTree(entity, edmEntitySet, expand); 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 ? final SerializerResult serializerResult = isReference ?
serializeReference(entity, edmEntitySet, requestedFormat) : serializeReference(entity, edmEntitySet, requestedFormat) :
@ -480,9 +481,9 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
entitySet.getEntities().addAll(entitySetInitial.getEntities()); entitySet.getEntities().addAll(entitySetInitial.getEntities());
// Apply system query options // Apply system query options
FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, edmEntitySet); FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, uriInfo, serviceMetadata.getEdm());
CountHandler.applyCountSystemQueryOption(uriInfo.getCountOption(), entitySet); CountHandler.applyCountSystemQueryOption(uriInfo.getCountOption(), entitySet);
OrderByHandler.applyOrderByOption(uriInfo.getOrderByOption(), entitySet, edmEntitySet); OrderByHandler.applyOrderByOption(uriInfo.getOrderByOption(), entitySet, uriInfo, serviceMetadata.getEdm());
SkipHandler.applySkipSystemQueryHandler(uriInfo.getSkipOption(), entitySet); SkipHandler.applySkipSystemQueryHandler(uriInfo.getSkipOption(), entitySet);
TopHandler.applyTopSystemQueryOption(uriInfo.getTopOption(), entitySet); TopHandler.applyTopSystemQueryOption(uriInfo.getTopOption(), entitySet);
@ -505,7 +506,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
final EntityCollection entitySetSerialization = expandHandler.transformEntitySetGraphToTree(entitySet, final EntityCollection entitySetSerialization = expandHandler.transformEntitySetGraphToTree(entitySet,
edmEntitySet, edmEntitySet,
expand); expand);
expandHandler.applyExpandQueryOptions(entitySetSerialization, edmEntitySet, expand); expandHandler.applyExpandQueryOptions(entitySetSerialization, edmEntitySet, expand, uriInfo,
serviceMetadata.getEdm());
final CountOption countOption = uriInfo.getCountOption(); final CountOption countOption = uriInfo.getCountOption();
String id; 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.Entity;
import org.apache.olingo.commons.api.data.EntityCollection; import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Link; 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.EdmBindingTarget;
import org.apache.olingo.commons.api.edm.EdmElement; import org.apache.olingo.commons.api.edm.EdmElement;
import org.apache.olingo.commons.api.edm.EdmEntitySet; 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.edm.EdmNavigationPropertyBinding;
import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException; 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.UriResource;
import org.apache.olingo.server.api.uri.UriResourceNavigation; import org.apache.olingo.server.api.uri.UriResourceNavigation;
import org.apache.olingo.server.api.uri.queryoption.CountOption; 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 class ExpandSystemQueryOptionHandler {
public void applyExpandQueryOptions(final EntityCollection entitySet, final EdmEntitySet edmEntitySet, 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) { if (expandOption == null) {
return; return;
} }
for (final Entity entity : entitySet.getEntities()) { 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, public void applyExpandQueryOptions(final Entity entity, final EdmEntitySet edmEntitySet,
final ExpandOption expandOption) final ExpandOption expandOption, final UriInfoResource uriInfo, final Edm edm) throws ODataApplicationException {
throws ODataApplicationException {
if (expandOption == null) { if (expandOption == null) {
return; return;
} }
applyExpandOptionToEntity(entity, edmEntitySet, expandOption); applyExpandOptionToEntity(entity, edmEntitySet, expandOption, uriInfo, edm);
} }
private void applyExpandOptionToEntity(final Entity entity, final EdmBindingTarget edmBindingTarget, 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(); final EdmEntityType entityType = edmBindingTarget.getEntityType();
for (ExpandItem item : expandOption.getExpandItems()) { 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 String navPropertyName = navigationProperty.getName();
final EdmBindingTarget targetEdmEntitySet = edmBindingTarget.getRelatedBindingTarget(navPropertyName); final EdmBindingTarget targetEdmEntitySet = edmBindingTarget.getRelatedBindingTarget(navPropertyName);
@ -116,7 +117,8 @@ public class ExpandSystemQueryOptionHandler {
item.getCountOption(), item.getCountOption(),
item.getSkipOption(), item.getSkipOption(),
item.getTopOption(), item.getTopOption(),
item.getExpandOption()); item.getExpandOption(),
uriInfo, edm);
} }
} }
} }
@ -125,11 +127,12 @@ public class ExpandSystemQueryOptionHandler {
private void applyOptionsToEntityCollection(final EntityCollection entitySet, private void applyOptionsToEntityCollection(final EntityCollection entitySet,
final EdmBindingTarget edmBindingTarget, final EdmBindingTarget edmBindingTarget,
final FilterOption filterOption, final OrderByOption orderByOption, final CountOption countOption, 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 { throws ODataApplicationException {
FilterHandler.applyFilterSystemQuery(filterOption, entitySet, edmBindingTarget); FilterHandler.applyFilterSystemQuery(filterOption, entitySet, uriInfo, edm);
OrderByHandler.applyOrderByOption(orderByOption, entitySet, edmBindingTarget); OrderByHandler.applyOrderByOption(orderByOption, entitySet, uriInfo, edm);
CountHandler.applyCountSystemQueryOption(countOption, entitySet); CountHandler.applyCountSystemQueryOption(countOption, entitySet);
SkipHandler.applySkipSystemQueryHandler(skipOption, entitySet); SkipHandler.applySkipSystemQueryHandler(skipOption, entitySet);
TopHandler.applyTopSystemQueryOption(topOption, entitySet); TopHandler.applyTopSystemQueryOption(topOption, entitySet);
@ -137,7 +140,7 @@ public class ExpandSystemQueryOptionHandler {
// Apply nested expand system query options to remaining entities // Apply nested expand system query options to remaining entities
if (expandOption != null) { if (expandOption != null) {
for (final Entity entity : entitySet.getEntities()) { 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.Entity;
import org.apache.olingo.commons.api.data.Property; 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.EdmEnumType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.http.HttpStatusCode; 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> { 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.entity = entity;
this.uriInfo = uriInfo;
this.edm = edm;
} }
@Override @Override
public VisitorOperand visitBinaryOperator(final BinaryOperatorKind operator, final VisitorOperand left, public VisitorOperand visitBinaryOperator(final BinaryOperatorKind operator, final VisitorOperand left,
final VisitorOperand right) final VisitorOperand right) throws ExpressionVisitException, ODataApplicationException {
throws ExpressionVisitException, ODataApplicationException {
final BinaryOperator binaryOperator = new BinaryOperator(left, right); final BinaryOperator binaryOperator = new BinaryOperator(left, right);
@ -84,6 +88,9 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand>
case DIV: case DIV:
case MOD: case MOD:
return binaryOperator.arithmeticOperator(operator); return binaryOperator.arithmeticOperator(operator);
case HAS:
return binaryOperator.hasOperator();
default: default:
return throwNotImplemented(); return throwNotImplemented();
} }
@ -161,15 +168,13 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand>
@Override @Override
public VisitorOperand visitLambdaExpression(final String lambdaFunction, final String lambdaVariable, public VisitorOperand visitLambdaExpression(final String lambdaFunction, final String lambdaVariable,
final Expression expression) final Expression expression) throws ExpressionVisitException, ODataApplicationException {
throws ExpressionVisitException, ODataApplicationException {
return throwNotImplemented(); return throwNotImplemented();
} }
@Override @Override
public VisitorOperand visitLiteral(final Literal literal) throws ExpressionVisitException, ODataApplicationException { public VisitorOperand visitLiteral(final Literal literal) throws ExpressionVisitException, ODataApplicationException {
return new UntypedOperand(literal.getText()); return new UntypedOperand(literal.getText(), edm);
} }
@Override @Override
@ -204,12 +209,12 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand>
@Override @Override
public VisitorOperand visitAlias(final String aliasName) throws ExpressionVisitException, ODataApplicationException { public VisitorOperand visitAlias(final String aliasName) throws ExpressionVisitException, ODataApplicationException {
return throwNotImplemented(); return new UntypedOperand(uriInfo.getValueForAlias(aliasName), edm);
} }
@Override @Override
public VisitorOperand visitTypeLiteral(final EdmType type) throws ExpressionVisitException, public VisitorOperand visitTypeLiteral(final EdmType type)
ODataApplicationException { throws ExpressionVisitException, ODataApplicationException {
return throwNotImplemented(); return throwNotImplemented();
} }
@ -221,9 +226,18 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand>
@Override @Override
public VisitorOperand visitEnum(final EdmEnumType type, final List<String> enumValues) public VisitorOperand visitEnum(final EdmEnumType type, final List<String> enumValues)
throws ExpressionVisitException, throws ExpressionVisitException, ODataApplicationException {
ODataApplicationException { Long result = null;
return throwNotImplemented(); 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 { private VisitorOperand throwNotImplemented() throws ODataApplicationException {

View File

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

View File

@ -168,7 +168,15 @@ public class BinaryOperator {
return new TypedOperand(result, primBoolean); 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) { private boolean binaryComparison(final int... expect) {
int result; int result;
@ -180,13 +188,14 @@ public class BinaryOperator {
result = left.getTypedValue(BigInteger.class).compareTo(right.getTypedValue(BigInteger.class)); result = left.getTypedValue(BigInteger.class).compareTo(right.getTypedValue(BigInteger.class));
} else if (left.isDecimalType()) { } else if (left.isDecimalType()) {
result = left.getTypedValue(BigDecimal.class).compareTo(right.getTypedValue(BigDecimal.class)); result = left.getTypedValue(BigDecimal.class).compareTo(right.getTypedValue(BigDecimal.class));
} else if(left.getValue().getClass() == right.getValue().getClass() && left.getValue() instanceof Comparable) { } else if(left.getValue().getClass() == right.getValue().getClass()
result = ((Comparable)left.getValue()).compareTo(right.getValue()); && left.getValue() instanceof Comparable<?>) {
result = ((Comparable<Object>) left.getValue()).compareTo(right.getValue());
} else { } else {
result = left.getValue().equals(right.getValue()) ? 0 : 1; result = left.getValue().equals(right.getValue()) ? 0 : 1;
} }
} }
for (int expectedValue : expect) { for (int expectedValue : expect) {
if (expectedValue == result) { if (expectedValue == result) {
return true; 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.Entity;
import org.apache.olingo.commons.api.data.EntityCollection; 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.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException; 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.FilterOption;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException; import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.ExpressionVisitorImpl; 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 { public class FilterHandler {
protected static final OData oData; protected static final EdmPrimitiveType primBoolean =
protected static final EdmPrimitiveType primBoolean; OData.newInstance().createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean);
static {
oData = OData.newInstance();
primBoolean = oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean);
}
public static void applyFilterSystemQuery(final FilterOption filterOption, final EntityCollection entitySet, 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) { if (filterOption == null) {
return; return;
@ -57,16 +53,17 @@ public class FilterHandler {
while (iter.hasNext()) { while (iter.hasNext()) {
final VisitorOperand operand = filterOption.getExpression() final VisitorOperand operand = filterOption.getExpression()
.accept(new ExpressionVisitorImpl(iter.next(), edmEntitySet)); .accept(new ExpressionVisitorImpl(iter.next(), uriInfo, edm));
final TypedOperand typedOperand = operand.asTypedOperand(); final TypedOperand typedOperand = operand.asTypedOperand();
if(typedOperand.is(primBoolean)) { if (typedOperand.is(primBoolean)) {
if(Boolean.FALSE.equals(typedOperand.getTypedValue(Boolean.class))) { if (Boolean.FALSE.equals(typedOperand.getTypedValue(Boolean.class))) {
iter.remove(); iter.remove();
} }
} else { } else {
throw new ODataApplicationException("Invalid filter expression. Filter expressions must return a value of " throw new ODataApplicationException(
+ "type Edm.Boolean", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); "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.Entity;
import org.apache.olingo.commons.api.data.EntityCollection; 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.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException; 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.OrderByItem;
import org.apache.olingo.server.api.uri.queryoption.OrderByOption; import org.apache.olingo.server.api.uri.queryoption.OrderByOption;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException; 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 class OrderByHandler {
public static void applyOrderByOption(final OrderByOption orderByOption, final EntityCollection entitySet, 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) { if (orderByOption == null) {
return; return;
} }
try { try {
applyOrderByOptionInternal(orderByOption, entitySet, edmBindingTarget); applyOrderByOptionInternal(orderByOption, entitySet, uriInfo, edm);
} catch (SystemQueryOptionsRuntimeException e) { } catch (SystemQueryOptionsRuntimeException e) {
if (e.getCause() instanceof ODataApplicationException) { if (e.getCause() instanceof ODataApplicationException) {
// Throw the nested exception, to send the correct HTTP status code in the HTTP response // Throw the nested exception, to send the correct HTTP status code in the HTTP response
throw (ODataApplicationException) e.getCause(); throw (ODataApplicationException) e.getCause();
} else { } else {
throw new ODataApplicationException("Exception in orderBy evaluation", HttpStatusCode.INTERNAL_SERVER_ERROR throw new ODataApplicationException("Exception in orderBy evaluation",
.getStatusCode(), Locale.ROOT); HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
} }
} }
} }
private static void applyOrderByOptionInternal(final OrderByOption orderByOption, final EntityCollection entitySet, 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>() { Collections.sort(entitySet.getEntities(), new Comparator<Entity>() {
@Override @Override
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings("unchecked")
public int compare(final Entity e1, final Entity e2) { public int compare(final Entity e1, final Entity e2) {
// Evaluate the first order option for both entity // Evaluate the first order option for both entities.
// If and only if the result of the previous order option is equals to 0 // 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 equals // evaluate the next order option until all options are evaluated or they are not equal.
int result = 0; int result = 0;
for (int i = 0; i < orderByOption.getOrders().size() && result == 0; i++) { for (int i = 0; i < orderByOption.getOrders().size() && result == 0; i++) {
try { try {
final OrderByItem item = orderByOption.getOrders().get(i); final OrderByItem item = orderByOption.getOrders().get(i);
final TypedOperand op1 = final TypedOperand op1 =
item.getExpression().accept(new ExpressionVisitorImpl(e1, edmBindingTarget)).asTypedOperand(); item.getExpression().accept(new ExpressionVisitorImpl(e1, uriInfo, edm)).asTypedOperand();
final TypedOperand op2 = 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()) {
if (op1.isNull() && op2.isNull()) { if (op1.isNull() && op2.isNull()) {
@ -84,7 +85,7 @@ public class OrderByHandler {
Object o2 = op2.getValue(); Object o2 = op2.getValue();
if (o1.getClass() == o2.getClass() && o1 instanceof Comparable) { if (o1.getClass() == o2.getClass() && o1 instanceof Comparable) {
result = ((Comparable) o1).compareTo(o2); result = ((Comparable<Object>) o1).compareTo(o2);
} else { } else {
result = 0; result = 0;
} }