[OLINGO-834] ExpressionParser parses path expressions

Signed-off-by: Christian Amend <christian.amend@sap.com>
This commit is contained in:
Klaus Straubinger 2015-12-18 16:42:51 +01:00 committed by Christian Amend
parent 104ecf43d2
commit a809165896
37 changed files with 1768 additions and 1443 deletions

View File

@ -27,14 +27,8 @@ public abstract class ExpandTreeBuilder {
public abstract ExpandTreeBuilder expand(EdmNavigationProperty edmNavigationProperty);
protected ExpandItemImpl buildExpandItem(final EdmNavigationProperty edmNavigationProperty) {
final ExpandItemImpl expandItem = new ExpandItemImpl();
final UriInfoImpl uriInfo = new UriInfoImpl();
final UriResourceNavigationPropertyImpl resourceNavigation = new UriResourceNavigationPropertyImpl();
resourceNavigation.setNavigationProperty(edmNavigationProperty);
uriInfo.addResourcePart(resourceNavigation);
expandItem.setResourcePath(uriInfo);
return expandItem;
return new ExpandItemImpl()
.setResourcePath(new UriInfoImpl()
.addResourcePart(new UriResourceNavigationPropertyImpl(edmNavigationProperty)));
}
}
}

View File

@ -31,11 +31,19 @@ import org.apache.olingo.server.api.uri.UriResourceKind;
*/
public class UriResourceActionImpl extends UriResourceImpl implements UriResourceAction {
protected EdmAction action;
protected EdmActionImport actionImport;
private final EdmActionImport actionImport;
private final EdmAction action;
public UriResourceActionImpl() {
public UriResourceActionImpl(final EdmActionImport actionImport) {
super(UriResourceKind.action);
this.actionImport = actionImport;
this.action = actionImport.getUnboundAction();
}
public UriResourceActionImpl(final EdmAction action) {
super(UriResourceKind.action);
this.actionImport = null;
this.action = action;
}
@Override
@ -43,38 +51,21 @@ public class UriResourceActionImpl extends UriResourceImpl implements UriResourc
return action;
}
public UriResourceActionImpl setAction(final EdmAction action) {
this.action = action;
return this;
}
@Override
public EdmActionImport getActionImport() {
return actionImport;
}
public UriResourceActionImpl setActionImport(final EdmActionImport actionImport) {
this.actionImport = actionImport;
setAction(actionImport.getUnboundAction());
return this;
}
@Override
public boolean isCollection() {
if (action.getReturnType() != null) {
return action.getReturnType().isCollection();
}
return false;
return action.getReturnType() != null && action.getReturnType().isCollection();
}
@Override
public EdmType getType() {
if (action.getReturnType() != null) {
return action.getReturnType().getType();
}
return null;
return action.getReturnType() == null ? null : action.getReturnType().getType();
}
@Override
public String getSegmentValue(final boolean includeFilters) {
return actionImport == null ? (action == null ? "" : action.getName()) : actionImport.getName();
@ -84,14 +75,9 @@ public class UriResourceActionImpl extends UriResourceImpl implements UriResourc
public String getSegmentValue() {
return getSegmentValue(false);
}
@Override
public String toString(final boolean includeFilters) {
return getSegmentValue(includeFilters);
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -26,10 +26,11 @@ import org.apache.olingo.server.api.uri.UriResourceKind;
public class UriResourceComplexPropertyImpl extends UriResourceTypedImpl implements UriResourceComplexProperty {
protected EdmProperty property;
private final EdmProperty property;
public UriResourceComplexPropertyImpl() {
public UriResourceComplexPropertyImpl(final EdmProperty property) {
super(UriResourceKind.complexProperty);
this.property = property;
}
@Override
@ -37,11 +38,6 @@ public class UriResourceComplexPropertyImpl extends UriResourceTypedImpl impleme
return property;
}
public UriResourceComplexPropertyImpl setProperty(final EdmProperty property) {
this.property = property;
return this;
}
@Override
public EdmComplexType getComplexType() {
return (EdmComplexType) getType();
@ -63,13 +59,7 @@ public class UriResourceComplexPropertyImpl extends UriResourceTypedImpl impleme
}
@Override
public String getSegmentValue(){
public String getSegmentValue() {
return property.getName();
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -26,15 +26,9 @@ public class UriResourceCountImpl extends UriResourceImpl implements UriResource
public UriResourceCountImpl() {
super(UriResourceKind.count);
}
@Override
public String getSegmentValue(){
public String getSegmentValue() {
return "$count";
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -25,10 +25,12 @@ import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.UriResourceKind;
public class UriResourceEntitySetImpl extends UriResourceWithKeysImpl implements UriResourceEntitySet {
protected EdmEntitySet edmEntitySet = null;
public UriResourceEntitySetImpl() {
private final EdmEntitySet edmEntitySet;
public UriResourceEntitySetImpl(final EdmEntitySet edmEntitySet) {
super(UriResourceKind.entitySet);
this.edmEntitySet = edmEntitySet;
}
@Override
@ -36,11 +38,6 @@ public class UriResourceEntitySetImpl extends UriResourceWithKeysImpl implements
return edmEntitySet;
}
public UriResourceEntitySetImpl setEntitSet(final EdmEntitySet edmES) {
edmEntitySet = edmES;
return this;
}
@Override
public EdmEntityType getEntityType() {
return edmEntitySet.getEntityType();
@ -57,13 +54,7 @@ public class UriResourceEntitySetImpl extends UriResourceWithKeysImpl implements
}
@Override
public String getSegmentValue(){
public String getSegmentValue() {
return edmEntitySet.getName();
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -33,13 +33,16 @@ import org.apache.olingo.server.api.uri.UriResourceKind;
*/
public class UriResourceFunctionImpl extends UriResourceWithKeysImpl implements UriResourceFunction {
protected List<UriParameter> parameters;
protected EdmFunction function;
protected EdmFunctionImport functionImport;
private boolean isParameterListFilled = false;
private final EdmFunctionImport functionImport;
private final EdmFunction function;
private final List<UriParameter> parameters;
public UriResourceFunctionImpl() {
public UriResourceFunctionImpl(final EdmFunctionImport edmFunctionImport, final EdmFunction function,
final List<UriParameter> parameters) {
super(UriResourceKind.function);
this.functionImport = edmFunctionImport;
this.function = function;
this.parameters = parameters;
}
@Override
@ -49,34 +52,16 @@ public class UriResourceFunctionImpl extends UriResourceWithKeysImpl implements
Collections.unmodifiableList(parameters);
}
public UriResourceFunctionImpl setParameters(final List<UriParameter> parameters) {
isParameterListFilled = true;
this.parameters = parameters;
return this;
}
@Override
public EdmFunction getFunction() {
return function;
}
public UriResourceFunctionImpl setFunction(final EdmFunction function) {
this.function = function;
return this;
}
@Override
public EdmFunctionImport getFunctionImport() {
return functionImport;
}
public UriResourceFunctionImpl setFunctionImport(final EdmFunctionImport edmFunctionImport,
final List<UriParameter> parameters) {
functionImport = edmFunctionImport;
setParameters(parameters);
return this;
}
@Override
public EdmType getType() {
return function.getReturnType().getType();
@ -89,21 +74,6 @@ public class UriResourceFunctionImpl extends UriResourceWithKeysImpl implements
@Override
public String getSegmentValue() {
if (functionImport != null) {
return functionImport.getName();
} else if (function != null) {
return function.getName();
}
return "";
return functionImport == null ? (function == null ? "" : function.getName()) : functionImport.getName();
}
@Override
public String toString() {
return getSegmentValue();
}
public boolean isParameterListFilled() {
return isParameterListFilled;
}
}

View File

@ -22,7 +22,7 @@ import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceKind;
/**
* Covers Functionimports and BoundFunction in URI
* Abstract class for resource-path elements in URI.
*/
public abstract class UriResourceImpl implements UriResource {
protected UriResourceKind kind;
@ -36,4 +36,8 @@ public abstract class UriResourceImpl implements UriResource {
return kind;
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -27,11 +27,13 @@ import org.apache.olingo.server.api.uri.UriResourceKind;
*/
public class UriResourceItImpl extends UriResourceWithKeysImpl implements UriResourceIt {
private EdmType type;
private boolean isCollection;
private final EdmType type;
private final boolean isCollection;
public UriResourceItImpl() {
public UriResourceItImpl(final EdmType type, final boolean isCollection) {
super(UriResourceKind.it);
this.type = type;
this.isCollection = isCollection;
}
@Override
@ -39,32 +41,13 @@ public class UriResourceItImpl extends UriResourceWithKeysImpl implements UriRes
return type;
}
public UriResourceItImpl setType(final EdmType type) {
this.type = type;
return this;
}
@Override
public boolean isCollection() {
if (keyPredicates != null) {
return false;
}
return isCollection;
return keyPredicates == null && isCollection;
}
public UriResourceItImpl setCollection(final boolean isCollection) {
this.isCollection = isCollection;
return this;
}
@Override
public String getSegmentValue(){
public String getSegmentValue() {
return "$it";
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -19,7 +19,6 @@
package org.apache.olingo.server.core.uri;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
import org.apache.olingo.server.api.uri.UriResourceKind;
@ -28,12 +27,13 @@ import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
public class UriResourceLambdaAllImpl extends UriResourceTypedImpl implements UriResourceLambdaAll {
protected EdmProperty property;
private String lambdaVariable;
private Expression expression;
private final String lambdaVariable;
private final Expression expression;
public UriResourceLambdaAllImpl() {
public UriResourceLambdaAllImpl(final String lambdaVariable, final Expression expression) {
super(UriResourceKind.lambdaAll);
this.lambdaVariable = lambdaVariable;
this.expression = expression;
}
@Override
@ -51,29 +51,13 @@ public class UriResourceLambdaAllImpl extends UriResourceTypedImpl implements Ur
return lambdaVariable;
}
public UriResourceLambdaAllImpl setLamdaVariable(final String lambdaVariable) {
this.lambdaVariable = lambdaVariable;
return this;
}
@Override
public Expression getExpression() {
return expression;
}
public UriResourceLambdaAllImpl setExpression(final Expression expression) {
this.expression = expression;
return this;
}
@Override
public String getSegmentValue() {
return "all";
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -19,7 +19,6 @@
package org.apache.olingo.server.core.uri;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
import org.apache.olingo.server.api.uri.UriResourceKind;
@ -28,12 +27,13 @@ import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
public class UriResourceLambdaAnyImpl extends UriResourceTypedImpl implements UriResourceLambdaAny {
protected EdmProperty property;
private String lambdaVariable;
private Expression expression;
private final String lambdaVariable;
private final Expression expression;
public UriResourceLambdaAnyImpl() {
public UriResourceLambdaAnyImpl(final String lambdaVariable, final Expression expression) {
super(UriResourceKind.lambdaAny);
this.lambdaVariable = lambdaVariable;
this.expression = expression;
}
@Override
@ -51,28 +51,13 @@ public class UriResourceLambdaAnyImpl extends UriResourceTypedImpl implements Ur
return lambdaVariable;
}
public UriResourceLambdaAnyImpl setLamdaVariable(final String lambdaVariable) {
this.lambdaVariable = lambdaVariable;
return this;
}
@Override
public Expression getExpression() {
return expression;
}
public UriResourceLambdaAnyImpl setExpression(final Expression expression) {
this.expression = expression;
return this;
}
@Override
public String getSegmentValue() {
return "any";
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -24,12 +24,13 @@ import org.apache.olingo.server.api.uri.UriResourceLambdaVariable;
public class UriResourceLambdaVarImpl extends UriResourceTypedImpl implements UriResourceLambdaVariable {
private EdmType type;
private boolean isCollection;
private String variableText;
private final String variableText;
private final EdmType type;
public UriResourceLambdaVarImpl() {
public UriResourceLambdaVarImpl(final String variableText, final EdmType type) {
super(UriResourceKind.lambdaVariable);
this.variableText = variableText;
this.type = type;
}
@Override
@ -37,39 +38,18 @@ public class UriResourceLambdaVarImpl extends UriResourceTypedImpl implements Ur
return variableText;
}
public UriResourceLambdaVarImpl setVariableText(final String variableText) {
this.variableText = variableText;
return this;
}
@Override
public EdmType getType() {
return type;
}
public UriResourceLambdaVarImpl setType(final EdmType type) {
this.type = type;
return this;
}
@Override
public boolean isCollection() {
return isCollection;
}
public UriResourceLambdaVarImpl setCollection(final boolean isCollection) {
this.isCollection = isCollection;
return this;
return false;
}
@Override
public String getSegmentValue() {
return variableText;
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -25,10 +25,11 @@ import org.apache.olingo.server.api.uri.UriResourceNavigation;
public class UriResourceNavigationPropertyImpl extends UriResourceWithKeysImpl implements UriResourceNavigation {
protected EdmNavigationProperty navigationProperty;
private final EdmNavigationProperty navigationProperty;
public UriResourceNavigationPropertyImpl() {
public UriResourceNavigationPropertyImpl(final EdmNavigationProperty property) {
super(UriResourceKind.navigationProperty);
navigationProperty = property;
}
@Override
@ -36,12 +37,6 @@ public class UriResourceNavigationPropertyImpl extends UriResourceWithKeysImpl i
return navigationProperty;
}
public UriResourceNavigationPropertyImpl setNavigationProperty(final EdmNavigationProperty property) {
navigationProperty = property;
return this;
}
@Override
public EdmType getType() {
return navigationProperty.getType();
@ -51,15 +46,9 @@ public class UriResourceNavigationPropertyImpl extends UriResourceWithKeysImpl i
public boolean isCollection() {
return navigationProperty.isCollection() && keyPredicates == null;
}
@Override
public String getSegmentValue(){
public String getSegmentValue() {
return navigationProperty.getName();
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -25,10 +25,11 @@ import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty;
public class UriResourcePrimitivePropertyImpl extends UriResourceTypedImpl implements UriResourcePrimitiveProperty {
EdmProperty property;
private final EdmProperty property;
public UriResourcePrimitivePropertyImpl() {
public UriResourcePrimitivePropertyImpl(final EdmProperty property) {
super(UriResourceKind.primitiveProperty);
this.property = property;
}
@Override
@ -36,11 +37,6 @@ public class UriResourcePrimitivePropertyImpl extends UriResourceTypedImpl imple
return property;
}
public UriResourcePrimitivePropertyImpl setProperty(final EdmProperty property) {
this.property = property;
return this;
}
@Override
public EdmType getType() {
return property.getType();
@ -50,15 +46,9 @@ public class UriResourcePrimitivePropertyImpl extends UriResourceTypedImpl imple
public boolean isCollection() {
return property.isCollection();
}
@Override
public String getSegmentValue(){
return property.getName();
}
@Override
public String toString() {
return getSegmentValue();
public String getSegmentValue() {
return property.getName();
}
}

View File

@ -25,16 +25,10 @@ public class UriResourceRefImpl extends UriResourceImpl implements UriResourceRe
public UriResourceRefImpl() {
super(UriResourceKind.ref);
}
@Override
public String getSegmentValue(){
public String getSegmentValue() {
return "$ref";
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -24,11 +24,13 @@ import org.apache.olingo.server.api.uri.UriResourceRoot;
public class UriResourceRootImpl extends UriResourceWithKeysImpl implements UriResourceRoot {
private EdmType type;
private boolean isCollection;
private final EdmType type;
private final boolean isCollection;
public UriResourceRootImpl() {
public UriResourceRootImpl(final EdmType type, final boolean isCollection) {
super(UriResourceKind.root);
this.type = type;
this.isCollection = isCollection;
}
@Override
@ -36,32 +38,13 @@ public class UriResourceRootImpl extends UriResourceWithKeysImpl implements UriR
return type;
}
public UriResourceRootImpl setType(final EdmType type) {
this.type = type;
return this;
}
@Override
public boolean isCollection() {
if (keyPredicates != null) {
return false;
}
return isCollection;
return keyPredicates == null && isCollection;
}
public UriResourceRootImpl setCollection(final boolean isCollection) {
this.isCollection = isCollection;
return this;
}
@Override
public String getSegmentValue(){
public String getSegmentValue() {
return "$root";
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -26,10 +26,11 @@ import org.apache.olingo.server.api.uri.UriResourceSingleton;
public class UriResourceSingletonImpl extends UriResourceTypedImpl implements UriResourceSingleton {
private EdmSingleton singleton;
private final EdmSingleton singleton;
public UriResourceSingletonImpl() {
public UriResourceSingletonImpl(final EdmSingleton singleton) {
super(UriResourceKind.singleton);
this.singleton = singleton;
}
@Override
@ -37,12 +38,6 @@ public class UriResourceSingletonImpl extends UriResourceTypedImpl implements Ur
return singleton;
}
public UriResourceSingletonImpl setSingleton(final EdmSingleton singleton) {
this.singleton = singleton;
return this;
}
@Override
public EdmEntityType getEntityTypeFilter() {
return (EdmEntityType) typeFilter;
@ -62,15 +57,9 @@ public class UriResourceSingletonImpl extends UriResourceTypedImpl implements Ur
public boolean isCollection() {
return false;
}
@Override
public String getSegmentValue(){
public String getSegmentValue() {
return singleton.getName();
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -23,11 +23,13 @@ import org.apache.olingo.server.api.uri.UriResourceKind;
public class UriResourceStartingTypeFilterImpl extends UriResourceWithKeysImpl {
private EdmType type;
private boolean isCollection;
private final EdmType type;
private final boolean isCollection;
public UriResourceStartingTypeFilterImpl() {
public UriResourceStartingTypeFilterImpl(final EdmType type, final boolean isCollection) {
super(null);
this.type = type;
this.isCollection = isCollection;
}
@Override
@ -40,32 +42,13 @@ public class UriResourceStartingTypeFilterImpl extends UriResourceWithKeysImpl {
return type;
}
public UriResourceStartingTypeFilterImpl setType(final EdmType type) {
this.type = type;
return this;
}
@Override
public boolean isCollection() {
if (keyPredicates != null) {
return false;
}
return isCollection;
}
public UriResourceStartingTypeFilterImpl setCollection(final boolean isCollection) {
this.isCollection = isCollection;
return this;
return keyPredicates == null && isCollection;
}
@Override
public String getSegmentValue(){
return type.getNamespace() + "." + type.getName();
public String getSegmentValue() {
return type.getFullQualifiedName().getFullQualifiedNameAsString();
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -41,14 +41,9 @@ public abstract class UriResourceTypedImpl extends UriResourceImpl implements Ur
}
public String getSegmentValue(final boolean includeFilters) {
if (includeFilters) {
if (typeFilter != null) {
return getSegmentValue() + "/" + typeFilter.getFullQualifiedName().toString();
} else {
return getSegmentValue();
}
}
return getSegmentValue();
return includeFilters && typeFilter != null ?
getSegmentValue() + "/" + typeFilter.getFullQualifiedName().getFullQualifiedNameAsString() :
getSegmentValue();
}
@Override

View File

@ -25,17 +25,10 @@ public class UriResourceValueImpl extends UriResourceImpl implements UriResource
public UriResourceValueImpl() {
super(UriResourceKind.value);
}
@Override
public String getSegmentValue(){
public String getSegmentValue() {
return "$value";
}
@Override
public String toString() {
return getSegmentValue();
}
}

View File

@ -18,20 +18,41 @@
*/
package org.apache.olingo.server.core.uri.parser;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmComplexType;
import org.apache.olingo.commons.api.edm.EdmElement;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmEnumType;
import org.apache.olingo.commons.api.edm.EdmFunction;
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmReturnType;
import org.apache.olingo.commons.api.edm.EdmSingleton;
import org.apache.olingo.commons.api.edm.EdmStructuredType;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.edm.EdmTypeDefinition;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.UriResourceFunction;
import org.apache.olingo.server.api.uri.UriResourceLambdaVariable;
import org.apache.olingo.server.api.uri.UriResourceNavigation;
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
import org.apache.olingo.server.api.uri.queryoption.expression.Alias;
import org.apache.olingo.server.api.uri.queryoption.expression.Binary;
import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
@ -45,12 +66,32 @@ import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
import org.apache.olingo.server.api.uri.queryoption.expression.TypeLiteral;
import org.apache.olingo.server.api.uri.queryoption.expression.Unary;
import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
import org.apache.olingo.server.core.uri.UriInfoImpl;
import org.apache.olingo.server.core.uri.UriResourceComplexPropertyImpl;
import org.apache.olingo.server.core.uri.UriResourceCountImpl;
import org.apache.olingo.server.core.uri.UriResourceEntitySetImpl;
import org.apache.olingo.server.core.uri.UriResourceFunctionImpl;
import org.apache.olingo.server.core.uri.UriResourceItImpl;
import org.apache.olingo.server.core.uri.UriResourceLambdaAllImpl;
import org.apache.olingo.server.core.uri.UriResourceLambdaAnyImpl;
import org.apache.olingo.server.core.uri.UriResourceLambdaVarImpl;
import org.apache.olingo.server.core.uri.UriResourceNavigationPropertyImpl;
import org.apache.olingo.server.core.uri.UriResourcePrimitivePropertyImpl;
import org.apache.olingo.server.core.uri.UriResourceRootImpl;
import org.apache.olingo.server.core.uri.UriResourceSingletonImpl;
import org.apache.olingo.server.core.uri.UriResourceStartingTypeFilterImpl;
import org.apache.olingo.server.core.uri.UriResourceTypedImpl;
import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
import org.apache.olingo.server.core.uri.queryoption.expression.AliasImpl;
import org.apache.olingo.server.core.uri.queryoption.expression.BinaryImpl;
import org.apache.olingo.server.core.uri.queryoption.expression.EnumerationImpl;
import org.apache.olingo.server.core.uri.queryoption.expression.LiteralImpl;
import org.apache.olingo.server.core.uri.queryoption.expression.MemberImpl;
import org.apache.olingo.server.core.uri.queryoption.expression.MethodImpl;
import org.apache.olingo.server.core.uri.queryoption.expression.TypeLiteralImpl;
import org.apache.olingo.server.core.uri.queryoption.expression.UnaryImpl;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
public class ExpressionParser {
private static final Map<TokenKind, BinaryOperatorKind> tokenToBinaryOperator;
@ -129,7 +170,7 @@ public class ExpressionParser {
Map<TokenKind, EdmPrimitiveTypeKind> temp = new HashMap<TokenKind, EdmPrimitiveTypeKind>();
temp.put(TokenKind.BooleanValue, EdmPrimitiveTypeKind.Boolean);
temp.put(TokenKind.StringValue, EdmPrimitiveTypeKind.String);
// TODO:Check if int64 is correct here or if it has to be single instead
// TODO: Check if int64 is correct here or if it has to be decimal or single or double instead.
temp.put(TokenKind.IntegerValue, EdmPrimitiveTypeKind.Int64);
temp.put(TokenKind.GuidValue, EdmPrimitiveTypeKind.Guid);
temp.put(TokenKind.DateValue, EdmPrimitiveTypeKind.Date);
@ -147,20 +188,27 @@ public class ExpressionParser {
private final OData odata;
private UriTokenizer tokenizer;
private Deque<UriResourceLambdaVariable> lambdaVariables = new ArrayDeque<UriResourceLambdaVariable>();
private EdmType referringType;
private Collection<String> crossjoinEntitySetNames;
public ExpressionParser(final Edm edm, final OData odata) {
this.edm = edm;
this.odata = odata;
}
public Expression parse(UriTokenizer tokenizer) throws UriParserException {
public Expression parse(UriTokenizer tokenizer, final EdmType referringType,
final Collection<String> crossjoinEntitySetNames)
throws UriParserException, UriValidationException {
// Initialize tokenizer.
this.tokenizer = tokenizer;
this.referringType = referringType;
this.crossjoinEntitySetNames = crossjoinEntitySetNames;
return parseExpression();
}
private Expression parseExpression() throws UriParserException {
private Expression parseExpression() throws UriParserException, UriValidationException {
Expression left = parseAnd();
while (tokenizer.next(TokenKind.OrOperator)) {
final Expression right = parseAnd();
@ -172,7 +220,7 @@ public class ExpressionParser {
return left;
}
private Expression parseAnd() throws UriParserException {
private Expression parseAnd() throws UriParserException, UriValidationException {
Expression left = parseExprEquality();
while (tokenizer.next(TokenKind.AndOperator)) {
final Expression right = parseExprEquality();
@ -184,7 +232,7 @@ public class ExpressionParser {
return left;
}
private Expression parseExprEquality() throws UriParserException {
private Expression parseExprEquality() throws UriParserException, UriValidationException {
Expression left = parseExprRel();
TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.EqualsOperator, TokenKind.NotEqualsOperator);
// Null for everything other than EQ or NE
@ -199,7 +247,7 @@ public class ExpressionParser {
}
// TODO: The 'isof' method has relational precedence and should appear here.
private Expression parseExprRel() throws UriParserException {
private Expression parseExprRel() throws UriParserException, UriValidationException {
Expression left = parseExprAdd();
TokenKind operatorTokenKind = ParserHelper.next(tokenizer,
TokenKind.GreaterThanOperator, TokenKind.GreaterThanOrEqualsOperator,
@ -217,7 +265,7 @@ public class ExpressionParser {
return left;
}
private Expression parseExprAdd() throws UriParserException {
private Expression parseExprAdd() throws UriParserException, UriValidationException {
Expression left = parseExprMul();
TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.AddOperator, TokenKind.SubOperator);
// Null for everything other than ADD or SUB
@ -231,7 +279,7 @@ public class ExpressionParser {
return left;
}
private Expression parseExprMul() throws UriParserException {
private Expression parseExprMul() throws UriParserException, UriValidationException {
Expression left = parseExprUnary();
TokenKind operatorTokenKind = ParserHelper.next(tokenizer,
TokenKind.MulOperator, TokenKind.DivOperator, TokenKind.ModOperator);
@ -255,7 +303,22 @@ public class ExpressionParser {
}
// TODO: The 'cast' method has unary precedence and should appear here.
private Expression parseExprUnary() throws UriParserException {
private Expression parseExprUnary() throws UriParserException, UriValidationException {
// Negative numbers start with a minus indistinguishable from an unary minus operator.
// So we read numbers (and primitive values starting with numbers) right here.
// TODO: Find a better idea how to solve this problem.
final TokenKind numberTokenKind = ParserHelper.next(tokenizer,
TokenKind.DoubleValue, TokenKind.DecimalValue, TokenKind.GuidValue,
TokenKind.DateTimeOffsetValue, TokenKind.DateValue, TokenKind.TimeOfDayValue,
TokenKind.IntegerValue);
if (numberTokenKind != null) {
final EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(numberTokenKind);
final EdmPrimitiveType type = primitiveTypeKind == null ?
// Null handling
null :
odata.createPrimitiveTypeInstance(primitiveTypeKind);
return new LiteralImpl(tokenizer.getText(), type);
}
Expression left = null;
TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.MINUS, TokenKind.NotOperator);
// Null for everything other than - or NOT
@ -279,13 +342,11 @@ public class ExpressionParser {
return left;
}
private Expression parseExprPrimary() throws UriParserException {
private Expression parseExprPrimary() throws UriParserException, UriValidationException {
final Expression left = parseExprValue();
if (isEnumType(left) && tokenizer.next(TokenKind.HasOperator)) {
ParserHelper.requireNext(tokenizer, TokenKind.EnumValue);
final String primitiveValueLiteral = tokenizer.getText();
final Expression right = new LiteralImpl(primitiveValueLiteral, getEnumType(primitiveValueLiteral));
checkEnumLiteral(right);
final Expression right = createEnumExpression(tokenizer.getText());
return new BinaryImpl(left, BinaryOperatorKind.HAS, right,
odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean));
} else {
@ -293,7 +354,7 @@ public class ExpressionParser {
}
}
private Expression parseExprValue() throws UriParserException {
private Expression parseExprValue() throws UriParserException, UriValidationException {
if (tokenizer.next(TokenKind.OPEN)) {
final Expression expression = parseExpression();
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
@ -310,51 +371,49 @@ public class ExpressionParser {
}
if (tokenizer.next(TokenKind.ROOT)) {
// TODO: Consume $root expression.
return parseFirstMemberExpr(TokenKind.ROOT);
}
if (tokenizer.next(TokenKind.IT)) {
// TODO: Consume $it expression.
return parseFirstMemberExpr(TokenKind.IT);
}
TokenKind nextPrimitive = ParserHelper.nextPrimitive(tokenizer);
final TokenKind nextPrimitive = ParserHelper.nextPrimitiveValue(tokenizer);
if (nextPrimitive != null) {
final String primitiveValueLiteral = tokenizer.getText();
final EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
EdmPrimitiveType type;
if (primitiveTypeKind == null) {
if (nextPrimitive == TokenKind.EnumValue) {
type = getEnumType(primitiveValueLiteral);
} else {
// Null handling
type = null;
}
if (nextPrimitive == TokenKind.EnumValue) {
return createEnumExpression(primitiveValueLiteral);
} else {
type = odata.createPrimitiveTypeInstance(primitiveTypeKind);
final EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
final EdmPrimitiveType type = primitiveTypeKind == null ?
// Null handling
null :
odata.createPrimitiveTypeInstance(primitiveTypeKind);
return new LiteralImpl(primitiveValueLiteral, type);
}
return new LiteralImpl(primitiveValueLiteral, type);
}
// The method token text includes the opening parenthesis so that method calls can be recognized unambiguously.
// OData identifiers have to be considered after that.
TokenKind nextMethod = nextMethod();
final TokenKind nextMethod = nextMethod();
if (nextMethod != null) {
MethodKind methodKind = tokenToMethod.get(nextMethod);
return new MethodImpl(methodKind, parseMethodParameters(methodKind));
}
if (tokenizer.next(TokenKind.QualifiedName)) {
// TODO: Consume typecast or bound-function expression.
return parseFirstMemberExpr(TokenKind.QualifiedName);
}
if (tokenizer.next(TokenKind.ODataIdentifier)) {
// TODO: Consume property-path or lambda-variable expression.
return parseFirstMemberExpr(TokenKind.ODataIdentifier);
}
throw new UriParserSyntaxException("Unexpected token", UriParserSyntaxException.MessageKeys.SYNTAX);
throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
}
private List<Expression> parseMethodParameters(final MethodKind methodKind) throws UriParserException {
private List<Expression> parseMethodParameters(final MethodKind methodKind)
throws UriParserException, UriValidationException {
List<Expression> parameters = new ArrayList<Expression>();
switch (methodKind) {
// Must have no parameter.
@ -477,6 +536,411 @@ public class ExpressionParser {
return parameters;
}
private Expression parseFirstMemberExpr(final TokenKind lastTokenKind)
throws UriParserException, UriValidationException {
final UriInfoImpl uriInfo = new UriInfoImpl();
EdmType startTypeFilter = null;
if (lastTokenKind == TokenKind.ROOT) {
parseDollarRoot(uriInfo);
} else if (lastTokenKind == TokenKind.IT) {
parseDollarIt(uriInfo);
} else if (lastTokenKind == TokenKind.ODataIdentifier) {
parseFirstMemberODataIdentifier(uriInfo);
} else if (lastTokenKind == TokenKind.QualifiedName) {
// Special handling for leading type casts and type literals
final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
EdmStructuredType structuredType = edm.getEntityType(fullQualifiedName);
if (structuredType == null) {
structuredType = edm.getComplexType(fullQualifiedName);
}
if (structuredType != null) {
if (tokenizer.next(TokenKind.SLASH)) {
// Leading type cast
checkStructuredTypeFilter(referringType, structuredType);
startTypeFilter = structuredType;
final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
parseMemberExpression(tokenKind, uriInfo, new UriResourceStartingTypeFilterImpl(structuredType, false),
false);
} else {
// Type literal
checkStructuredTypeFilter(referringType, structuredType);
return new TypeLiteralImpl(structuredType);
}
} else {
// Must be bound or unbound function. // TODO: Is unbound function allowed?
parseFunction(fullQualifiedName, uriInfo, referringType, true);
}
}
return new MemberImpl(uriInfo, startTypeFilter);
}
private void parseDollarRoot(UriInfoImpl uriInfo) throws UriParserException, UriValidationException {
UriResourceRootImpl rootResource = new UriResourceRootImpl(referringType, true);
uriInfo.addResourcePart(rootResource);
ParserHelper.requireNext(tokenizer, TokenKind.SLASH);
ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
final String name = tokenizer.getText();
UriResourcePartTyped resource = null;
final EdmEntitySet entitySet = edm.getEntityContainer().getEntitySet(name);
if (entitySet == null) {
final EdmSingleton singleton = edm.getEntityContainer().getSingleton(name);
if (singleton == null) {
throw new UriParserSemanticException("EntitySet or singleton expected.",
UriParserSemanticException.MessageKeys.UNKNOWN_PART, name);
} else {
resource = new UriResourceSingletonImpl(singleton);
}
} else {
ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
final List<UriParameter> keyPredicates =
ParserHelper.parseKeyPredicate(tokenizer, entitySet.getEntityType(), null);
resource = new UriResourceEntitySetImpl(entitySet).setKeyPredicates(keyPredicates);
}
uriInfo.addResourcePart(resource);
parseSingleNavigationExpr(uriInfo, resource);
}
private void parseDollarIt(UriInfoImpl uriInfo) throws UriParserException, UriValidationException {
UriResourceItImpl itResource = new UriResourceItImpl(referringType,
referringType instanceof EdmEntityType); // TODO: Determine isCollection.
uriInfo.addResourcePart(itResource);
if (tokenizer.next(TokenKind.SLASH)) {
final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
parseMemberExpression(tokenKind, uriInfo, itResource, true);
}
}
private void parseFirstMemberODataIdentifier(UriInfoImpl uriInfo) throws UriParserException, UriValidationException {
final String name = tokenizer.getText();
// For a crossjoin, the identifier must be an entity-set name.
if (crossjoinEntitySetNames != null && !crossjoinEntitySetNames.isEmpty()) {
if (crossjoinEntitySetNames.contains(name)) {
final UriResourceEntitySetImpl resource =
new UriResourceEntitySetImpl(edm.getEntityContainer().getEntitySet(name));
uriInfo.addResourcePart(resource);
if (tokenizer.next(TokenKind.SLASH)) {
final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
parseMemberExpression(tokenKind, uriInfo, resource, true);
}
return;
} else {
throw new UriParserSemanticException("Unknown crossjoin entity set.",
UriParserSemanticException.MessageKeys.UNKNOWN_PART, name);
}
}
// Check if the OData identifier is a lambda variable, otherwise it must be a property.
UriResourceLambdaVariable lambdaVariable = null;
for (final UriResourceLambdaVariable variable : lambdaVariables) {
if (variable.getVariableName().equals(name)) {
lambdaVariable = variable;
break;
}
}
if (lambdaVariable != null) {
// Copy lambda variable into new resource, just in case ...
final UriResourceLambdaVariable lambdaResource =
new UriResourceLambdaVarImpl(lambdaVariable.getVariableName(), lambdaVariable.getType());
uriInfo.addResourcePart(lambdaResource);
if (tokenizer.next(TokenKind.SLASH)) {
final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
parseMemberExpression(tokenKind, uriInfo, lambdaResource, true);
}
} else {
// Must be a property.
parseMemberExpression(TokenKind.ODataIdentifier, uriInfo, null, true); // TODO: Find last resource.
}
}
private void parseMemberExpression(final TokenKind lastTokenKind, UriInfoImpl uriInfo,
final UriResourcePartTyped lastResource, final boolean allowTypeFilter)
throws UriParserException, UriValidationException {
if (lastTokenKind == TokenKind.QualifiedName) {
// Type cast or bound function
final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
final EdmEntityType edmEntityType = edm.getEntityType(fullQualifiedName);
if (edmEntityType != null) {
if (allowTypeFilter) {
setTypeFilter(lastResource, edmEntityType);
} else {
throw new UriParserSemanticException("Type filters are not chainable.",
UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
lastResource.getType().getFullQualifiedName().getFullQualifiedNameAsString(),
fullQualifiedName.getFullQualifiedNameAsString());
}
} else {
parseBoundFunction(fullQualifiedName, uriInfo, lastResource);
}
} else if (lastTokenKind == TokenKind.ODataIdentifier) {
parsePropertyPathExpr(uriInfo, lastResource);
} else {
throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
}
}
private void setTypeFilter(UriResourcePartTyped lastResource, final EdmEntityType entityTypeFilter)
throws UriParserException {
checkStructuredTypeFilter(lastResource.getType(), entityTypeFilter);
if (lastResource instanceof UriResourceTypedImpl) {
((UriResourceTypedImpl) lastResource).setTypeFilter(entityTypeFilter);
} else if (lastResource instanceof UriResourceWithKeysImpl) {
((UriResourceWithKeysImpl) lastResource).setEntryTypeFilter(entityTypeFilter);
}
}
private void parsePropertyPathExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
throws UriParserException, UriValidationException {
final String oDataIdentifier = tokenizer.getText();
final EdmType lastType = lastResource == null ? referringType : ParserHelper.getTypeInformation(lastResource);
if (!(lastType instanceof EdmStructuredType)) {
throw new UriParserSemanticException("Property paths must follow a structured type.",
UriParserSemanticException.MessageKeys.ONLY_FOR_STRUCTURAL_TYPES, oDataIdentifier);
}
final EdmStructuredType structuredType = (EdmStructuredType) lastType;
final EdmElement property = structuredType.getProperty(oDataIdentifier);
if (property == null) {
throw new UriParserSemanticException("Unknown property.",
UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE, oDataIdentifier);
}
if (property.getType() instanceof EdmComplexType) {
final UriResourceComplexPropertyImpl complexResource =
new UriResourceComplexPropertyImpl((EdmProperty) property);
uriInfo.addResourcePart(complexResource);
if (property.isCollection()) {
parseCollectionPathExpr(uriInfo, complexResource);
} else {
parseComplexPathExpr(uriInfo, complexResource);
}
} else if (property instanceof EdmNavigationProperty) {
// Nav. property; maybe a collection
final UriResourceNavigationPropertyImpl navigationResource =
new UriResourceNavigationPropertyImpl((EdmNavigationProperty) property);
navigationResource.setKeyPredicates(
ParserHelper.parseNavigationKeyPredicate(tokenizer, (EdmNavigationProperty) property));
uriInfo.addResourcePart(navigationResource);
if (navigationResource.isCollection()) {
parseCollectionNavigationExpr(uriInfo, navigationResource);
} else {
parseSingleNavigationExpr(uriInfo, navigationResource);
}
} else {
// Primitive type or Enum type
final UriResourcePrimitivePropertyImpl primitiveResource =
new UriResourcePrimitivePropertyImpl((EdmProperty) property);
uriInfo.addResourcePart(primitiveResource);
if (property.isCollection()) {
parseCollectionPathExpr(uriInfo, primitiveResource);
} else {
parseSinglePathExpr(uriInfo, primitiveResource);
}
}
}
private void parseSingleNavigationExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
throws UriParserException, UriValidationException {
// TODO: Is that correct?
if (tokenizer.next(TokenKind.SLASH)) {
final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
parseMemberExpression(tokenKind, uriInfo, lastResource, true);
}
}
private void parseCollectionNavigationExpr(UriInfoImpl uriInfo, UriResourcePartTyped lastResource)
throws UriParserException, UriValidationException {
// TODO: Is type cast missing?
if (tokenizer.next(TokenKind.OPEN)) {
if (lastResource instanceof UriResourceNavigation) {
((UriResourceNavigationPropertyImpl) lastResource).setKeyPredicates(
ParserHelper.parseNavigationKeyPredicate(tokenizer,
((UriResourceNavigationPropertyImpl) lastResource).getProperty()));
} else if (lastResource instanceof UriResourceFunction
&& ((UriResourceFunction) lastResource).getType() instanceof EdmEntityType) {
((UriResourceFunctionImpl) lastResource).setKeyPredicates(
ParserHelper.parseKeyPredicate(tokenizer,
(EdmEntityType) ((UriResourceFunction) lastResource).getType(),
null));
} else {
throw new UriParserSemanticException("Unknown or wrong resource type.",
UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, lastResource.toString());
}
parseSingleNavigationExpr(uriInfo, lastResource);
}
parseCollectionPathExpr(uriInfo, lastResource);
}
private void parseSinglePathExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
throws UriParserException, UriValidationException {
if (tokenizer.next(TokenKind.SLASH)) {
ParserHelper.requireNext(tokenizer, TokenKind.QualifiedName);
parseBoundFunction(new FullQualifiedName(tokenizer.getText()), uriInfo, lastResource);
}
}
private void parseComplexPathExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
throws UriParserException, UriValidationException {
if (tokenizer.next(TokenKind.SLASH)) {
if (tokenizer.next(TokenKind.QualifiedName)) {
final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
final EdmEntityType edmEntityType = edm.getEntityType(fullQualifiedName);
if (edmEntityType != null) {
setTypeFilter(lastResource, edmEntityType);
if (tokenizer.next(TokenKind.SLASH)) {
parseComplexPathRestExpr(uriInfo, lastResource);
}
} else {
// Must be a bound function.
parseBoundFunction(fullQualifiedName, uriInfo, lastResource);
}
} else {
parseComplexPathRestExpr(uriInfo, lastResource);
}
}
}
private void parseComplexPathRestExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
throws UriParserException, UriValidationException {
if (tokenizer.next(TokenKind.QualifiedName)) {
final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
// Must be a bound function.
parseBoundFunction(fullQualifiedName, uriInfo, lastResource);
} else if (tokenizer.next(TokenKind.ODataIdentifier)) {
parsePropertyPathExpr(uriInfo, lastResource);
} else {
throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
}
}
private void parseCollectionPathExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
throws UriParserException, UriValidationException {
if (tokenizer.next(TokenKind.SLASH)) {
if (tokenizer.next(TokenKind.COUNT)) {
uriInfo.addResourcePart(new UriResourceCountImpl());
} else if (tokenizer.next(TokenKind.ANY)) {
uriInfo.addResourcePart(parseLambdaRest(TokenKind.ANY, lastResource));
} else if (tokenizer.next(TokenKind.ALL)) {
uriInfo.addResourcePart(parseLambdaRest(TokenKind.ALL, lastResource));
} else if (tokenizer.next(TokenKind.QualifiedName)) {
final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
parseBoundFunction(fullQualifiedName, uriInfo, lastResource);
}
}
}
private void parseFunction(final FullQualifiedName fullQualifiedName, UriInfoImpl uriInfo,
final EdmType lastType, final boolean lastIsCollection) throws UriParserException, UriValidationException {
final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, true);
final List<String> parameterNames = ParserHelper.getParameterNames(parameters);
final EdmFunction boundFunction = edm.getBoundFunction(fullQualifiedName,
lastType.getFullQualifiedName(), lastIsCollection, parameterNames);
if (boundFunction != null) {
parseFunctionRest(uriInfo, boundFunction, parameters);
return;
}
final EdmFunction unboundFunction = edm.getUnboundFunction(fullQualifiedName, parameterNames);
if (unboundFunction != null) {
parseFunctionRest(uriInfo, unboundFunction, parameters);
return;
}
throw new UriParserSemanticException("No function found.",
UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND, fullQualifiedName.getFullQualifiedNameAsString());
}
private void parseBoundFunction(final FullQualifiedName fullQualifiedName, UriInfoImpl uriInfo,
final UriResourcePartTyped lastResource) throws UriParserException, UriValidationException {
final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, true);
final List<String> parameterNames = ParserHelper.getParameterNames(parameters);
final EdmFunction boundFunction = edm.getBoundFunction(fullQualifiedName,
lastResource.getType().getFullQualifiedName(), lastResource.isCollection(), parameterNames);
if (boundFunction == null) {
throw new UriParserSemanticException("Bound function not found.",
UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND, fullQualifiedName.getFullQualifiedNameAsString());
}
parseFunctionRest(uriInfo, boundFunction, parameters);
}
private void parseFunctionRest(UriInfoImpl uriInfo, final EdmFunction function,
final List<UriParameter> parameters) throws UriParserException, UriValidationException {
final UriResourceFunction functionResource = new UriResourceFunctionImpl(null, function, parameters);
uriInfo.addResourcePart(functionResource);
final EdmReturnType edmReturnType = function.getReturnType();
final EdmType edmType = edmReturnType.getType();
final boolean isCollection = edmReturnType.isCollection();
if (function.isComposable()) {
if (edmType instanceof EdmEntityType ) {
if (isCollection) {
parseCollectionNavigationExpr(uriInfo, null); // TODO: Get navigation property.
} else {
parseSingleNavigationExpr(uriInfo, null); // TODO: Get navigation property.
}
} else if (edmType instanceof EdmComplexType) {
if (isCollection) {
parseCollectionPathExpr(uriInfo, functionResource);
} else {
parseComplexPathExpr(uriInfo, functionResource);
}
} else if (edmType instanceof EdmPrimitiveType) {
if (isCollection) {
parseCollectionPathExpr(uriInfo, functionResource);
} else {
parseSinglePathExpr(uriInfo, functionResource);
}
}
} else if (tokenizer.next(TokenKind.SLASH)) {
throw new UriValidationException("Function is not composable.",
UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH, "");
}
}
private UriResourcePartTyped parseLambdaRest(final TokenKind lastTokenKind, final UriResourcePartTyped lastResource)
throws UriParserException, UriValidationException {
ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
if (lastTokenKind == TokenKind.ANY && tokenizer.next(TokenKind.CLOSE)) {
return new UriResourceLambdaAnyImpl(null, null);
}
ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
final String lambbdaVariable = tokenizer.getText();
ParserHelper.requireNext(tokenizer, TokenKind.COLON);
lambdaVariables.addFirst(new UriResourceLambdaVarImpl(lambbdaVariable,
lastResource == null ? referringType : lastResource.getType()));
final Expression lambdaPredicateExpr = parseExpression();
lambdaVariables.removeFirst();
// TODO: The ABNF suggests that the "lambaPredicateExpr" must contain at least one lambdaVariable.
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
if (lastTokenKind == TokenKind.ALL) {
return new UriResourceLambdaAllImpl(lambbdaVariable, lambdaPredicateExpr);
} else if (lastTokenKind == TokenKind.ANY) {
return new UriResourceLambdaAnyImpl(lambbdaVariable, lambdaPredicateExpr);
} else {
throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
}
}
private TokenKind nextMethod() {
return ParserHelper.next(tokenizer,
TokenKind.CeilingMethod,
@ -580,9 +1044,9 @@ public class ExpressionParser {
}
}
private EdmPrimitiveType getEnumType(final String primitiveValueLiteral) throws UriParserException {
private EdmEnumType getEnumType(final String primitiveValueLiteral) throws UriParserException {
final String enumTypeName = primitiveValueLiteral.substring(0, primitiveValueLiteral.indexOf('\''));
final EdmPrimitiveType type = edm.getEnumType(new FullQualifiedName(enumTypeName));
final EdmEnumType type = edm.getEnumType(new FullQualifiedName(enumTypeName));
if (type == null) {
throw new UriParserSemanticException("Unknown Enum type '" + enumTypeName + "'.",
UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, enumTypeName);
@ -599,13 +1063,16 @@ public class ExpressionParser {
EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte);
}
private void checkEnumLiteral(final Expression expression) throws UriParserException {
if (expression == null
|| !(expression instanceof Literal)
|| ((Literal) expression).getType() == null
|| ((Literal) expression).getType().getKind() != EdmTypeKind.ENUM) {
throw new UriParserSemanticException("Enum literal expected.",
UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, ""); // TODO: better message
private Enumeration createEnumExpression(final String primitiveValueLiteral) throws UriParserException {
final EdmEnumType enumType = getEnumType(primitiveValueLiteral);
// TODO: Can the Enumeration interface be changed to handle the value as a whole?
try {
return new EnumerationImpl(enumType,
Arrays.asList(enumType.fromUriLiteral(primitiveValueLiteral).split(",")));
} catch (final EdmPrimitiveTypeException e) {
// TODO: Better error message.
throw new UriParserSemanticException("Wrong enumeration value.", e,
UriParserSemanticException.MessageKeys.UNKNOWN_PART, primitiveValueLiteral);
}
}
@ -664,4 +1131,13 @@ public class ExpressionParser {
throw new UriParserSemanticException("Incompatible types.",
UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, ""); // TODO: better message
}
private void checkStructuredTypeFilter(final EdmType type, final EdmStructuredType filterType)
throws UriParserException {
if (!filterType.compatibleTo(type)) {
throw new UriParserSemanticException("Incompatible type filter.",
UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER,
filterType.getFullQualifiedName().getFullQualifiedNameAsString());
}
}
}

View File

@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.uri.parser;
import java.util.Collection;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmStructuredType;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.core.uri.queryoption.FilterOptionImpl;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
public class FilterParser {
private final Edm edm;
private final OData odata;
public FilterParser(final Edm edm, final OData odata) {
this.edm = edm;
this.odata = odata;
}
public FilterOption parse(UriTokenizer tokenizer, final EdmStructuredType referencedType,
final Collection<String> crossjoinEntitySetNames)
throws UriParserException, UriValidationException {
final Expression filterExpression = new ExpressionParser(edm, odata)
.parse(tokenizer, referencedType, crossjoinEntitySetNames);
// TODO: Check that the expression is boolean.
return new FilterOptionImpl().setExpression(filterExpression);
}
}

View File

@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.uri.parser;
import java.util.Collection;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmStructuredType;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.uri.queryoption.OrderByOption;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
import org.apache.olingo.server.core.uri.queryoption.OrderByItemImpl;
import org.apache.olingo.server.core.uri.queryoption.OrderByOptionImpl;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
public class OrderByParser {
private final Edm edm;
private final OData odata;
public OrderByParser(final Edm edm, final OData odata) {
this.edm = edm;
this.odata = odata;
}
public OrderByOption parse(UriTokenizer tokenizer, final EdmStructuredType referencedType,
final Collection<String> crossjoinEntitySetNames)
throws UriParserException, UriValidationException {
OrderByOptionImpl orderByOption = new OrderByOptionImpl();
do {
final Expression orderByExpression = new ExpressionParser(edm, odata)
.parse(tokenizer, referencedType, crossjoinEntitySetNames);
OrderByItemImpl item = new OrderByItemImpl();
item.setExpression(orderByExpression);
if (tokenizer.next(TokenKind.AscSuffix)) {
item.setDescending(false);
} else if (tokenizer.next(TokenKind.DescSuffix)) {
item.setDescending(true);
}
orderByOption.addOrder(item);
} while (tokenizer.next(TokenKind.COMMA));
return orderByOption;
}
}

View File

@ -46,29 +46,22 @@ import org.apache.olingo.server.api.uri.UriResourceRef;
import org.apache.olingo.server.api.uri.UriResourceValue;
import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
import org.apache.olingo.server.api.uri.queryoption.CustomQueryOption;
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
import org.apache.olingo.server.api.uri.queryoption.QueryOption;
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOption;
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.core.uri.UriInfoImpl;
import org.apache.olingo.server.core.uri.UriResourceStartingTypeFilterImpl;
import org.apache.olingo.server.core.uri.UriResourceTypedImpl;
import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
import org.apache.olingo.server.core.uri.antlr.UriLexer;
import org.apache.olingo.server.core.uri.antlr.UriParserParser;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemsEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.FilterExpressionEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByEOFContext;
import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
import org.apache.olingo.server.core.uri.parser.search.SearchParser;
import org.apache.olingo.server.core.uri.queryoption.AliasQueryOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.FilterOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.FormatOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.IdOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.OrderByOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.SkipOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.SkipTokenOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.TopOptionImpl;
@ -84,9 +77,7 @@ public class Parser {
private final Edm edm;
private final OData odata;
private enum ParserEntryRules {
ExpandItems, FilterExpression, Orderby
}
private enum ParserEntryRules { ExpandItems }
public Parser(final Edm edm, final OData odata) {
this.edm = edm;
@ -131,7 +122,7 @@ public class Parser {
if (numberOfSegments > 1) {
final String typeCastSegment = pathSegmentsDecoded.get(1);
ensureLastSegment(typeCastSegment, 2, numberOfSegments);
context.contextUriInfo = new ResourcePathParser(edm, odata).parseDollarEntityTypeCast(typeCastSegment);
context.contextUriInfo = new ResourcePathParser(edm).parseDollarEntityTypeCast(typeCastSegment);
context.contextTypes.push(context.contextUriInfo.getEntityTypeCast());
} else {
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
@ -141,7 +132,7 @@ public class Parser {
} else if (firstSegment.startsWith("$crossjoin")) {
ensureLastSegment(firstSegment, 1, numberOfSegments);
context.contextUriInfo = new ResourcePathParser(edm, odata).parseCrossjoinSegment(firstSegment);
context.contextUriInfo = new ResourcePathParser(edm).parseCrossjoinSegment(firstSegment);
final EdmEntityContainer container = edm.getEntityContainer();
for (final String name : context.contextUriInfo.getEntitySetNames()) {
context.contextTypes.push(container.getEntitySet(name).getEntityType());
@ -150,7 +141,7 @@ public class Parser {
} else {
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
final ResourcePathParser resourcePathParser = new ResourcePathParser(edm, odata);
final ResourcePathParser resourcePathParser = new ResourcePathParser(edm);
int count = 0;
UriResource lastSegment = null;
for (final String pathSegment : pathSegmentsDecoded) {
@ -183,7 +174,7 @@ public class Parser {
if (lastSegment instanceof UriResourcePartTyped) {
final UriResourcePartTyped typed = (UriResourcePartTyped) lastSegment;
final EdmType type = getTypeInformation(typed);
final EdmType type = ParserHelper.getTypeInformation(typed);
if (type != null) { // could be null for, e.g., actions without return type
context.contextTypes.push(type);
}
@ -199,23 +190,13 @@ public class Parser {
if (optionName.startsWith("$")) {
SystemQueryOption systemOption = null;
if (optionName.equals(SystemQueryOptionKind.FILTER.toString())) {
try {
FilterExpressionEOFContext ctxFilterExpression =
(FilterExpressionEOFContext) parseRule(optionValue, ParserEntryRules.FilterExpression);
systemOption = (FilterOptionImpl) uriParseTreeVisitor.visitFilterExpressionEOF(ctxFilterExpression);
} catch (final ParseCancellationException e) {
throw e.getCause() instanceof UriParserException ?
(UriParserException) e.getCause() :
new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
}
// UriTokenizer filterTokenizer = new UriTokenizer(optionValue);
// systemOption = new FilterOptionImpl().setExpression(
// new ExpressionParser().parse(filterTokenizer));
// if (!filterTokenizer.next(TokenKind.EOF)) {
// throw new UriParserSyntaxException("Illegal value of $filter option!",
// UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
// optionName, optionValue);
// }
UriTokenizer filterTokenizer = new UriTokenizer(optionValue);
systemOption = new FilterParser(edm, odata).parse(filterTokenizer,
context.contextTypes.peek() instanceof EdmStructuredType ?
(EdmStructuredType) context.contextTypes.peek() :
null,
context.contextUriInfo.getEntitySetNames());
checkOptionEOF(filterTokenizer, optionName, optionValue);
} else if (optionName.equals(SystemQueryOptionKind.FORMAT.toString())) {
FormatOptionImpl formatOption = new FormatOptionImpl();
@ -253,15 +234,13 @@ public class Parser {
UriParserSyntaxException.MessageKeys.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE);
} else if (optionName.equals(SystemQueryOptionKind.ORDERBY.toString())) {
try {
OrderByEOFContext ctxOrderByExpression =
(OrderByEOFContext) parseRule(optionValue, ParserEntryRules.Orderby);
systemOption = (OrderByOptionImpl) uriParseTreeVisitor.visitOrderByEOF(ctxOrderByExpression);
} catch (final ParseCancellationException e) {
throw e.getCause() instanceof UriParserException ?
(UriParserException) e.getCause() :
new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
}
UriTokenizer orderByTokenizer = new UriTokenizer(optionValue);
systemOption = new OrderByParser(edm, odata).parse(orderByTokenizer,
context.contextTypes.peek() instanceof EdmStructuredType ?
(EdmStructuredType) context.contextTypes.peek() :
null,
context.contextUriInfo.getEntitySetNames());
checkOptionEOF(orderByTokenizer, optionName, optionValue);
} else if (optionName.equals(SystemQueryOptionKind.SEARCH.toString())) {
systemOption = new SearchParser().parse(optionValue);
@ -273,11 +252,7 @@ public class Parser {
(EdmStructuredType) context.contextTypes.peek() :
null,
context.isCollection);
if (!selectTokenizer.next(TokenKind.EOF)) {
throw new UriParserSyntaxException("Illegal value of $select option!",
UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
optionName, optionValue);
}
checkOptionEOF(selectTokenizer, optionName, optionValue);
} else if (optionName.equals(SystemQueryOptionKind.SKIP.toString())) {
SkipOptionImpl skipOption = new SkipOptionImpl();
@ -343,15 +318,12 @@ public class Parser {
UriParserSyntaxException.MessageKeys.SYNTAX);
}
} else {
try {
final FilterExpressionEOFContext filterExpCtx =
(FilterExpressionEOFContext) parseRule(optionValue, ParserEntryRules.FilterExpression);
expression = ((FilterOption) uriParseTreeVisitor.visitFilterExpressionEOF(filterExpCtx))
.getExpression();
} catch (final ParseCancellationException e) {
throw e.getCause() instanceof UriParserException ?
(UriParserException) e.getCause() :
new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
UriTokenizer aliasValueTokenizer = new UriTokenizer(optionValue);
expression = new ExpressionParser(edm, odata).parse(aliasValueTokenizer, null,
context.contextUriInfo.getEntitySetNames());
if (!aliasValueTokenizer.next(TokenKind.EOF)) {
throw new UriParserSyntaxException("Illegal value for alias '" + optionName + "'.",
UriParserSyntaxException.MessageKeys.SYNTAX);
}
}
context.contextUriInfo.addAlias((AliasQueryOption) new AliasQueryOptionImpl()
@ -384,28 +356,13 @@ public class Parser {
return index > 0 && index < value.length() - 1 && index == value.lastIndexOf('/');
}
protected static EdmType getTypeInformation(final UriResourcePartTyped resourcePart) {
EdmType type = null;
if (resourcePart instanceof UriResourceWithKeysImpl) {
final UriResourceWithKeysImpl lastPartWithKeys = (UriResourceWithKeysImpl) resourcePart;
if (lastPartWithKeys.getTypeFilterOnEntry() != null) {
type = lastPartWithKeys.getTypeFilterOnEntry();
} else if (lastPartWithKeys.getTypeFilterOnCollection() != null) {
type = lastPartWithKeys.getTypeFilterOnCollection();
} else {
type = lastPartWithKeys.getType();
}
} else if (resourcePart instanceof UriResourceTypedImpl) {
final UriResourceTypedImpl lastPartTyped = (UriResourceTypedImpl) resourcePart;
type = lastPartTyped.getTypeFilter() == null ?
lastPartTyped.getType() :
lastPartTyped.getTypeFilter();
} else {
type = resourcePart.getType();
private void checkOptionEOF(UriTokenizer tokenizer, final String optionName, final String optionValue)
throws UriParserException {
if (!tokenizer.next(TokenKind.EOF)) {
throw new UriParserSyntaxException("Illegal value of '" + optionName + "' option!",
UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
optionName, optionValue);
}
return type;
}
private ParserRuleContext parseRule(final String input, final ParserEntryRules entryPoint)
@ -435,14 +392,6 @@ public class Parser {
// parse
switch (entryPoint) {
case FilterExpression:
lexer.mode(Lexer.DEFAULT_MODE);
ret = parser.filterExpressionEOF();
break;
case Orderby:
lexer.mode(Lexer.DEFAULT_MODE);
ret = parser.orderByEOF();
break;
case ExpandItems:
lexer.mode(Lexer.DEFAULT_MODE);
ret = parser.expandItemsEOF();
@ -471,14 +420,6 @@ public class Parser {
// parse
switch (entryPoint) {
case FilterExpression:
lexer.mode(Lexer.DEFAULT_MODE);
ret = parser.filterExpressionEOF();
break;
case Orderby:
lexer.mode(Lexer.DEFAULT_MODE);
ret = parser.orderByEOF();
break;
case ExpandItems:
lexer.mode(Lexer.DEFAULT_MODE);
ret = parser.expandItemsEOF();

View File

@ -18,10 +18,35 @@
*/
package org.apache.olingo.server.core.uri.parser;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmKeyPropertyRef;
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.edm.EdmTypeDefinition;
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
import org.apache.olingo.server.core.ODataImpl;
import org.apache.olingo.server.core.uri.UriParameterImpl;
import org.apache.olingo.server.core.uri.UriResourceTypedImpl;
import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
public class ParserHelper {
private static final OData odata = new ODataImpl();
public static void requireNext(UriTokenizer tokenizer, final TokenKind required) throws UriParserException {
if (!tokenizer.next(required)) {
throw new UriParserSyntaxException("Expected token '" + required.toString() + "' not found.",
@ -33,16 +58,16 @@ public class ParserHelper {
requireNext(tokenizer, TokenKind.EOF);
}
public static TokenKind next(UriTokenizer tokenizer, final TokenKind... kind) {
for (int i = 0; i < kind.length; i++) {
if (tokenizer.next(kind[i])) {
return kind[i];
public static TokenKind next(UriTokenizer tokenizer, final TokenKind... kinds) {
for (final TokenKind kind : kinds) {
if (tokenizer.next(kind)) {
return kind;
}
}
return null;
}
public static TokenKind nextPrimitive(UriTokenizer tokenizer) {
public static TokenKind nextPrimitiveValue(UriTokenizer tokenizer) {
return next(tokenizer,
TokenKind.NULL,
TokenKind.BooleanValue,
@ -62,4 +87,304 @@ public class ParserHelper {
TokenKind.BinaryValue,
TokenKind.EnumValue);
}
protected static List<UriParameter> parseFunctionParameters(UriTokenizer tokenizer, final boolean withComplex)
throws UriParserException {
List<UriParameter> parameters = new ArrayList<UriParameter>();
ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
if (tokenizer.next(TokenKind.CLOSE)) {
return parameters;
}
do {
ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
final String name = tokenizer.getText();
if (parameters.contains(name)) {
throw new UriParserSemanticException("Duplicated function parameter " + name,
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, name);
}
ParserHelper.requireNext(tokenizer, TokenKind.EQ);
if (tokenizer.next(TokenKind.COMMA) || tokenizer.next(TokenKind.CLOSE) || tokenizer.next(TokenKind.EOF)) {
throw new UriParserSyntaxException("Parameter value expected.", UriParserSyntaxException.MessageKeys.SYNTAX);
}
if (tokenizer.next(TokenKind.ParameterAliasName)) {
parameters.add(new UriParameterImpl().setName(name).setAlias(tokenizer.getText()));
} else if (tokenizer.next(TokenKind.jsonArrayOrObject)) {
if (withComplex) {
parameters.add(new UriParameterImpl().setName(name).setText(tokenizer.getText()));
} else {
throw new UriParserSemanticException("A JSON array or object is not allowed as parameter value.",
UriParserSemanticException.MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH, tokenizer.getText());
}
} else if (nextPrimitiveValue(tokenizer) == null) {
throw new UriParserSemanticException("Wrong parameter value.",
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, "");
} else {
final String literalValue = tokenizer.getText();
parameters.add(new UriParameterImpl().setName(name)
.setText("null".equals(literalValue) ? null : literalValue));
}
} while (tokenizer.next(TokenKind.COMMA));
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
return parameters;
}
protected static List<UriParameter> parseNavigationKeyPredicate(UriTokenizer tokenizer,
final EdmNavigationProperty navigationProperty) throws UriParserException, UriValidationException {
if (tokenizer.next(TokenKind.OPEN)) {
if (navigationProperty.isCollection()) {
return parseKeyPredicate(tokenizer, navigationProperty.getType(), navigationProperty.getPartner());
} else {
throw new UriParserSemanticException("A key is not allowed on non-collection navigation properties.",
UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
}
}
return null;
}
protected static List<UriParameter> parseKeyPredicate(UriTokenizer tokenizer, final EdmEntityType edmEntityType,
final EdmNavigationProperty partner) throws UriParserException, UriValidationException {
final List<EdmKeyPropertyRef> keyPropertyRefs = edmEntityType.getKeyPropertyRefs();
if (tokenizer.next(TokenKind.CLOSE)) {
throw new UriParserSemanticException(
"Expected " + keyPropertyRefs.size() + " key predicates but none.",
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
Integer.toString(keyPropertyRefs.size()), "0");
}
List<UriParameter> keys = new ArrayList<UriParameter>();
Map<String, String> referencedNames = new HashMap<String, String>();
if (partner != null) {
// Prepare list of potentially missing keys to be filled from referential constraints.
for (final String name : edmEntityType.getKeyPredicateNames()) {
final String referencedName = partner.getReferencingPropertyName(name);
if (referencedName != null) {
referencedNames.put(name, referencedName);
}
}
}
if (tokenizer.next(TokenKind.ODataIdentifier)) {
keys.addAll(compoundKey(tokenizer, edmEntityType));
} else if (keyPropertyRefs.size() - referencedNames.size() == 1) {
for (final EdmKeyPropertyRef candidate : keyPropertyRefs) {
if (referencedNames.get(candidate.getName()) == null) {
keys.add(simpleKey(tokenizer, candidate));
break;
}
}
} else {
throw new UriParserSemanticException(
"Expected " + (keyPropertyRefs.size() -referencedNames.size()) + " key predicates but found one.",
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
Integer.toString(keyPropertyRefs.size() - referencedNames.size()), "1");
}
if (keys.size() < keyPropertyRefs.size() && partner != null) {
// Fill missing keys from referential constraints.
for (final String name : edmEntityType.getKeyPredicateNames()) {
boolean found = false;
for (final UriParameter key : keys) {
if (name.equals(key.getName())) {
found = true;
break;
}
}
if (!found && referencedNames.get(name) != null) {
keys.add(0, new UriParameterImpl().setName(name).setReferencedProperty(referencedNames.get(name)));
}
}
}
// Check that all key predicates are filled from the URI.
if (keys.size() < keyPropertyRefs.size()) {
throw new UriParserSemanticException(
"Expected " + keyPropertyRefs.size() + " key predicates but found " + keys.size() + ".",
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
Integer.toString(keyPropertyRefs.size()), Integer.toString(keys.size()));
} else {
return keys;
}
}
private static UriParameter simpleKey(UriTokenizer tokenizer, final EdmKeyPropertyRef edmKeyPropertyRef)
throws UriParserException, UriValidationException {
final EdmProperty edmProperty = edmKeyPropertyRef == null ? null : edmKeyPropertyRef.getProperty();
if (nextPrimitiveTypeValue(tokenizer,
edmProperty == null ? null : (EdmPrimitiveType) edmProperty.getType(),
edmProperty == null ? false : edmProperty.isNullable())) {
final String literalValue = tokenizer.getText();
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
return createUriParameter(edmProperty, edmKeyPropertyRef.getName(), literalValue);
} else {
throw new UriParserSemanticException("The key value is not valid.",
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, edmKeyPropertyRef.getName());
}
}
private static List<UriParameter> compoundKey(UriTokenizer tokenizer, final EdmEntityType edmEntityType)
throws UriParserException, UriValidationException {
List<UriParameter> parameters = new ArrayList<UriParameter>();
List<String> parameterNames = new ArrayList<String>();
// To validate that each key predicate is exactly specified once, we use a list to pick from.
List<String> remainingKeyNames = new ArrayList<String>(edmEntityType.getKeyPredicateNames());
// At least one key predicate is mandatory. Try to fetch all.
boolean hasComma = false;
do {
final String keyPredicateName = tokenizer.getText();
if (parameterNames.contains(keyPredicateName)) {
throw new UriValidationException("Duplicated key property " + keyPredicateName,
UriValidationException.MessageKeys.DOUBLE_KEY_PROPERTY, keyPredicateName);
}
if (remainingKeyNames.isEmpty()) {
throw new UriParserSemanticException("Too many key properties.",
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
Integer.toString(parameters.size()), Integer.toString(parameters.size() + 1));
}
if (!remainingKeyNames.remove(keyPredicateName)) {
throw new UriValidationException("Unknown key property " + keyPredicateName,
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, keyPredicateName);
}
parameters.add(keyValuePair(tokenizer, keyPredicateName, edmEntityType));
parameterNames.add(keyPredicateName);
hasComma = tokenizer.next(TokenKind.COMMA);
if (hasComma) {
ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
}
} while (hasComma);
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
return parameters;
}
protected static UriParameter keyValuePair(UriTokenizer tokenizer,
final String keyPredicateName, final EdmEntityType edmEntityType)
throws UriParserException, UriValidationException {
final EdmKeyPropertyRef keyPropertyRef = edmEntityType.getKeyPropertyRef(keyPredicateName);
final EdmProperty edmProperty = keyPropertyRef == null ? null : keyPropertyRef.getProperty();
if (edmProperty == null) {
throw new UriValidationException(keyPredicateName + " is not a valid key property name.",
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, keyPredicateName);
}
ParserHelper.requireNext(tokenizer, TokenKind.EQ);
if (tokenizer.next(TokenKind.COMMA) || tokenizer.next(TokenKind.CLOSE) || tokenizer.next(TokenKind.EOF)) {
throw new UriParserSyntaxException("Key value expected.", UriParserSyntaxException.MessageKeys.SYNTAX);
}
if (nextPrimitiveTypeValue(tokenizer, (EdmPrimitiveType) edmProperty.getType(), edmProperty.isNullable())) {
return createUriParameter(edmProperty, keyPredicateName, tokenizer.getText());
} else {
throw new UriParserSemanticException(keyPredicateName + " has not a valid key value.",
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, keyPredicateName);
}
}
private static UriParameter createUriParameter(final EdmProperty edmProperty, final String parameterName,
final String literalValue) throws UriParserException, UriValidationException {
if (literalValue.startsWith("@")) {
return new UriParameterImpl()
.setName(parameterName)
.setAlias(literalValue);
}
final EdmPrimitiveType primitiveType = (EdmPrimitiveType) edmProperty.getType();
try {
if (!(primitiveType.validate(primitiveType.fromUriLiteral(literalValue), edmProperty.isNullable(),
edmProperty.getMaxLength(), edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode()))) {
throw new UriValidationException("Invalid key property",
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, parameterName);
}
} catch (final EdmPrimitiveTypeException e) {
throw new UriValidationException("Invalid key property",
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, parameterName);
}
return new UriParameterImpl()
.setName(parameterName)
.setText("null".equals(literalValue) ? null : literalValue);
}
private static boolean nextPrimitiveTypeValue(UriTokenizer tokenizer,
final EdmPrimitiveType primitiveType, final boolean nullable) {
final EdmPrimitiveType type = primitiveType instanceof EdmTypeDefinition ?
((EdmTypeDefinition) primitiveType).getUnderlyingType() :
primitiveType;
if (tokenizer.next(TokenKind.ParameterAliasName)) {
return true;
} else if (nullable && tokenizer.next(TokenKind.NULL)) {
return true;
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean).equals(type)) {
return tokenizer.next(TokenKind.BooleanValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String).equals(type)) {
return tokenizer.next(TokenKind.StringValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.SByte).equals(type)
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Byte).equals(type)
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int16).equals(type)
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int32).equals(type)
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int64).equals(type)) {
return tokenizer.next(TokenKind.IntegerValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Guid).equals(type)) {
return tokenizer.next(TokenKind.GuidValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Date).equals(type)) {
return tokenizer.next(TokenKind.DateValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.DateTimeOffset).equals(type)) {
return tokenizer.next(TokenKind.DateTimeOffsetValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.TimeOfDay).equals(type)) {
return tokenizer.next(TokenKind.TimeOfDayValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal).equals(type)) {
// The order is important.
// A decimal value should not be parsed as integer and let the tokenizer stop at the decimal point.
return tokenizer.next(TokenKind.DecimalValue)
|| tokenizer.next(TokenKind.IntegerValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Double).equals(type)) {
// The order is important.
// A floating-point value should not be parsed as decimal and let the tokenizer stop at 'E'.
// A decimal value should not be parsed as integer and let the tokenizer stop at the decimal point.
return tokenizer.next(TokenKind.DoubleValue)
|| tokenizer.next(TokenKind.DecimalValue)
|| tokenizer.next(TokenKind.IntegerValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Duration).equals(type)) {
return tokenizer.next(TokenKind.DurationValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Binary).equals(type)) {
return tokenizer.next(TokenKind.BinaryValue);
} else if (type.getKind() == EdmTypeKind.ENUM) {
return tokenizer.next(TokenKind.EnumValue);
} else {
return false;
}
}
protected static List<String> getParameterNames(final List<UriParameter> parameters) {
List<String> names = new ArrayList<String>();
for (final UriParameter parameter : parameters) {
names.add(parameter.getName());
}
return names;
}
protected static EdmType getTypeInformation(final UriResourcePartTyped resourcePart) {
EdmType type = null;
if (resourcePart instanceof UriResourceWithKeysImpl) {
final UriResourceWithKeysImpl lastPartWithKeys = (UriResourceWithKeysImpl) resourcePart;
if (lastPartWithKeys.getTypeFilterOnEntry() != null) {
type = lastPartWithKeys.getTypeFilterOnEntry();
} else if (lastPartWithKeys.getTypeFilterOnCollection() != null) {
type = lastPartWithKeys.getTypeFilterOnCollection();
} else {
type = lastPartWithKeys.getType();
}
} else if (resourcePart instanceof UriResourceTypedImpl) {
final UriResourceTypedImpl lastPartTyped = (UriResourceTypedImpl) resourcePart;
type = lastPartTyped.getTypeFilter() == null ?
lastPartTyped.getType() :
lastPartTyped.getTypeFilter();
} else {
type = resourcePart.getType();
}
return type;
}
}

View File

@ -18,10 +18,7 @@
*/
package org.apache.olingo.server.core.uri.parser;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmAction;
@ -31,25 +28,18 @@ import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmFunction;
import org.apache.olingo.commons.api.edm.EdmFunctionImport;
import org.apache.olingo.commons.api.edm.EdmKeyPropertyRef;
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmSingleton;
import org.apache.olingo.commons.api.edm.EdmStructuredType;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.edm.EdmTypeDefinition;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.uri.UriInfoKind;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
import org.apache.olingo.server.core.uri.UriInfoImpl;
import org.apache.olingo.server.core.uri.UriParameterImpl;
import org.apache.olingo.server.core.uri.UriResourceActionImpl;
import org.apache.olingo.server.core.uri.UriResourceComplexPropertyImpl;
import org.apache.olingo.server.core.uri.UriResourceCountImpl;
@ -69,13 +59,11 @@ public class ResourcePathParser {
private final Edm edm;
private final EdmEntityContainer edmEntityContainer;
private final OData odata;
private UriTokenizer tokenizer;
public ResourcePathParser(final Edm edm, final OData odata) {
public ResourcePathParser(final Edm edm) {
this.edm = edm;
edmEntityContainer = edm.getEntityContainer();
this.odata = odata;
}
public UriResource parsePathSegment(final String pathSegment, UriResource previous)
@ -188,10 +176,11 @@ public class ResourcePathParser {
final EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(oDataIdentifier);
if (edmEntitySet != null) {
final UriResourceEntitySetImpl entitySetResource = new UriResourceEntitySetImpl().setEntitSet(edmEntitySet);
final UriResourceEntitySetImpl entitySetResource = new UriResourceEntitySetImpl(edmEntitySet);
if (tokenizer.next(TokenKind.OPEN)) {
final List<UriParameter> keyPredicates = keyPredicate(entitySetResource.getEntityType(), null);
final List<UriParameter> keyPredicates =
ParserHelper.parseKeyPredicate(tokenizer, entitySetResource.getEntityType(), null);
entitySetResource.setKeyPredicates(keyPredicates);
}
@ -202,13 +191,13 @@ public class ResourcePathParser {
final EdmSingleton edmSingleton = edmEntityContainer.getSingleton(oDataIdentifier);
if (edmSingleton != null) {
ParserHelper.requireTokenEnd(tokenizer);
return new UriResourceSingletonImpl().setSingleton(edmSingleton);
return new UriResourceSingletonImpl(edmSingleton);
}
final EdmActionImport edmActionImport = edmEntityContainer.getActionImport(oDataIdentifier);
if (edmActionImport != null) {
ParserHelper.requireTokenEnd(tokenizer);
return new UriResourceActionImpl().setActionImport(edmActionImport);
return new UriResourceActionImpl(edmActionImport);
}
final EdmFunctionImport edmFunctionImport = edmEntityContainer.getFunctionImport(oDataIdentifier);
@ -252,8 +241,8 @@ public class ResourcePathParser {
return property.isPrimitive()
|| property.getType().getKind() == EdmTypeKind.ENUM
|| property.getType().getKind() == EdmTypeKind.DEFINITION ?
new UriResourcePrimitivePropertyImpl().setProperty(property) :
new UriResourceComplexPropertyImpl().setProperty(property);
new UriResourcePrimitivePropertyImpl(property) :
new UriResourceComplexPropertyImpl(property);
}
final EdmNavigationProperty navigationProperty = structType.getNavigationProperty(name);
if (navigationProperty == null) {
@ -262,18 +251,9 @@ public class ResourcePathParser {
UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE,
structType.getFullQualifiedName().getFullQualifiedNameAsString(), name);
}
List<UriParameter> keyPredicate = null;
if (tokenizer.next(TokenKind.OPEN)) {
if (navigationProperty.isCollection()) {
keyPredicate = keyPredicate(navigationProperty.getType(), navigationProperty.getPartner());
} else {
throw new UriParserSemanticException("A key is not allowed on non-collection navigation properties.",
UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
}
}
List<UriParameter> keyPredicate = ParserHelper.parseNavigationKeyPredicate(tokenizer, navigationProperty);
ParserHelper.requireTokenEnd(tokenizer);
return new UriResourceNavigationPropertyImpl()
.setNavigationProperty(navigationProperty)
return new UriResourceNavigationPropertyImpl(navigationProperty)
.setKeyPredicates(keyPredicate);
}
@ -289,7 +269,7 @@ public class ResourcePathParser {
previousTyped.isCollection());
if (boundAction != null) {
ParserHelper.requireTokenEnd(tokenizer);
return new UriResourceActionImpl().setAction(boundAction);
return new UriResourceActionImpl(boundAction);
}
EdmStructuredType type = edm.getEntityType(name);
if (type == null) {
@ -314,169 +294,6 @@ public class ResourcePathParser {
}
}
private List<UriParameter> keyPredicate(final EdmEntityType edmEntityType, final EdmNavigationProperty partner)
throws UriParserException, UriValidationException {
final List<EdmKeyPropertyRef> keyPropertyRefs = edmEntityType.getKeyPropertyRefs();
if (tokenizer.next(TokenKind.CLOSE)) {
throw new UriParserSemanticException(
"Expected " + keyPropertyRefs.size() + " key predicates but none.",
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
Integer.toString(keyPropertyRefs.size()), "0");
}
List<UriParameter> keys = new ArrayList<UriParameter>();
Map<String, String> referencedNames = new HashMap<String, String>();
if (partner != null) {
// Prepare list of potentially missing keys to be filled from referential constraints.
for (final String name : edmEntityType.getKeyPredicateNames()) {
final String referencedName = partner.getReferencingPropertyName(name);
if (referencedName != null) {
referencedNames.put(name, referencedName);
}
}
}
if (tokenizer.next(TokenKind.ODataIdentifier)) {
keys.addAll(compoundKey(edmEntityType));
} else if (keyPropertyRefs.size() - referencedNames.size() == 1) {
for (final EdmKeyPropertyRef candidate : keyPropertyRefs) {
if (referencedNames.get(candidate.getName()) == null) {
keys.add(simpleKey(candidate));
break;
}
}
} else {
throw new UriParserSemanticException(
"Expected " + (keyPropertyRefs.size() -referencedNames.size()) + " key predicates but found one.",
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
Integer.toString(keyPropertyRefs.size() - referencedNames.size()), "1");
}
if (keys.size() < keyPropertyRefs.size() && partner != null) {
// Fill missing keys from referential constraints.
for (final String name : edmEntityType.getKeyPredicateNames()) {
boolean found = false;
for (final UriParameter key : keys) {
if (name.equals(key.getName())) {
found = true;
break;
}
}
if (!found && referencedNames.get(name) != null) {
keys.add(0, new UriParameterImpl().setName(name).setReferencedProperty(referencedNames.get(name)));
}
}
}
// Check that all key predicates are filled from the URI.
if (keys.size() < keyPropertyRefs.size()) {
throw new UriParserSemanticException(
"Expected " + keyPropertyRefs.size() + " key predicates but found " + keys.size() + ".",
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
Integer.toString(keyPropertyRefs.size()), Integer.toString(keys.size()));
} else {
return keys;
}
}
private UriParameter simpleKey(final EdmKeyPropertyRef edmKeyPropertyRef)
throws UriParserException, UriValidationException {
final EdmProperty edmProperty = edmKeyPropertyRef == null ? null : edmKeyPropertyRef.getProperty();
if (nextPrimitiveTypeValue(
edmProperty == null ? null : (EdmPrimitiveType) edmProperty.getType(),
edmProperty == null ? false : edmProperty.isNullable())) {
final String literalValue = tokenizer.getText();
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
return createUriParameter(edmProperty, edmKeyPropertyRef.getName(), literalValue);
} else {
throw new UriParserSemanticException("The key value is not valid.",
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, edmKeyPropertyRef.getName());
}
}
private List<UriParameter> compoundKey(final EdmEntityType edmEntityType)
throws UriParserException, UriValidationException {
List<UriParameter> parameters = new ArrayList<UriParameter>();
List<String> parameterNames = new ArrayList<String>();
// To validate that each key predicate is exactly specified once, we use a list to pick from.
List<String> remainingKeyNames = new ArrayList<String>(edmEntityType.getKeyPredicateNames());
// At least one key predicate is mandatory. Try to fetch all.
boolean hasComma = false;
do {
final String keyPredicateName = tokenizer.getText();
if (parameterNames.contains(keyPredicateName)) {
throw new UriValidationException("Duplicated key property " + keyPredicateName,
UriValidationException.MessageKeys.DOUBLE_KEY_PROPERTY, keyPredicateName);
}
if (remainingKeyNames.isEmpty()) {
throw new UriParserSemanticException("Too many key properties.",
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
Integer.toString(parameters.size()), Integer.toString(parameters.size() + 1));
}
if (!remainingKeyNames.remove(keyPredicateName)) {
throw new UriValidationException("Unknown key property " + keyPredicateName,
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, keyPredicateName);
}
parameters.add(keyValuePair(keyPredicateName, edmEntityType));
parameterNames.add(keyPredicateName);
hasComma = tokenizer.next(TokenKind.COMMA);
if (hasComma) {
ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
}
} while (hasComma);
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
return parameters;
}
private UriParameter keyValuePair(final String keyPredicateName, final EdmEntityType edmEntityType)
throws UriParserException, UriValidationException {
final EdmKeyPropertyRef keyPropertyRef = edmEntityType.getKeyPropertyRef(keyPredicateName);
final EdmProperty edmProperty = keyPropertyRef == null ? null : keyPropertyRef.getProperty();
if (edmProperty == null) {
throw new UriValidationException(keyPredicateName + " is not a valid key property name.",
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, keyPredicateName);
}
ParserHelper.requireNext(tokenizer, TokenKind.EQ);
if (tokenizer.next(TokenKind.COMMA) || tokenizer.next(TokenKind.CLOSE) || tokenizer.next(TokenKind.EOF)) {
throw new UriParserSyntaxException("Key value expected.", UriParserSyntaxException.MessageKeys.SYNTAX);
}
if (nextPrimitiveTypeValue((EdmPrimitiveType) edmProperty.getType(), edmProperty.isNullable())) {
return createUriParameter(edmProperty, keyPredicateName, tokenizer.getText());
} else {
throw new UriParserSemanticException(keyPredicateName + " has not a valid key value.",
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, keyPredicateName);
}
}
private UriParameter createUriParameter(final EdmProperty edmProperty, final String parameterName,
final String literalValue) throws UriParserException, UriValidationException {
if (literalValue.startsWith("@")) {
return new UriParameterImpl()
.setName(parameterName)
.setAlias(literalValue);
}
final EdmPrimitiveType primitiveType = (EdmPrimitiveType) edmProperty.getType();
try {
if (!(primitiveType.validate(primitiveType.fromUriLiteral(literalValue), edmProperty.isNullable(),
edmProperty.getMaxLength(), edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode()))) {
throw new UriValidationException("Invalid key property",
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, parameterName);
}
} catch (final EdmPrimitiveTypeException e) {
throw new UriValidationException("Invalid key property",
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, parameterName);
}
return new UriParameterImpl()
.setName(parameterName)
.setText("null".equals(literalValue) ? null : literalValue);
}
private UriResource typeCast(final FullQualifiedName name, final EdmStructuredType type,
final UriResourcePartTyped previousTyped) throws UriParserException, UriValidationException {
if (type.compatibleTo(previousTyped.getType())) {
@ -501,7 +318,7 @@ public class ResourcePathParser {
}
if (tokenizer.next(TokenKind.OPEN)) {
((UriResourceWithKeysImpl) previousTyped).setKeyPredicates(
keyPredicate((EdmEntityType) type, null));
ParserHelper.parseKeyPredicate(tokenizer, (EdmEntityType) type, null));
}
} else {
previousTypeFilter = ((UriResourceTypedImpl) previousTyped).getTypeFilter();
@ -534,11 +351,8 @@ public class ResourcePathParser {
private UriResource functionCall(final EdmFunctionImport edmFunctionImport,
final FullQualifiedName boundFunctionName, final FullQualifiedName bindingParameterTypeName,
final boolean isBindingParameterCollection) throws UriParserException, UriValidationException {
final List<UriParameter> parameters = functionParameters();
List<String> names = new ArrayList<String>();
for (final UriParameter parameter : parameters) {
names.add(parameter.getName());
}
final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, false);
final List<String> names = ParserHelper.getParameterNames(parameters);
EdmFunction function = null;
if (edmFunctionImport != null) {
function = edmFunctionImport.getUnboundFunction(names);
@ -557,16 +371,13 @@ public class ResourcePathParser {
UriParserSemanticException.MessageKeys.UNKNOWN_PART, boundFunctionName.getFullQualifiedNameAsString());
}
}
UriResourceFunctionImpl resource = new UriResourceFunctionImpl()
.setFunctionImport(edmFunctionImport, null)
.setFunction(function)
.setParameters(parameters);
UriResourceFunctionImpl resource = new UriResourceFunctionImpl(edmFunctionImport, function, parameters);
if (tokenizer.next(TokenKind.OPEN)) {
if (function.getReturnType() != null
&& function.getReturnType().getType().getKind() == EdmTypeKind.ENTITY
&& function.getReturnType().isCollection()) {
resource.setKeyPredicates(
keyPredicate((EdmEntityType) function.getReturnType().getType(), null));
ParserHelper.parseKeyPredicate(tokenizer, (EdmEntityType) function.getReturnType().getType(), null));
} else {
throw new UriParserSemanticException("A key is not allowed.",
UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
@ -575,106 +386,4 @@ public class ResourcePathParser {
ParserHelper.requireTokenEnd(tokenizer);
return resource;
}
private List<UriParameter> functionParameters() throws UriParserException {
List<UriParameter> parameters = new ArrayList<UriParameter>();
ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
if (tokenizer.next(TokenKind.CLOSE)) {
return parameters;
}
do {
ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
final String name = tokenizer.getText();
if (parameters.contains(name)) {
throw new UriParserSemanticException("Duplicated function parameter " + name,
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, name);
}
ParserHelper.requireNext(tokenizer, TokenKind.EQ);
if (tokenizer.next(TokenKind.COMMA) || tokenizer.next(TokenKind.CLOSE) || tokenizer.next(TokenKind.EOF)) {
throw new UriParserSyntaxException("Parameter value expected.", UriParserSyntaxException.MessageKeys.SYNTAX);
}
if (tokenizer.next(TokenKind.ParameterAliasName)) {
parameters.add(new UriParameterImpl().setName(name).setAlias(tokenizer.getText()));
} else if (nextPrimitiveValue()) {
final String literalValue = tokenizer.getText();
parameters.add(new UriParameterImpl().setName(name)
.setText("null".equals(literalValue) ? null : literalValue));
} else {
throw new UriParserSemanticException("Wrong parameter value.",
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, "");
}
} while (tokenizer.next(TokenKind.COMMA));
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
return parameters;
}
private boolean nextPrimitiveTypeValue(final EdmPrimitiveType primitiveType, final boolean nullable) {
final EdmPrimitiveType type = primitiveType instanceof EdmTypeDefinition ?
((EdmTypeDefinition) primitiveType).getUnderlyingType() :
primitiveType;
if (tokenizer.next(TokenKind.ParameterAliasName)) {
return true;
} else if (nullable && tokenizer.next(TokenKind.NULL)) {
return true;
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean).equals(type)) {
return tokenizer.next(TokenKind.BooleanValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String).equals(type)) {
return tokenizer.next(TokenKind.StringValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.SByte).equals(type)
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Byte).equals(type)
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int16).equals(type)
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int32).equals(type)
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int64).equals(type)) {
return tokenizer.next(TokenKind.IntegerValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Guid).equals(type)) {
return tokenizer.next(TokenKind.GuidValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Date).equals(type)) {
return tokenizer.next(TokenKind.DateValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.DateTimeOffset).equals(type)) {
return tokenizer.next(TokenKind.DateTimeOffsetValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.TimeOfDay).equals(type)) {
return tokenizer.next(TokenKind.TimeOfDayValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal).equals(type)) {
// The order is important.
// A decimal value should not be parsed as integer and let the tokenizer stop at the decimal point.
return tokenizer.next(TokenKind.DecimalValue)
|| tokenizer.next(TokenKind.IntegerValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Double).equals(type)) {
// The order is important.
// A floating-point value should not be parsed as decimal and let the tokenizer stop at 'E'.
// A decimal value should not be parsed as integer and let the tokenizer stop at the decimal point.
return tokenizer.next(TokenKind.DoubleValue)
|| tokenizer.next(TokenKind.DecimalValue)
|| tokenizer.next(TokenKind.IntegerValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Duration).equals(type)) {
return tokenizer.next(TokenKind.DurationValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Binary).equals(type)) {
return tokenizer.next(TokenKind.BinaryValue);
} else if (type.getKind() == EdmTypeKind.ENUM) {
return tokenizer.next(TokenKind.EnumValue);
} else {
return false;
}
}
private boolean nextPrimitiveValue() {
return tokenizer.next(TokenKind.NULL)
|| tokenizer.next(TokenKind.BooleanValue)
|| tokenizer.next(TokenKind.StringValue)
// The order of the next seven expressions is important in order to avoid
// finding partly parsed tokens (counter-intuitive as it may be, even a GUID may start with digits ...).
|| tokenizer.next(TokenKind.DoubleValue)
|| tokenizer.next(TokenKind.DecimalValue)
|| tokenizer.next(TokenKind.GuidValue)
|| tokenizer.next(TokenKind.DateTimeOffsetValue)
|| tokenizer.next(TokenKind.DateValue)
|| tokenizer.next(TokenKind.TimeOfDayValue)
|| tokenizer.next(TokenKind.IntegerValue)
|| tokenizer.next(TokenKind.DurationValue)
|| tokenizer.next(TokenKind.BinaryValue)
|| tokenizer.next(TokenKind.EnumValue);
}
}

View File

@ -156,10 +156,10 @@ public class SelectParser {
throw new UriParserSemanticException("Function not found.",
UriParserSemanticException.MessageKeys.UNKNOWN_PART, qualifiedName.getFullQualifiedNameAsString());
} else {
return new UriResourceFunctionImpl().setFunction(boundFunction);
return new UriResourceFunctionImpl(null, boundFunction, null);
}
} else {
return new UriResourceActionImpl().setAction(boundAction);
return new UriResourceActionImpl(boundAction);
}
}
@ -187,16 +187,16 @@ public class SelectParser {
UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE,
referencedType.getName(), name);
} else {
resource.addResourcePart(new UriResourceNavigationPropertyImpl().setNavigationProperty(navigationProperty));
resource.addResourcePart(new UriResourceNavigationPropertyImpl(navigationProperty));
}
} else if (property.isPrimitive()
|| property.getType().getKind() == EdmTypeKind.ENUM
|| property.getType().getKind() == EdmTypeKind.DEFINITION) {
resource.addResourcePart(new UriResourcePrimitivePropertyImpl().setProperty(property));
resource.addResourcePart(new UriResourcePrimitivePropertyImpl(property));
} else {
UriResourceComplexPropertyImpl complexPart = new UriResourceComplexPropertyImpl().setProperty(property);
UriResourceComplexPropertyImpl complexPart = new UriResourceComplexPropertyImpl(property);
resource.addResourcePart(complexPart);
if (tokenizer.next(TokenKind.SLASH)) {
if (tokenizer.next(TokenKind.QualifiedName)) {

View File

@ -32,10 +32,9 @@ import org.apache.olingo.server.core.uri.queryoption.SelectItemImpl;
*/
public class UriContext {
public static class LambdaVariables {
public static class LambdaVariable {
public String name;
public EdmType type;
public boolean isCollection;
}
/**
@ -43,7 +42,7 @@ public class UriContext {
* As lambda functions can be nested there may be more than one allowed lambda variables at a time while parsing a
* $filter or $orderby expressions.
*/
public Deque<LambdaVariables> allowedLambdaVariables;
public Deque<LambdaVariable> allowedLambdaVariables;
/**
* Used to stack type information for nested $expand, $filter query options and other cases.
*/
@ -110,7 +109,7 @@ public class UriContext {
contextReadingFunctionParameters = false;
contextSelectItem = null;
contextTypes = new ArrayDeque<EdmType>();
allowedLambdaVariables = new ArrayDeque<UriContext.LambdaVariables>();
allowedLambdaVariables = new ArrayDeque<UriContext.LambdaVariable>();
}
}

View File

@ -252,8 +252,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
return new FullQualifiedName(namespace, odi);
}
private UriContext.LambdaVariables getLambdaVar(final String odi) {
for (UriContext.LambdaVariables item : context.allowedLambdaVariables) {
private UriContext.LambdaVariable getLambdaVar(final String odi) {
for (UriContext.LambdaVariable item : context.allowedLambdaVariables) {
if (item.name.equals(odi)) {
return item;
}
@ -292,7 +292,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|| parts.get(0) instanceof UriResourceRoot)) {
ensureNamespaceIsNull(ctx.vNS);
context.contextUriInfo.addResourcePart(
new UriResourceEntitySetImpl().setEntitSet(edmEntitySet));
new UriResourceEntitySetImpl(edmEntitySet));
return null;
}
@ -303,7 +303,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|| parts.get(0) instanceof UriResourceRoot)) {
ensureNamespaceIsNull(ctx.vNS);
context.contextUriInfo.addResourcePart(
new UriResourceSingletonImpl().setSingleton(edmSingleton));
new UriResourceSingletonImpl(edmSingleton));
return null;
}
@ -314,7 +314,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|| parts.get(0) instanceof UriResourceRoot)) {
ensureNamespaceIsNull(ctx.vNS);
context.contextUriInfo.addResourcePart(
new UriResourceActionImpl().setActionImport(edmActionImport));
new UriResourceActionImpl(edmActionImport));
return null;
}
@ -344,9 +344,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
// mark parameters as consumed
ctx.vlNVO.remove(0);
UriResourceFunctionImpl uriResource = new UriResourceFunctionImpl()
.setFunctionImport(edmFunctionImport, parameters);
// collect parameter names
List<String> names = new ArrayList<String>();
for (UriParameter item : parameters) {
@ -366,7 +363,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
}
ensureNamespaceIsNull(ctx.vNS);
uriResource.setFunction(edmFunctionImport.getUnboundFunction(names));
UriResourceFunctionImpl uriResource = new UriResourceFunctionImpl(edmFunctionImport,
edmFunctionImport.getUnboundFunction(names),
parameters);
context.contextUriInfo.addResourcePart(uriResource);
return null;
}
@ -390,7 +389,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
sourceType = context.contextTypes.peek();
sourceIsCollection = context.isCollection;
} else if (lastResourcePart instanceof UriResourcePartTyped) {
sourceType = Parser.getTypeInformation((UriResourcePartTyped) lastResourcePart);
sourceType = ParserHelper.getTypeInformation((UriResourcePartTyped) lastResourcePart);
sourceIsCollection = ((UriResourcePartTyped) lastResourcePart).isCollection();
} else {
throw wrap(new UriParserSemanticException(
@ -401,12 +400,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
if (ctx.vNS == null) { // without namespace
// first check for lambda variable because a newly add property should not shadow a long used lambda variable
UriContext.LambdaVariables lVar = getLambdaVar(odi);
UriContext.LambdaVariable lVar = getLambdaVar(odi);
if (lVar != null) {
UriResourceLambdaVarImpl lambdaResource = new UriResourceLambdaVarImpl();
lambdaResource.setVariableText(lVar.name);
lambdaResource.setType(lVar.type);
lambdaResource.setCollection(lVar.isCollection);
UriResourceLambdaVarImpl lambdaResource = new UriResourceLambdaVarImpl(lVar.name, lVar.type);
context.contextUriInfo.addResourcePart(lambdaResource);
return null;
}
@ -442,14 +438,13 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|| property.getType().getKind() == EdmTypeKind.ENUM
|| property.getType().getKind() == EdmTypeKind.DEFINITION) {
// create simple property
UriResourcePrimitivePropertyImpl simpleResource = new UriResourcePrimitivePropertyImpl()
.setProperty((EdmProperty) property);
UriResourcePrimitivePropertyImpl simpleResource =
new UriResourcePrimitivePropertyImpl((EdmProperty) property);
context.contextUriInfo.addResourcePart(simpleResource);
return null;
} else {
// create complex property
UriResourceComplexPropertyImpl complexResource = new UriResourceComplexPropertyImpl()
.setProperty((EdmProperty) property);
UriResourceComplexPropertyImpl complexResource = new UriResourceComplexPropertyImpl((EdmProperty) property);
context.contextUriInfo.addResourcePart(complexResource);
return null;
}
@ -461,8 +456,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
}
UriResourceNavigationPropertyImpl navigationResource = new UriResourceNavigationPropertyImpl()
.setNavigationProperty((EdmNavigationProperty) property);
UriResourceNavigationPropertyImpl navigationResource =
new UriResourceNavigationPropertyImpl((EdmNavigationProperty) property);
context.contextUriInfo.addResourcePart(navigationResource);
return null;
} else {
@ -488,9 +483,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
if (lastResourcePart == null) {
// this may be the case if a member expression within a filter starts with a typeCast
UriResourceStartingTypeFilterImpl uriResource = new UriResourceStartingTypeFilterImpl()
.setType(filterEntityType)
.setCollection(sourceIsCollection);
UriResourceStartingTypeFilterImpl uriResource = new UriResourceStartingTypeFilterImpl(
filterEntityType,
sourceIsCollection);
if (sourceIsCollection) {
uriResource.setCollectionTypeFilter(filterEntityType);
} else {
@ -562,9 +557,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
// is simple complex type cast
if (lastResourcePart == null) {
// this may be the case if a member expression within a filter starts with a typeCast
UriResourceStartingTypeFilterImpl uriResource = new UriResourceStartingTypeFilterImpl()
.setType(filterComplexType)
.setCollection(sourceIsCollection);
UriResourceStartingTypeFilterImpl uriResource =
new UriResourceStartingTypeFilterImpl(filterComplexType, sourceIsCollection);
if (sourceIsCollection) {
uriResource.setCollectionTypeFilter(filterComplexType);
@ -626,8 +620,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
// check for action
EdmAction action = edm.getBoundAction(fullFilterName, fullBindingTypeName, sourceIsCollection);
if (action != null) {
UriResourceActionImpl pathInfoAction = new UriResourceActionImpl();
pathInfoAction.setAction(action);
UriResourceActionImpl pathInfoAction = new UriResourceActionImpl(action);
context.contextUriInfo.addResourcePart(pathInfoAction);
return null;
}
@ -652,9 +645,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
EdmFunction function = edm.getBoundFunction(fullFilterName, fullBindingTypeName, sourceIsCollection, names);
if (function != null) {
UriResourceFunctionImpl pathInfoFunction = new UriResourceFunctionImpl()
.setFunction(function)
.setParameters(parameters);
UriResourceFunctionImpl pathInfoFunction = new UriResourceFunctionImpl(null, function, parameters);
context.contextUriInfo.addResourcePart(pathInfoFunction);
// mark parameters as consumed
@ -666,9 +657,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
function = edm.getUnboundFunction(fullFilterName, names);
if (function != null) {
UriResourceFunctionImpl pathInfoFunction = new UriResourceFunctionImpl()
.setFunction(function)
.setParameters(parameters);
UriResourceFunctionImpl pathInfoFunction = new UriResourceFunctionImpl(null, function, parameters);
context.contextUriInfo.addResourcePart(pathInfoFunction);
// mark parameters as consumed
@ -706,8 +695,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
@Override
public Object visitAllExpr(final AllExprContext ctx) {
UriResourceLambdaAllImpl all = new UriResourceLambdaAllImpl();
UriResource obj = context.contextUriInfo.getLastResourcePart();
if (!(obj instanceof UriResourcePartTyped)) {
throw wrap(new UriParserSemanticException("all only allowed on typed path segments",
@ -720,16 +707,14 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
}
}
UriContext.LambdaVariables var = new UriContext.LambdaVariables();
UriContext.LambdaVariable var = new UriContext.LambdaVariable();
var.name = ctx.vLV.getText();
var.type = Parser.getTypeInformation((UriResourcePartTyped) obj);
var.isCollection = false;
var.type = ParserHelper.getTypeInformation((UriResourcePartTyped) obj);
all.setLamdaVariable(ctx.vLV.getText());
context.allowedLambdaVariables.push(var);
all.setExpression((Expression) ctx.vLE.accept(this));
Expression expression = (Expression) ctx.vLE.accept(this);
context.allowedLambdaVariables.pop();
return all;
return new UriResourceLambdaAllImpl(var.name, expression);
}
@Override
@ -895,7 +880,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
@Override
public Object visitAnyExpr(final AnyExprContext ctx) {
UriResourceLambdaAnyImpl any = new UriResourceLambdaAnyImpl();
if (ctx.vLV != null) {
UriResourceImpl lastResourcePart = (UriResourceImpl) context.contextUriInfo.getLastResourcePart();
if (!(lastResourcePart instanceof UriResourcePartTyped)) {
@ -909,17 +893,16 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
}
}
UriContext.LambdaVariables var = new UriContext.LambdaVariables();
UriContext.LambdaVariable var = new UriContext.LambdaVariable();
var.name = ctx.vLV.getText();
var.type = Parser.getTypeInformation((UriResourcePartTyped) lastResourcePart);
var.isCollection = false;
var.type = ParserHelper.getTypeInformation((UriResourcePartTyped) lastResourcePart);
any.setLamdaVariable(ctx.vLV.getText());
context.allowedLambdaVariables.push(var);
any.setExpression((Expression) ctx.vLE.accept(this));
Expression expression = (Expression) ctx.vLE.accept(this);
context.allowedLambdaVariables.pop();
return new UriResourceLambdaAnyImpl(var.name, expression);
}
return any;
return null;
}
@Override
@ -1238,18 +1221,18 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
if (context.contextExpandItemPath == null) {
// use the type of the last resource path segement
UriResourceTypedImpl lastSegment = (UriResourceTypedImpl) context.contextUriInfo.getLastResourcePart();
targetType = Parser.getTypeInformation(lastSegment);
targetType = ParserHelper.getTypeInformation(lastSegment);
isColl = lastSegment.isCollection();
} else {
if (context.contextExpandItemPath.getResourcePath() == null) {
// use the type of the last resource path segement
UriResourceTypedImpl lastSegment = (UriResourceTypedImpl) context.contextUriInfo.getLastResourcePart();
targetType = Parser.getTypeInformation(lastSegment);
targetType = ParserHelper.getTypeInformation(lastSegment);
isColl = lastSegment.isCollection();
} else {
// use the type of the last ''expand'' path segement
UriInfoImpl info = (UriInfoImpl) context.contextExpandItemPath.getResourcePath();
targetType = Parser.getTypeInformation((UriResourcePartTyped) info.getLastResourcePart());
targetType = ParserHelper.getTypeInformation((UriResourcePartTyped) info.getLastResourcePart());
isColl = ((UriResourcePartTyped) info.getLastResourcePart()).isCollection();
}
}
@ -1400,10 +1383,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
}
if (ctx.vIt != null || ctx.vIts != null) {
UriResourceItImpl pathInfoIT = new UriResourceItImpl();
pathInfoIT.setType(context.contextTypes.peek());
pathInfoIT.setCollection(context.isCollection);
uriInfoImplpath.addResourcePart(pathInfoIT);
uriInfoImplpath.addResourcePart(new UriResourceItImpl(context.contextTypes.peek(), context.isCollection));
}
if (ctx.vPs != null) {
@ -1915,9 +1895,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
UriResourcePartTyped lastType = (UriResourcePartTyped) lastResource;
UriResourceRootImpl pathInfoRoot = new UriResourceRootImpl();
pathInfoRoot.setCollection(lastType.isCollection());
pathInfoRoot.setType(Parser.getTypeInformation(lastType));
UriResourceRootImpl pathInfoRoot = new UriResourceRootImpl(
ParserHelper.getTypeInformation(lastType),
lastType.isCollection());
UriInfoImpl uriInfoImplpath = new UriInfoImpl().setKind(UriInfoKind.resource);
uriInfoImplpath.addResourcePart(pathInfoRoot);
@ -2010,7 +1990,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
UriInfoImpl uriInfo = (UriInfoImpl) context.contextSelectItem.getResourcePath();
UriResource last = uriInfo.getLastResourcePart();
prevType = Parser.getTypeInformation((UriResourcePartTyped) last);
prevType = ParserHelper.getTypeInformation((UriResourcePartTyped) last);
if (prevType == null) {
throw wrap(new UriParserSemanticException("prev segment not typed",
UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "select"));
@ -2038,8 +2018,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|| property.getType().getKind() == EdmTypeKind.ENUM
|| property.getType().getKind() == EdmTypeKind.DEFINITION) {
UriResourcePrimitivePropertyImpl simple = new UriResourcePrimitivePropertyImpl();
simple.setProperty(property);
UriResourcePrimitivePropertyImpl simple = new UriResourcePrimitivePropertyImpl(property);
UriInfoImpl uriInfo = (UriInfoImpl) context.contextSelectItem.getResourcePath();
if (uriInfo == null) {
@ -2059,8 +2038,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
} else {
UriInfoImpl uriInfo = (UriInfoImpl) context.contextSelectItem.getResourcePath();
UriResourceComplexPropertyImpl complex = new UriResourceComplexPropertyImpl();
complex.setProperty(property);
UriResourceComplexPropertyImpl complex = new UriResourceComplexPropertyImpl(property);
if (uriInfo == null) {
uriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
@ -2096,7 +2074,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
EdmComplexType ct = edm.getComplexType(fullName);
if (ct != null) {
if ((ct.compatibleTo(prevType))) {
UriResourceStartingTypeFilterImpl resourcePart = new UriResourceStartingTypeFilterImpl();
UriResourceStartingTypeFilterImpl resourcePart = new UriResourceStartingTypeFilterImpl(null, false);
resourcePart.setCollectionTypeFilter(ct);
UriInfoImpl uriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
@ -2115,7 +2093,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
EdmEntityType et = edm.getEntityType(fullName);
if (et != null) {
if ((et.compatibleTo(prevType))) {
UriResourceStartingTypeFilterImpl resourcePart = new UriResourceStartingTypeFilterImpl();
UriResourceStartingTypeFilterImpl resourcePart = new UriResourceStartingTypeFilterImpl(null, false);
resourcePart.setCollectionTypeFilter(et);
UriInfoImpl uriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
@ -2142,13 +2120,13 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
throw wrap(new UriParserSemanticException("prev segment typed",
UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "select"));
}
EdmType prevType = Parser.getTypeInformation((UriResourcePartTyped) last);
EdmType prevType = ParserHelper.getTypeInformation((UriResourcePartTyped) last);
if (prevType instanceof EdmComplexType) {
EdmComplexType ct = edm.getComplexType(fullName);
if (ct != null) {
if ((ct.compatibleTo(prevType))) {
UriResourceStartingTypeFilterImpl resourcePart = new UriResourceStartingTypeFilterImpl();
UriResourceStartingTypeFilterImpl resourcePart = new UriResourceStartingTypeFilterImpl(null, false);
resourcePart.setCollectionTypeFilter(ct);
uriInfo.addResourcePart(resourcePart);
@ -2186,7 +2164,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
throw wrap(new UriParserSemanticException("prev segment typed",
UriParserSemanticException.MessageKeys.PREVIOUS_PART_TYPED));
}
prevType = Parser.getTypeInformation((UriResourcePartTyped) last);
prevType = ParserHelper.getTypeInformation((UriResourcePartTyped) last);
}
final FullQualifiedName finalTypeName = prevType.getFullQualifiedName();
@ -2195,8 +2173,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
EdmAction action = edm.getBoundAction(fullName, finalTypeName, null);
if (action != null) {
UriResourceActionImpl uriAction = new UriResourceActionImpl();
uriAction.setAction(action);
UriResourceActionImpl uriAction = new UriResourceActionImpl(action);
UriInfoImpl resourcePath = (UriInfoImpl) context.contextSelectItem.getResourcePath();
resourcePath.addResourcePart(uriAction);
@ -2206,8 +2183,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
EdmFunction function = edm.getBoundFunction(fullName, finalTypeName, null, null);
if (function != null) {
UriResourceFunctionImpl uriFunction = new UriResourceFunctionImpl();
uriFunction.setFunction(function);
UriResourceFunctionImpl uriFunction = new UriResourceFunctionImpl(null, function, null);
UriInfoImpl resourcePath = (UriInfoImpl) context.contextSelectItem.getResourcePath();
resourcePath.addResourcePart(uriFunction);

View File

@ -40,10 +40,14 @@ public class UriTokenizer {
ROOT,
IT,
ANY,
ALL,
OPEN,
CLOSE,
COMMA,
SEMI,
COLON,
DOT,
SLASH,
EQ,
@ -119,7 +123,10 @@ public class UriTokenizer {
TotalsecondsMethod,
ToupperMethod,
TrimMethod,
YearMethod
YearMethod,
AscSuffix,
DescSuffix
}
private final String parseString;
@ -174,6 +181,13 @@ public class UriTokenizer {
found = nextConstant("$it");
break;
case ANY:
found = nextConstant("any");
break;
case ALL:
found = nextConstant("all");
break;
case OPEN:
found = nextCharacter('(');
break;
@ -186,6 +200,9 @@ public class UriTokenizer {
case SEMI:
found = nextCharacter(';');
break;
case COLON:
found = nextCharacter(':');
break;
case DOT:
found = nextCharacter('.');
break;
@ -409,6 +426,14 @@ public class UriTokenizer {
case YearMethod:
found = nextMethod("year");
break;
// Suffixes
case AscSuffix:
found = nextSuffix("asc");
break;
case DescSuffix:
found = nextSuffix("desc");
break;
}
if (found) {
@ -542,6 +567,15 @@ public class UriTokenizer {
return nextConstant(methodName) && nextCharacter('(');
}
/**
* Moves past (required) whitespace and the given suffix name if found;
* otherwise leaves the index unchanged.
* @return whether the suffix has been found at the current index
*/
private boolean nextSuffix(final String suffixName) {
return nextWhitespace() && nextConstant(suffixName);
}
/**
* Moves past an OData identifier if found; otherwise leaves the index unchanged.
* @return whether an OData identifier has been found at the current index

View File

@ -94,4 +94,9 @@ public class MemberImpl implements Member {
}
return false;
}
@Override
public String toString() {
return path.getUriResourceParts().toString() + (startTypeFilter == null ? "" : startTypeFilter);
}
}

View File

@ -25,6 +25,7 @@ import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import org.apache.olingo.commons.api.edm.EdmAction;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
import org.apache.olingo.server.api.uri.UriInfo;
@ -33,9 +34,6 @@ import org.apache.olingo.server.api.uri.UriResourceAction;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
import org.apache.olingo.server.api.uri.queryoption.QueryOption;
import org.apache.olingo.server.core.uri.UriInfoImpl;
import org.apache.olingo.server.core.uri.UriResourceActionImpl;
import org.apache.olingo.server.core.uri.UriResourceEntitySetImpl;
import org.apache.olingo.server.core.uri.queryoption.AliasQueryOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.CustomQueryOptionImpl;
@ -86,9 +84,9 @@ public class UriInfoImplTest {
public void resourceParts() {
UriInfoImpl uriInfo = new UriInfoImpl();
final UriResourceAction action = new UriResourceActionImpl();
final UriResourceEntitySet entitySet0 = new UriResourceEntitySetImpl();
final UriResourceEntitySet entitySet1 = new UriResourceEntitySetImpl();
final UriResourceAction action = new UriResourceActionImpl((EdmAction) null);
final UriResourceEntitySet entitySet0 = new UriResourceEntitySetImpl(null);
final UriResourceEntitySet entitySet1 = new UriResourceEntitySetImpl(null);
uriInfo.addResourcePart(action);
uriInfo.addResourcePart(entitySet0);

View File

@ -28,6 +28,7 @@ import java.util.Locale;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
import org.junit.Test;
public class ExpressionParserTest {
@ -127,7 +128,7 @@ public class ExpressionParserTest {
@Test
public void unary() throws Exception {
Expression expression = parseExpression("-5");
assertEquals("{MINUS 5}", expression.toString());
assertEquals("-5", expression.toString());
assertEquals("{MINUS -1}", parseExpression("--1").toString());
assertEquals("{MINUS duration'PT1M'}", parseExpression("-duration'PT1M'").toString());
@ -135,13 +136,13 @@ public class ExpressionParserTest {
expression = parseExpression("not false");
assertEquals("{NOT false}", expression.toString());
wrongExpression("-11:12:13");
wrongExpression("not 11:12:13");
}
@Test
public void grouping() throws Exception {
Expression expression = parseExpression("-5 add 5");
assertEquals("{{MINUS 5} ADD 5}", expression.toString());
assertEquals("{-5 ADD 5}", expression.toString());
expression = parseExpression("-(5 add 5)");
assertEquals("{MINUS {5 ADD 5}}", expression.toString());
@ -149,7 +150,7 @@ public class ExpressionParserTest {
@Test
public void precedence() throws Exception {
assertEquals("{{MINUS 1} ADD {2 DIV 3}}", parseExpression("-1 add 2 div 3").toString());
assertEquals("{-1 ADD {2 DIV 3}}", parseExpression("-1 add 2 div 3").toString());
assertEquals("{true OR {{NOT false} AND true}}", parseExpression("true or not false and true").toString());
}
@ -264,7 +265,8 @@ public class ExpressionParserTest {
wrongExpression("substring(1,2)");
}
private Expression parseMethod(TokenKind kind, String... parameters) throws UriParserException {
private Expression parseMethod(TokenKind kind, String... parameters)
throws UriParserException, UriValidationException {
String expressionString = kind.name().substring(0, kind.name().indexOf("Method"))
.toLowerCase(Locale.ROOT).replace("geo", "geo.") + '(';
boolean first = true;
@ -283,9 +285,10 @@ public class ExpressionParserTest {
return expression;
}
private Expression parseExpression(final String expressionString) throws UriParserException {
private Expression parseExpression(final String expressionString)
throws UriParserException, UriValidationException {
UriTokenizer tokenizer = new UriTokenizer(expressionString);
Expression expression = new ExpressionParser(null, odata).parse(tokenizer);
Expression expression = new ExpressionParser(null, odata).parse(tokenizer, null, null);
assertNotNull(expression);
assertTrue(tokenizer.next(TokenKind.EOF));
return expression;
@ -293,10 +296,12 @@ public class ExpressionParserTest {
private void wrongExpression(final String expressionString) {
try {
new ExpressionParser(null, odata).parse(new UriTokenizer(expressionString));
new ExpressionParser(null, odata).parse(new UriTokenizer(expressionString), null, null);
fail("Expected exception not thrown.");
} catch (final UriParserException e) {
assertNotNull(e);
} catch (final UriValidationException e) {
assertNotNull(e);
}
}
}

View File

@ -55,7 +55,7 @@ public class UriTokenizerTest {
@Test
public void sequence() {
final UriTokenizer tokenizer = new UriTokenizer("(A=1,B=2);.*/+-");
UriTokenizer tokenizer = new UriTokenizer("(A=1,B=2);.*/+-");
assertTrue(tokenizer.next(TokenKind.OPEN));
assertFalse(tokenizer.next(TokenKind.OPEN));
assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
@ -78,6 +78,22 @@ public class UriTokenizerTest {
assertTrue(tokenizer.next(TokenKind.PLUS));
assertTrue(tokenizer.next(TokenKind.MINUS));
assertTrue(tokenizer.next(TokenKind.EOF));
tokenizer = new UriTokenizer("any(a:true) or all(b:false)");
assertTrue(tokenizer.next(TokenKind.ANY));
assertTrue(tokenizer.next(TokenKind.OPEN));
assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
assertTrue(tokenizer.next(TokenKind.COLON));
assertTrue(tokenizer.next(TokenKind.BooleanValue));
assertTrue(tokenizer.next(TokenKind.CLOSE));
assertTrue(tokenizer.next(TokenKind.OrOperator));
assertTrue(tokenizer.next(TokenKind.ALL));
assertTrue(tokenizer.next(TokenKind.OPEN));
assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
assertTrue(tokenizer.next(TokenKind.COLON));
assertTrue(tokenizer.next(TokenKind.BooleanValue));
assertTrue(tokenizer.next(TokenKind.CLOSE));
assertTrue(tokenizer.next(TokenKind.EOF));
}
@Test
@ -455,6 +471,19 @@ public class UriTokenizerTest {
}
}
@Test
public void suffixes() {
UriTokenizer tokenizer = new UriTokenizer("p1 asc,p2 desc");
assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
assertTrue(tokenizer.next(TokenKind.AscSuffix));
assertTrue(tokenizer.next(TokenKind.COMMA));
assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
assertTrue(tokenizer.next(TokenKind.DescSuffix));
assertTrue(tokenizer.next(TokenKind.EOF));
wrongToken(TokenKind.DescSuffix, " desc", 'D');
}
private void wrongToken(final TokenKind kind, final String value, final char disturbCharacter) {
assertFalse(new UriTokenizer(disturbCharacter + value).next(kind));

View File

@ -57,7 +57,7 @@ public class UriResourceImplTest {
new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
@Test
public void testUriParameterImpl() {
public void uriParameterImpl() {
UriParameterImpl impl = new UriParameterImpl();
Expression expression = new LiteralImpl("Expression", null);
@ -73,21 +73,20 @@ public class UriResourceImplTest {
}
@Test
public void testUriResourceActionImpl() {
UriResourceActionImpl impl = new UriResourceActionImpl();
public void uriResourceActionImpl() {
UriResourceActionImpl impl = new UriResourceActionImpl((EdmAction) null);
assertEquals(UriResourceKind.action, impl.getKind());
assertEquals("", impl.toString());
// action
EdmAction action = edm.getUnboundAction(ActionProvider.nameUARTETTwoKeyTwoPrimParam);
impl.setAction(action);
impl = new UriResourceActionImpl(action);
assertEquals(action, impl.getAction());
assertEquals(ActionProvider.nameUARTETTwoKeyTwoPrimParam.getName(), impl.toString());
// action import
impl = new UriResourceActionImpl();
EdmActionImport actionImport = edm.getEntityContainer().getActionImport("AIRTCTTwoPrimParam");
impl.setActionImport(actionImport);
impl = new UriResourceActionImpl(actionImport);
assertEquals(actionImport, impl.getActionImport());
assertEquals(actionImport.getUnboundAction(), impl.getAction());
assertFalse(impl.isCollection());
@ -95,20 +94,16 @@ public class UriResourceImplTest {
assertEquals(actionImport.getUnboundAction().getReturnType().getType(), impl.getType());
actionImport = edm.getEntityContainer().getActionImport("AIRT");
impl.setActionImport(actionImport);
impl = new UriResourceActionImpl(actionImport);
assertFalse(impl.isCollection());
assertNull(impl.getType());
}
@Test
public void testUriResourceLambdaAllImpl() {
UriResourceLambdaAllImpl impl = new UriResourceLambdaAllImpl();
assertEquals(UriResourceKind.lambdaAll, impl.getKind());
public void uriResourceLambdaAllImpl() {
Expression expression = new LiteralImpl("Expression", null);
impl.setExpression(expression);
impl.setLamdaVariable("A");
UriResourceLambdaAllImpl impl = new UriResourceLambdaAllImpl("A", expression);
assertEquals(UriResourceKind.lambdaAll, impl.getKind());
assertFalse(impl.isCollection());
assertEquals(expression, impl.getExpression());
assertEquals("A", impl.getLambdaVariable());
@ -117,14 +112,10 @@ public class UriResourceImplTest {
}
@Test
public void testUriResourceLambdaAnyImpl() {
UriResourceLambdaAnyImpl impl = new UriResourceLambdaAnyImpl();
assertEquals(UriResourceKind.lambdaAny, impl.getKind());
public void uriResourceLambdaAnyImpl() {
Expression expression = new LiteralImpl("Expression", null);
impl.setExpression(expression);
impl.setLamdaVariable("A");
UriResourceLambdaAnyImpl impl = new UriResourceLambdaAnyImpl("A", expression);
assertEquals(UriResourceKind.lambdaAny, impl.getKind());
assertFalse(impl.isCollection());
assertEquals(expression, impl.getExpression());
assertEquals("A", impl.getLambdaVariable());
@ -133,14 +124,11 @@ public class UriResourceImplTest {
}
@Test
public void testUriResourceComplexPropertyImpl() {
UriResourceComplexPropertyImpl impl = new UriResourceComplexPropertyImpl();
assertEquals(UriResourceKind.complexProperty, impl.getKind());
public void uriResourceComplexPropertyImpl() {
EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETKeyNav);
EdmProperty property = (EdmProperty) entityType.getProperty("PropertyCompNav");
impl.setProperty(property);
UriResourceComplexPropertyImpl impl = new UriResourceComplexPropertyImpl(property);
assertEquals(UriResourceKind.complexProperty, impl.getKind());
assertEquals(property, impl.getProperty());
assertEquals(property.getName(), impl.toString());
assertFalse(impl.isCollection());
@ -158,14 +146,11 @@ public class UriResourceImplTest {
}
@Test
public void testUriResourcePrimitivePropertyImpl() {
UriResourcePrimitivePropertyImpl impl = new UriResourcePrimitivePropertyImpl();
assertEquals(UriResourceKind.primitiveProperty, impl.getKind());
public void uriResourcePrimitivePropertyImpl() {
EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETKeyNav);
EdmProperty property = (EdmProperty) entityType.getProperty("PropertyInt16");
impl.setProperty(property);
UriResourcePrimitivePropertyImpl impl = new UriResourcePrimitivePropertyImpl(property);
assertEquals(UriResourceKind.primitiveProperty, impl.getKind());
assertEquals(property, impl.getProperty());
assertEquals(property.getName(), impl.toString());
assertFalse(impl.isCollection());
@ -173,20 +158,17 @@ public class UriResourceImplTest {
}
@Test
public void testUriResourceCountImpl() {
public void uriResourceCountImpl() {
UriResourceCountImpl impl = new UriResourceCountImpl();
assertEquals(UriResourceKind.count, impl.getKind());
assertEquals("$count", impl.toString());
}
@Test
public void testUriResourceEntitySetImpl() {
UriResourceEntitySetImpl impl = new UriResourceEntitySetImpl();
assertEquals(UriResourceKind.entitySet, impl.getKind());
public void uriResourceEntitySetImpl() {
EdmEntitySet entitySet = edm.getEntityContainer().getEntitySet("ESAllPrim");
impl.setEntitSet(entitySet);
UriResourceEntitySetImpl impl = new UriResourceEntitySetImpl(entitySet);
assertEquals(UriResourceKind.entitySet, impl.getKind());
assertEquals("ESAllPrim", impl.toString());
assertEquals(entitySet, impl.getEntitySet());
@ -201,8 +183,8 @@ public class UriResourceImplTest {
}
@Test
public void testUriResourceFunctionImpl() {
UriResourceFunctionImpl impl = new UriResourceFunctionImpl();
public void uriResourceFunctionImpl() {
UriResourceFunctionImpl impl = new UriResourceFunctionImpl(null, null, null);
assertEquals(UriResourceKind.function, impl.getKind());
assertEquals("", impl.toString());
@ -210,39 +192,38 @@ public class UriResourceImplTest {
EdmFunction function = edm.getEntityContainer().getFunctionImport("FINRTInt16")
.getUnboundFunction(Collections.<String> emptyList());
assertNotNull(function);
impl.setFunction(function);
impl = new UriResourceFunctionImpl(null, function, null);
assertEquals(function, impl.getFunction());
assertEquals("UFNRTInt16", impl.toString());
assertEquals(function.getReturnType().getType(), impl.getType());
assertFalse(impl.isParameterListFilled());
assertTrue(impl.getParameters().isEmpty());
// function import
impl = new UriResourceFunctionImpl();
EdmFunctionImport functionImport = edm.getEntityContainer().getFunctionImport("FINRTInt16");
impl.setFunctionImport(functionImport, Collections.<UriParameter> emptyList());
impl = new UriResourceFunctionImpl(functionImport, functionImport.getUnboundFunctions().get(0),
Collections.<UriParameter> emptyList());
assertEquals(functionImport, impl.getFunctionImport());
assertEquals("FINRTInt16", impl.toString());
// function collection
impl = new UriResourceFunctionImpl();
functionImport = edm.getEntityContainer().getFunctionImport("FICRTCollESTwoKeyNavParam");
assertNotNull(function);
UriParameter parameter = new UriParameterImpl().setName("ParameterInt16");
impl.setFunctionImport(functionImport, Collections.singletonList(parameter));
impl = new UriResourceFunctionImpl(functionImport,
functionImport.getUnboundFunction(Collections.singletonList("ParameterInt16")),
Collections.singletonList(parameter));
assertEquals("FICRTCollESTwoKeyNavParam", impl.toString());
impl.setFunction(functionImport.getUnboundFunction(Collections.singletonList("ParameterInt16")));
assertTrue(impl.isCollection());
impl.setKeyPredicates(Collections.<UriParameter> emptyList());
assertFalse(impl.isCollection());
assertFalse(impl.getParameters().isEmpty());
assertEquals(parameter, impl.getParameters().get(0));
assertTrue(impl.isParameterListFilled());
}
@Test
public void testUriResourceImplKeyPred() {
public void uriResourceImplKeyPred() {
final EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
class Mock extends UriResourceWithKeysImpl {
@ -306,7 +287,7 @@ public class UriResourceImplTest {
}
@Test
public void testUriResourceImplTyped() {
public void uriResourceImplTyped() {
final EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
class Mock extends UriResourceTypedImpl {
@ -344,18 +325,15 @@ public class UriResourceImplTest {
}
@Test
public void testUriResourceItImpl() {
UriResourceItImpl impl = new UriResourceItImpl();
assertEquals(UriResourceKind.it, impl.getKind());
public void uriResourceItImpl() {
EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
UriResourceItImpl impl = new UriResourceItImpl(entityType, false);
assertEquals(UriResourceKind.it, impl.getKind());
assertEquals("$it", impl.toString());
impl.setType(entityType);
assertEquals(entityType, impl.getType());
assertFalse(impl.isCollection());
impl.setCollection(true);
impl = new UriResourceItImpl(entityType, true);
assertTrue(impl.isCollection());
impl.setKeyPredicates(Collections.singletonList(
(UriParameter) new UriParameterImpl().setName("ParameterInt16")));
@ -363,15 +341,13 @@ public class UriResourceImplTest {
}
@Test
public void testUriResourceNavigationPropertyImpl() {
UriResourceNavigationPropertyImpl impl = new UriResourceNavigationPropertyImpl();
assertEquals(UriResourceKind.navigationProperty, impl.getKind());
public void uriResourceNavigationPropertyImpl() {
EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
EdmNavigationProperty property = (EdmNavigationProperty) entityType.getProperty("NavPropertyETKeyNavMany");
assertNotNull(property);
impl.setNavigationProperty(property);
UriResourceNavigationPropertyImpl impl = new UriResourceNavigationPropertyImpl(property);
assertEquals(UriResourceKind.navigationProperty, impl.getKind());
assertEquals(property, impl.getProperty());
assertEquals("NavPropertyETKeyNavMany", impl.toString());
@ -384,25 +360,22 @@ public class UriResourceImplTest {
}
@Test
public void testUriResourceRefImpl() {
public void uriResourceRefImpl() {
UriResourceRefImpl impl = new UriResourceRefImpl();
assertEquals(UriResourceKind.ref, impl.getKind());
assertEquals("$ref", impl.toString());
}
@Test
public void testUriResourceRootImpl() {
UriResourceRootImpl impl = new UriResourceRootImpl();
assertEquals(UriResourceKind.root, impl.getKind());
public void uriResourceRootImpl() {
EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
UriResourceRootImpl impl = new UriResourceRootImpl(entityType, false);
assertEquals(UriResourceKind.root, impl.getKind());
assertEquals("$root", impl.toString());
impl.setType(entityType);
assertEquals(entityType, impl.getType());
assertFalse(impl.isCollection());
impl.setCollection(true);
impl = new UriResourceRootImpl(entityType, true);
assertTrue(impl.isCollection());
impl.setKeyPredicates(Collections.singletonList(
(UriParameter) new UriParameterImpl().setName("ParameterInt16")));
@ -410,14 +383,11 @@ public class UriResourceImplTest {
}
@Test
public void testUriResourceSingletonImpl() {
UriResourceSingletonImpl impl = new UriResourceSingletonImpl();
assertEquals(UriResourceKind.singleton, impl.getKind());
public void uriResourceSingletonImpl() {
EdmSingleton singleton = edm.getEntityContainer().getSingleton("SINav");
EdmEntityType entityTypeBaseColl = edm.getEntityType(EntityTypeProvider.nameETBaseTwoKeyNav);
impl.setSingleton(singleton);
UriResourceSingletonImpl impl = new UriResourceSingletonImpl(singleton);
assertEquals(UriResourceKind.singleton, impl.getKind());
assertEquals("SINav", impl.toString());
assertEquals(singleton, impl.getSingleton());
@ -433,41 +403,33 @@ public class UriResourceImplTest {
}
@Test
public void testUriResourceValueImpl() {
public void uriResourceValueImpl() {
UriResourceValueImpl impl = new UriResourceValueImpl();
assertEquals(UriResourceKind.value, impl.getKind());
assertEquals("$value", impl.toString());
}
@Test
public void testUriResourceLambdaVarImpl() {
UriResourceLambdaVarImpl impl = new UriResourceLambdaVarImpl();
assertEquals(UriResourceKind.lambdaVariable, impl.getKind());
public void uriResourceLambdaVarImpl() {
EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
impl.setType(entityType);
impl.setVariableText("A");
UriResourceLambdaVarImpl impl = new UriResourceLambdaVarImpl("A", entityType);
assertEquals(UriResourceKind.lambdaVariable, impl.getKind());
assertEquals("A", impl.toString());
assertEquals(entityType, impl.getType());
assertEquals("A", impl.getVariableName());
assertFalse(impl.isCollection());
impl.setCollection(true);
assertTrue(impl.isCollection());
}
@Test
public void testUriResourceStartingTypeFilterImpl() {
UriResourceStartingTypeFilterImpl impl = new UriResourceStartingTypeFilterImpl();
public void uriResourceStartingTypeFilterImpl() {
EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
impl.setType(entityType);
UriResourceStartingTypeFilterImpl impl = new UriResourceStartingTypeFilterImpl(entityType, false);
assertEquals("olingo.odata.test1.ETTwoKeyNav", impl.toString());
assertEquals(entityType, impl.getType());
assertFalse(impl.isCollection());
impl.setCollection(true);
impl = new UriResourceStartingTypeFilterImpl(entityType, true);
assertTrue(impl.isCollection());
impl.setKeyPredicates(Collections.singletonList(
(UriParameter) new UriParameterImpl().setName("ParameterInt16")));

View File

@ -38,6 +38,7 @@ import org.apache.olingo.server.tecsvc.provider.ContainerProvider;
import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
import org.apache.olingo.server.tecsvc.provider.EntityTypeProvider;
import org.apache.olingo.server.tecsvc.provider.PropertyProvider;
import org.junit.Ignore;
import org.junit.Test;
public class TestUriParserImpl {
@ -561,11 +562,12 @@ public class TestUriParserImpl {
@Test
public void unary() throws Exception {
testFilter.runOnETAllPrim("not PropertyBoolean").isCompr("<not <PropertyBoolean>>");
testFilter.runOnETAllPrim("- PropertyInt16 eq PropertyInt16").isCompr("<<- <PropertyInt16>> eq <PropertyInt16>>");
testFilter.runOnETAllPrim("-PropertyInt16 eq PropertyInt16").isCompr("<<- <PropertyInt16>> eq <PropertyInt16>>");
}
// TODO: Use correct types.
@Test
@Ignore
public void filterComplexMixedPriority() throws Exception {
testFilter.runOnETAllPrim("PropertyInt16 or PropertyInt32 and PropertyInt64")
.isCompr("<<PropertyInt16> or <<PropertyInt32> and <PropertyInt64>>>");
@ -1069,28 +1071,21 @@ public class TestUriParserImpl {
}
@Test
public void testLambda() throws Exception {
testUri.run("ESTwoKeyNav", "$filter=CollPropertyComp/all( l : true )")
.goFilter().is("<CollPropertyComp/<ALL;<true>>>");
public void lambda() throws Exception {
testFilter.runOnETTwoKeyNav("CollPropertyComp/all(l:true)")
.is("<CollPropertyComp/<ALL;<true>>>");
testUri.run("ESTwoKeyNav", "$filter=CollPropertyComp/all( x : x/PropertyInt16 eq 2)")
.goFilter().is("<CollPropertyComp/<ALL;<<x/PropertyInt16> eq <2>>>>");
testFilter.runOnETTwoKeyNav("CollPropertyComp/all(x:x/PropertyInt16 eq 2)")
.is("<CollPropertyComp/<ALL;<<x/PropertyInt16> eq <2>>>>");
testUri.run("ESTwoKeyNav", "$filter=CollPropertyComp/any( l : true )")
.goFilter().is("<CollPropertyComp/<ANY;<true>>>");
testUri.run("ESTwoKeyNav", "$filter=CollPropertyComp/any( )")
.goFilter().is("<CollPropertyComp/<ANY;>>");
testUri.run("ESTwoKeyNav", "$filter=all( l : true )")
.goFilter().is("<<ALL;<true>>>");
testUri.run("ESTwoKeyNav", "$filter=any( l : true )")
.goFilter().is("<<ANY;<true>>>");
testUri.run("ESTwoKeyNav", "$filter=any( )")
.goFilter().is("<<ANY;>>");
testFilter.runOnETTwoKeyNav("CollPropertyComp/any(l:true)")
.is("<CollPropertyComp/<ANY;<true>>>");
testFilter.runOnETTwoKeyNav("CollPropertyComp/any()")
.is("<CollPropertyComp/<ANY;>>");
}
@Test
public void testCustomQueryOption() throws Exception {
public void customQueryOption() throws Exception {
testUri.run("ESTwoKeyNav", "custom")
.isCustomParameter(0, "custom", "");
testUri.run("ESTwoKeyNav", "custom=ABC")
@ -1098,6 +1093,7 @@ public class TestUriParserImpl {
}
@Test
@Ignore("Geo types are not supported yet.")
public void geo() throws Exception {
testFilter.runOnETAllPrim("geo.distance(PropertySByte,PropertySByte)")
.is("<geo.distance(<PropertySByte>,<PropertySByte>)>")

View File

@ -128,7 +128,7 @@ public class ExpressionTest {
// UriResourceImpl
EdmAction action = edm.getUnboundAction(ActionProvider.nameUARTString);
UriInfoResource uriInfo = new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
new UriResourceActionImpl().setAction(action)).asUriInfoResource();
new UriResourceActionImpl(action)).asUriInfoResource();
MemberImpl expression = new MemberImpl(uriInfo, null);
assertEquals(action.getReturnType().getType(), expression.getType());
@ -142,7 +142,7 @@ public class ExpressionTest {
// UriResourceImplTyped check collection = true case
action = edm.getUnboundAction(ActionProvider.nameUARTCollStringTwoParam);
expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource)
.addResourcePart(new UriResourceActionImpl().setAction(action))
.addResourcePart(new UriResourceActionImpl(action))
.asUriInfoResource(),
null);
assertTrue(expression.isCollection());
@ -150,7 +150,7 @@ public class ExpressionTest {
// UriResourceImplTyped with filter
EdmFunction function = edm.getUnboundFunction(FunctionProvider.nameUFCRTETKeyNav, null);
expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
new UriResourceFunctionImpl().setFunction(function).setEntryTypeFilter(entityType))
new UriResourceFunctionImpl(null, function, null).setEntryTypeFilter(entityType))
.asUriInfoResource(),
null);
assertEquals(entityType, expression.getType());
@ -158,7 +158,7 @@ public class ExpressionTest {
// UriResourceImplKeyPred
function = edm.getUnboundFunction(FunctionProvider.nameUFCRTETKeyNav, null);
expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
new UriResourceFunctionImpl().setFunction(function))
new UriResourceFunctionImpl(null, function, null))
.asUriInfoResource(),
null);
assertEquals(function.getReturnType().getType(), expression.getType());
@ -167,7 +167,7 @@ public class ExpressionTest {
EdmEntityType entityBaseType = edm.getEntityType(EntityTypeProvider.nameETBaseTwoKeyNav);
function = edm.getUnboundFunction(FunctionProvider.nameUFCRTCollETTwoKeyNavParam, Arrays.asList("ParameterInt16"));
expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
new UriResourceFunctionImpl().setFunction(function).setEntryTypeFilter(entityBaseType))
new UriResourceFunctionImpl(null, function, null).setEntryTypeFilter(entityBaseType))
.asUriInfoResource(),
null);
assertEquals(entityBaseType, expression.getType());
@ -176,7 +176,7 @@ public class ExpressionTest {
entityBaseType = edm.getEntityType(EntityTypeProvider.nameETBaseTwoKeyNav);
function = edm.getUnboundFunction(FunctionProvider.nameUFCRTCollETTwoKeyNavParam, Arrays.asList("ParameterInt16"));
expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
new UriResourceFunctionImpl().setFunction(function).setCollectionTypeFilter(entityBaseType))
new UriResourceFunctionImpl(null, function, null).setCollectionTypeFilter(entityBaseType))
.asUriInfoResource(),
null);
assertEquals(entityBaseType, expression.getType());