[OLINGO-801] UriParser supports Complex / Entity Parameters.

This commit is contained in:
Christian Holzer 2015-10-15 10:01:55 +02:00
parent f221962f72
commit 3584e1d71d
15 changed files with 353 additions and 90 deletions

View File

@ -29,6 +29,7 @@ STRING : '\'' -> more, pushMode(MODE_STRING) ;
QUOTATION_MARK : '\u0022' -> more, pushMode(MODE_JSON_STRING); //reads up to next unescaped " QUOTATION_MARK : '\u0022' -> more, pushMode(MODE_JSON_STRING); //reads up to next unescaped "
SEARCH_INLINE : '$search' -> pushMode(MODE_SYSTEM_QUERY_SEARCH); // SEARCH_INLINE : '$search' -> pushMode(MODE_SYSTEM_QUERY_SEARCH); //
FRAGMENT : '#' -> pushMode(MODE_FRAGMENT); // FRAGMENT : '#' -> pushMode(MODE_FRAGMENT); //
STRING_JSON : '"' -> more, pushMode(MODE_JSON_STRING); //reads up to next unescaped "
GEOGRAPHY : G E O G R A P H Y SQUOTE -> pushMode(MODE_ODATA_GEO); //TODO make case insensitive GEOGRAPHY : G E O G R A P H Y SQUOTE -> pushMode(MODE_ODATA_GEO); //TODO make case insensitive
GEOMETRY : G E O M E T R Y SQUOTE -> pushMode(MODE_ODATA_GEO); GEOMETRY : G E O M E T R Y SQUOTE -> pushMode(MODE_ODATA_GEO);
@ -364,7 +365,10 @@ mode MODE_JSON_STRING;
// Any """ characters inside a string are escaped with "\". // Any """ characters inside a string are escaped with "\".
//;============================================================================== //;==============================================================================
STRING_IN_JSON : ('\\"' | ~[\u0022] )* '"' -> popMode; STRING_IN_JSON : (ESCAPED_JSON_CHAR | ~["\\])* '"' -> popMode;
fragment ESCAPED_JSON_CHAR : '\\' (["\\/bfnrt] | UNICODE_CHAR);
fragment UNICODE_CHAR : 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT;
fragment HEX_DIGIT : [0-9a-fA-F];
ERROR_CHARACTER_jsm : EOF | .; ERROR_CHARACTER_jsm : EOF | .;
//;============================================================================== //;==============================================================================

View File

@ -205,6 +205,7 @@ commonExpr : OPEN commonExpr CLOSE
| rootExpr #altRoot // $... | rootExpr #altRoot // $...
| AT odataIdentifier #altAlias // @... | AT odataIdentifier #altAlias // @...
| primitiveLiteral #altLiteral // ... | primitiveLiteral #altLiteral // ...
| arrayOrObject #altJson
; ;
unary : (MINUS| NOT) ; unary : (MINUS| NOT) ;
@ -309,11 +310,15 @@ json_value : jsonPrimitiv
| json_array; | json_array;
json_object : BEGIN_OBJECT json_object : BEGIN_OBJECT
STRING_IN_JSON (
WSP? COLON WSP? json_key_value_pair
json_value (COMMA json_key_value_pair)*
)?
END_OBJECT; END_OBJECT;
json_key_value_pair : STRING_IN_JSON
WSP? COLON WSP?
json_value;
//; JSON syntax: adapted to URI restrictions from [RFC4627] //; JSON syntax: adapted to URI restrictions from [RFC4627]
jsonPrimitiv : STRING_IN_JSON jsonPrimitiv : STRING_IN_JSON

View File

@ -25,8 +25,8 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriInfoAll; import org.apache.olingo.server.api.uri.UriInfoAll;
import org.apache.olingo.server.api.uri.UriInfoBatch; import org.apache.olingo.server.api.uri.UriInfoBatch;
@ -36,6 +36,7 @@ import org.apache.olingo.server.api.uri.UriInfoKind;
import org.apache.olingo.server.api.uri.UriInfoMetadata; import org.apache.olingo.server.api.uri.UriInfoMetadata;
import org.apache.olingo.server.api.uri.UriInfoResource; import org.apache.olingo.server.api.uri.UriInfoResource;
import org.apache.olingo.server.api.uri.UriInfoService; import org.apache.olingo.server.api.uri.UriInfoService;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.UriResource; import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.queryoption.CountOption; import org.apache.olingo.server.api.uri.queryoption.CountOption;
import org.apache.olingo.server.api.uri.queryoption.CustomQueryOption; import org.apache.olingo.server.api.uri.queryoption.CustomQueryOption;
@ -63,7 +64,7 @@ public class UriInfoImpl implements UriInfo {
private EdmEntityType entityTypeCast; // for $entity private EdmEntityType entityTypeCast; // for $entity
private List<CustomQueryOptionImpl> customQueryOptions = new ArrayList<CustomQueryOptionImpl>(); private List<CustomQueryOptionImpl> customQueryOptions = new ArrayList<CustomQueryOptionImpl>();
private Map<String, String> aliasToValue = new HashMap<String, String>(); private Map<String, UriParameter> aliasValues = new HashMap<String, UriParameter>();
private Map<SystemQueryOptionKind, SystemQueryOption> systemQueryOptions = private Map<SystemQueryOptionKind, SystemQueryOption> systemQueryOptions =
new HashMap<SystemQueryOptionKind, SystemQueryOption>(); new HashMap<SystemQueryOptionKind, SystemQueryOption>();
@ -138,7 +139,16 @@ public class UriInfoImpl implements UriInfo {
@Override @Override
public String getValueForAlias(final String alias) { public String getValueForAlias(final String alias) {
return aliasToValue.get(alias); final UriParameter parameter = aliasValues.get(alias);
return parameter == null ? null : parameter.getText();
}
public UriParameter getAlias(final String key) {
return aliasValues.get(key);
}
public void addAlias(final String key, UriParameter parameter) {
aliasValues.put(key, parameter);
} }
@Override @Override
@ -235,9 +245,6 @@ public class UriInfoImpl implements UriInfo {
public void addCustomQueryOption(final CustomQueryOptionImpl item) { public void addCustomQueryOption(final CustomQueryOptionImpl item) {
customQueryOptions.add(item); customQueryOptions.add(item);
if (item.getName().startsWith("@")) {
aliasToValue.put(item.getName(), item.getText());
}
} }
/** /**
@ -297,5 +304,4 @@ public class UriInfoImpl implements UriInfo {
public Collection<SystemQueryOption> getSystemQueryOptions() { public Collection<SystemQueryOption> getSystemQueryOptions() {
return Collections.unmodifiableCollection(systemQueryOptions.values()); return Collections.unmodifiableCollection(systemQueryOptions.values());
} }
} }

View File

@ -30,8 +30,8 @@ import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.atn.PredictionMode; import org.antlr.v4.runtime.atn.PredictionMode;
import org.antlr.v4.runtime.misc.ParseCancellationException; import org.antlr.v4.runtime.misc.ParseCancellationException;
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriInfoKind; import org.apache.olingo.server.api.uri.UriInfoKind;
import org.apache.olingo.server.api.uri.UriResource; import org.apache.olingo.server.api.uri.UriResource;
@ -42,6 +42,7 @@ import org.apache.olingo.server.api.uri.UriResourceValue;
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOption; 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.SystemQueryOptionKind;
import org.apache.olingo.server.core.uri.UriInfoImpl; import org.apache.olingo.server.core.uri.UriInfoImpl;
import org.apache.olingo.server.core.uri.UriParameterImpl;
import org.apache.olingo.server.core.uri.antlr.UriLexer; 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;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.AllEOFContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.AllEOFContext;
@ -65,11 +66,14 @@ import org.apache.olingo.server.core.uri.queryoption.SelectOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.SkipOptionImpl; 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.SkipTokenOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.TopOptionImpl; import org.apache.olingo.server.core.uri.queryoption.TopOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.expression.ExpressionImpl;
public class Parser { public class Parser {
private static final String ATOM = "atom"; private static final String ATOM = "atom";
private static final String JSON = "json"; private static final String JSON = "json";
private static final String XML = "xml"; private static final String XML = "xml";
private static final String AT = "@";
private static final String NULL = "null";
int logLevel = 0; int logLevel = 0;
private enum ParserEntryRules { private enum ParserEntryRules {
@ -271,7 +275,26 @@ public class Parser {
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, option.name); UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, option.name);
} }
} else { } else {
CustomQueryOptionImpl customOption = new CustomQueryOptionImpl(); if (option.name.startsWith(AT)) {
final FilterExpressionEOFContext filterExpCtx =
(FilterExpressionEOFContext) parseRule(option.value, ParserEntryRules.FilterExpression);
final ExpressionImpl expression = ((FilterOptionImpl) uriParseTreeVisitor
.visitFilterExpressionEOF(filterExpCtx)).getExpression();
final UriParameterImpl parameter = new UriParameterImpl();
parameter.setAlias(option.name);
parameter.setExpression(expression);
parameter.setText(NULL.equals(option.value) ? null : option.value);
if(context.contextUriInfo.getAlias(option.name) == null) {
context.contextUriInfo.addAlias(option.name, parameter);
} else {
throw new UriParserSyntaxException("Alias already specified! Name: " + option.name,
UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS, option.name);
}
}
final CustomQueryOptionImpl customOption = new CustomQueryOptionImpl();
customOption.setName(option.name); customOption.setName(option.name);
customOption.setText(option.value); customOption.setText(option.value);
context.contextUriInfo.addCustomQueryOption(customOption); context.contextUriInfo.addCustomQueryOption(customOption);

View File

@ -96,6 +96,11 @@ public class UriContext {
public UriInfoImpl contextUriInfo; public UriInfoImpl contextUriInfo;
public boolean contextReadingFunctionParameters; public boolean contextReadingFunctionParameters;
/**
* Set to true if the parser operates on query part.
*/
public boolean contextReadingQueryPart;
public UriContext() { public UriContext() {
contextExpandItemPath = null; contextExpandItemPath = null;

View File

@ -95,6 +95,7 @@ import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltHasContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltMultContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltMultContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltOrContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltOrContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.AnyExprContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.AnyExprContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ArrayOrObjectContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.BatchEOFContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.BatchEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.BinaryLiteralContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.BinaryLiteralContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.BooleanNonCaseLiteralContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.BooleanNonCaseLiteralContext;
@ -116,6 +117,7 @@ import org.apache.olingo.server.core.uri.antlr.UriParserParser.EnumLiteralContex
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandCountOptionContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandCountOptionContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemsContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemsContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemsEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandOptionContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandOptionContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandPathContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandPathContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandPathExtensionContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandPathExtensionContext;
@ -179,6 +181,7 @@ import org.apache.olingo.server.core.uri.antlr.UriParserParser.TotalOffsetMinute
import org.apache.olingo.server.core.uri.antlr.UriParserParser.TotalsecondsMethodCallExprContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.TotalsecondsMethodCallExprContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.TrimMethodCallExprContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.TrimMethodCallExprContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.YearMethodCallExprContext; import org.apache.olingo.server.core.uri.antlr.UriParserParser.YearMethodCallExprContext;
import org.apache.olingo.server.core.uri.parser.UriParserSemanticException.MessageKeys;
import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl; import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.ExpandItemImpl; import org.apache.olingo.server.core.uri.queryoption.ExpandItemImpl;
import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl; import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
@ -361,6 +364,12 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
// check FunctionImport // check FunctionImport
EdmFunctionImport edmFunctionImport = edmEntityContainer.getFunctionImport(odi); EdmFunctionImport edmFunctionImport = edmEntityContainer.getFunctionImport(odi);
if(edmFunctionImport != null && context.contextReadingQueryPart) {
throw wrap(new UriParserSemanticException("Function Imports are not allowed in $filter or $orderby",
UriParserSemanticException.MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED, odi));
}
if (edmFunctionImport != null if (edmFunctionImport != null
&& (parts.isEmpty() || !(parts.get(0) instanceof UriResourcePartTyped) && (parts.isEmpty() || !(parts.get(0) instanceof UriResourcePartTyped)
|| parts.get(0) instanceof UriResourceRoot)) { || parts.get(0) instanceof UriResourceRoot)) {
@ -466,8 +475,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
throw wrap(new UriParserSemanticException("Property '" + odi + "' not found in type '" throw wrap(new UriParserSemanticException("Property '" + odi + "' not found in type '"
+ structType.getFullQualifiedName().getFullQualifiedNameAsString() + "'", + structType.getFullQualifiedName().getFullQualifiedNameAsString() + "'",
ctx.depth() > 2 ? // path evaluation inside an expression or for the resource path? ctx.depth() > 2 ? // path evaluation inside an expression or for the resource path?
UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE : UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE
UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE, : UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE,
structType.getFullQualifiedName().getFullQualifiedNameAsString(), odi)); structType.getFullQualifiedName().getFullQualifiedNameAsString(), odi));
} }
@ -667,7 +676,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
// do a check for bound functions (which requires a parameter list) // do a check for bound functions (which requires a parameter list)
if (ctx.vlNVO.size() == 0) { if (ctx.vlNVO.size() == 0) {
throw wrap(new UriParserSemanticException("Unknown type for type cast " + fullFilterName.toString() throw wrap(new UriParserSemanticException("Unknown type for type cast " + fullFilterName.toString()
+ " not found", UriParserSemanticException.MessageKeys.UNKNOWN_TYPE , fullFilterName.toString())); + " not found", UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, fullFilterName.toString()));
} }
context.contextReadingFunctionParameters = true; context.contextReadingFunctionParameters = true;
@ -718,7 +727,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
* @param vNS namespace or null * @param vNS namespace or null
*/ */
private void ensureNamespaceIsNull(final NamespaceContext vNS) { private void ensureNamespaceIsNull(final NamespaceContext vNS) {
if(vNS != null && context.contextUriInfo.getLastResourcePart() == null) { if (vNS != null && context.contextUriInfo.getLastResourcePart() == null) {
// First resource part and namespace is not null! // First resource part and namespace is not null!
throw wrap(new UriParserSemanticException("Namespace is not allowed for EntitySets, Singeltons, " throw wrap(new UriParserSemanticException("Namespace is not allowed for EntitySets, Singeltons, "
+ " Action Imports and Function Imports. Found " + vNS.getText(), + " Action Imports and Function Imports. Found " + vNS.getText(),
@ -1237,7 +1246,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
levels.setText(ctx.vM.getText()); levels.setText(ctx.vM.getText());
try { try {
expandItem.setSystemQueryOption(levels); expandItem.setSystemQueryOption(levels);
} catch(ODataRuntimeException e) { } catch (ODataRuntimeException e) {
// Thrown if duplicated system query options are detected // Thrown if duplicated system query options are detected
throw wrap(new UriParserSyntaxException("Double system query option!", e, throw wrap(new UriParserSyntaxException("Double system query option!", e,
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage())); UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage()));
@ -1249,7 +1258,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
levels.setValue(Integer.parseInt(text)); levels.setValue(Integer.parseInt(text));
try { try {
expandItem.setSystemQueryOption(levels); expandItem.setSystemQueryOption(levels);
} catch(ODataRuntimeException e) { } catch (ODataRuntimeException e) {
// Thrown if duplicated system query options are detected // Thrown if duplicated system query options are detected
throw wrap(new UriParserSyntaxException("Double system query option!", e, throw wrap(new UriParserSyntaxException("Double system query option!", e,
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage())); UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage()));
@ -1269,7 +1278,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
for (SystemQueryOptionImpl option : list) { for (SystemQueryOptionImpl option : list) {
expandItem.setSystemQueryOption(option); expandItem.setSystemQueryOption(option);
} }
} catch(ODataRuntimeException e) { } catch (ODataRuntimeException e) {
// Thrown if duplicated system query options are detected // Thrown if duplicated system query options are detected
throw wrap(new UriParserSyntaxException("Double system query option!", e, throw wrap(new UriParserSyntaxException("Double system query option!", e,
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage())); UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage()));
@ -1400,14 +1409,22 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
@Override @Override
public Object visitFilter(final FilterContext ctx) { public Object visitFilter(final FilterContext ctx) {
context.contextReadingQueryPart = true;
final FilterOptionImpl result = new FilterOptionImpl().setExpression((ExpressionImpl) ctx.children.get(2)
.accept(this));
context.contextReadingQueryPart = false;
return new FilterOptionImpl().setExpression((ExpressionImpl) ctx.children.get(2).accept(this)); return result;
} }
@Override @Override
public Object visitFilterExpressionEOF(final FilterExpressionEOFContext ctx) { public Object visitFilterExpressionEOF(final FilterExpressionEOFContext ctx) {
context.contextReadingQueryPart = true;
final FilterOptionImpl result = new FilterOptionImpl().setExpression((ExpressionImpl) ctx.children.get(0)
.accept(this));
context.contextReadingQueryPart = false;
return new FilterOptionImpl().setExpression((ExpressionImpl) ctx.children.get(0).accept(this)); return result;
} }
@Override @Override
@ -1711,7 +1728,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
throw wrap(new UriParserSemanticException("Parameters list on untyped resource path segment not allowed", throw wrap(new UriParserSemanticException("Parameters list on untyped resource path segment not allowed",
UriParserSemanticException.MessageKeys.PARAMETERS_LIST_ONLY_FOR_TYPED_PARTS)); UriParserSemanticException.MessageKeys.PARAMETERS_LIST_ONLY_FOR_TYPED_PARTS));
} }
if(last instanceof UriResourceFunction) { if (last instanceof UriResourceFunction) {
final UriResourceFunction uriResourceFunction = (UriResourceFunction) context.contextUriInfo final UriResourceFunction uriResourceFunction = (UriResourceFunction) context.contextUriInfo
.getLastResourcePart(); .getLastResourcePart();
final EdmReturnType returnType = uriResourceFunction.getFunction().getReturnType(); final EdmReturnType returnType = uriResourceFunction.getFunction().getReturnType();
@ -1726,7 +1743,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
final EdmEntityType entityType = (EdmEntityType) uriResourceFunction.getFunction().getReturnType().getType(); final EdmEntityType entityType = (EdmEntityType) uriResourceFunction.getFunction().getReturnType().getType();
final List<String> lastKeyPredicates = entityType.getKeyPredicateNames(); final List<String> lastKeyPredicates = entityType.getKeyPredicateNames();
if(lastKeyPredicates.size() == list.size()) { if (lastKeyPredicates.size() == list.size()) {
return list; return list;
} else { } else {
throw wrap(new UriParserSemanticException("Wrong number of key properties.", throw wrap(new UriParserSemanticException("Wrong number of key properties.",
@ -1825,8 +1842,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
@Override @Override
public Object visitNaninfinityLiteral(final NaninfinityLiteralContext ctx) { public Object visitNaninfinityLiteral(final NaninfinityLiteralContext ctx) {
return new LiteralImpl().setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)). return new LiteralImpl().setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)).setText(ctx
setText(ctx.getText()); .getText());
} }
@Override @Override
@ -1863,6 +1880,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
@Override @Override
public Object visitOrderByEOF(final OrderByEOFContext ctx) { public Object visitOrderByEOF(final OrderByEOFContext ctx) {
context.contextReadingQueryPart = true;
OrderByOptionImpl orderBy = new OrderByOptionImpl(); OrderByOptionImpl orderBy = new OrderByOptionImpl();
@ -1871,6 +1889,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
orderBy.addOrder(oItem); orderBy.addOrder(oItem);
} }
context.contextReadingFunctionParameters = false;
return orderBy; return orderBy;
} }
@ -1955,7 +1974,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
return child1.accept(this); return child1.accept(this);
} }
// TODO Implement geography types and set the proper type // TODO Implement geography types and set a proper type
return new LiteralImpl().setText(ctx.getText()); return new LiteralImpl().setText(ctx.getText());
} }
@ -1974,8 +1993,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
@Override @Override
public Object visitDecimalLiteral(final DecimalLiteralContext ctx) { public Object visitDecimalLiteral(final DecimalLiteralContext ctx) {
final EdmType type = EdmPrimitiveTypeFactory.getInstance( final EdmType type = EdmPrimitiveTypeFactory.getInstance(
ctx.getText().contains("e") || ctx.getText().contains("E") ? ctx.getText().contains("e") || ctx.getText().contains("E") ? EdmPrimitiveTypeKind.Double
EdmPrimitiveTypeKind.Double : EdmPrimitiveTypeKind.Decimal); : EdmPrimitiveTypeKind.Decimal);
return new LiteralImpl().setText(ctx.getText()).setType(type); return new LiteralImpl().setText(ctx.getText()).setType(type);
} }
@ -1999,7 +2018,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
} }
return new LiteralImpl().setText(ctx.getText()).setType(type); return new LiteralImpl().setText(ctx.getText()).setType(type);
} catch( NumberFormatException e) { } catch (NumberFormatException e) {
return new LiteralImpl().setText(ctx.getText()) return new LiteralImpl().setText(ctx.getText())
.setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)); .setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal));
} }
@ -2124,13 +2143,17 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
@Override @Override
public Object visitSelectEOF(final SelectEOFContext ctx) { public Object visitSelectEOF(final SelectEOFContext ctx) {
context.contextReadingQueryPart = true;
List<SelectItemImpl> selectItems = new ArrayList<SelectItemImpl>(); List<SelectItemImpl> selectItems = new ArrayList<SelectItemImpl>();
for (SelectItemContext si : ctx.vlSI) { for (SelectItemContext si : ctx.vlSI) {
selectItems.add((SelectItemImpl) si.accept(this)); selectItems.add((SelectItemImpl) si.accept(this));
} }
return new SelectOptionImpl().setSelectItems(selectItems).setText(ctx.getText()); final QueryOptionImpl result = new SelectOptionImpl().setSelectItems(selectItems).setText(ctx.getText());
context.contextReadingQueryPart = false;
return result;
} }
@Override @Override
@ -2498,4 +2521,23 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
throw wrap(new UriParserSemanticException("System query option '$search' not implemented!", throw wrap(new UriParserSemanticException("System query option '$search' not implemented!",
UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, "System query option '$search")); UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, "System query option '$search"));
} }
@Override
public Object visitArrayOrObject(final ArrayOrObjectContext ctx) {
if (!context.contextReadingQueryPart) {
throw wrap(new UriParserSemanticException("Complex parameter are not allowed in resource path",
MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH, ctx.getText()));
}
return new LiteralImpl().setText(ctx.getText()).setType(null);
}
@Override
public Object visitExpandItemsEOF(ExpandItemsEOFContext ctx) {
context.contextReadingQueryPart = true;
final Object result = super.visitExpandItemsEOF(ctx);
context.contextReadingQueryPart = false;
return result;
}
} }

View File

@ -79,7 +79,11 @@ public class UriParserSemanticException extends UriParserException {
/** parameter: not implemented part */ /** parameter: not implemented part */
NOT_IMPLEMENTED, NOT_IMPLEMENTED,
/** parameter: namespace **/ /** parameter: namespace **/
NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT; NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT,
/** parameter: complex parameter value */
COMPLEX_PARAMETER_IN_RESOURCE_PATH,
/** parameter: function import name */
FUNCTION_IMPORT_NOT_ALLOWED;
@Override @Override
public String getKey() { public String getKey() {

View File

@ -35,7 +35,9 @@ public class UriParserSyntaxException extends UriParserException {
/** parameter: $format option value */ /** parameter: $format option value */
WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT, WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT,
SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE, SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE,
SYNTAX; SYNTAX,
/** parameter: alias name */
DUPLICATED_ALIAS;
@Override @Override
public String getKey() { public String getKey() {

View File

@ -37,6 +37,8 @@ public class UriValidationException extends ODataLibraryException {
UNSUPPORTED_ACTION_RETURN_TYPE, UNSUPPORTED_ACTION_RETURN_TYPE,
/** parameter: unsupported http method */ /** parameter: unsupported http method */
UNSUPPORTED_HTTP_METHOD, UNSUPPORTED_HTTP_METHOD,
/** parameter: unsupported parameter name */
UNSUPPORTED_PARAMETER,
/** parameter: system query option */ /** parameter: system query option */
SYSTEM_QUERY_OPTION_NOT_ALLOWED, SYSTEM_QUERY_OPTION_NOT_ALLOWED,
/** parameters: system query option, http method */ /** parameters: system query option, http method */
@ -54,7 +56,10 @@ public class UriValidationException extends ODataLibraryException {
/** parameter: unallowed kind before $count */ /** parameter: unallowed kind before $count */
UNALLOWED_KIND_BEFORE_COUNT, UNALLOWED_KIND_BEFORE_COUNT,
/** parameter: unallowed resource path */ /** parameter: unallowed resource path */
UNALLOWED_RESOURCE_PATH; UNALLOWED_RESOURCE_PATH,
/** parameter: missing parameter name */
MISSING_PARAMETER;
@Override @Override
public String getKey() { public String getKey() {

View File

@ -139,6 +139,7 @@ public class UriValidator {
validateForHttpMethod(uriInfo, httpMethod); validateForHttpMethod(uriInfo, httpMethod);
} }
validateQueryOptions(uriInfo); validateQueryOptions(uriInfo);
validateParameters(uriInfo);
validateKeyPredicates(uriInfo); validateKeyPredicates(uriInfo);
validatePropertyOperations(uriInfo, httpMethod); validatePropertyOperations(uriInfo, httpMethod);
} }
@ -556,6 +557,58 @@ public class UriValidator {
return UriResourceKind.action == uriResourceParts.get(uriResourceParts.size() - 1).getKind(); return UriResourceKind.action == uriResourceParts.get(uriResourceParts.size() - 1).getKind();
} }
private void validateParameters(final UriInfo uriInfo) throws UriValidationException {
for (UriResource pathSegment : uriInfo.getUriResourceParts()) {
final boolean isFunction = pathSegment.getKind() == UriResourceKind.function;
if(isFunction) {
final UriResourceFunction functionPathSegement = (UriResourceFunction) pathSegment;
final EdmFunction edmFuntion = functionPathSegement.getFunction();
final Map<String, UriParameter> parameters = new HashMap<String, UriParameter>();
for(final UriParameter parameter : functionPathSegement.getParameters()) {
parameters.put(parameter.getName(), parameter);
}
boolean firstParameter = true;
for(final String parameterName : edmFuntion.getParameterNames()) {
final UriParameter parameter = parameters.get(parameterName);
final boolean isNullable = edmFuntion.getParameter(parameterName).isNullable();
if(parameter != null) {
/** No alias, value explicit null */
if(parameter.getText() == null
&& parameter.getAlias() == null && !isNullable) {
throw new UriValidationException("Missing non nullable parameter " + parameterName,
UriValidationException.MessageKeys.MISSING_PARAMETER, parameterName);
} else if(parameter.getText() == null && parameter.getAlias() != null) {
final String valueForAlias = uriInfo.getValueForAlias(parameter.getAlias());
/** Alias value is missing or explicit null **/
if(valueForAlias == null && !isNullable) {
throw new UriValidationException("Missing non nullable parameter " + parameterName,
UriValidationException.MessageKeys.MISSING_PARAMETER, parameterName);
}
}
parameters.remove(parameterName);
} else if(!isNullable && !(firstParameter && edmFuntion.isBound())) {
// The first parameter of bound functions is implicit provided by the preceding path segment
throw new UriValidationException("Missing non nullable parameter " + parameterName,
UriValidationException.MessageKeys.MISSING_PARAMETER, parameterName);
}
firstParameter = false;
}
if(!parameters.isEmpty()) {
final String parameterName = parameters.keySet().iterator().next();
throw new UriValidationException("Unsupported parameter " + parameterName,
UriValidationException.MessageKeys.UNSUPPORTED_PARAMETER, parameterName);
}
}
}
}
private void validateKeyPredicates(final UriInfo uriInfo) throws UriValidationException { private void validateKeyPredicates(final UriInfo uriInfo) throws UriValidationException {
for (UriResource pathSegment : uriInfo.getUriResourceParts()) { for (UriResource pathSegment : uriInfo.getUriResourceParts()) {
final boolean isEntitySet = pathSegment.getKind() == UriResourceKind.entitySet; final boolean isEntitySet = pathSegment.getKind() == UriResourceKind.entitySet;

View File

@ -35,6 +35,7 @@ UriParserSyntaxException.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION=The system query op
UriParserSyntaxException.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT=The system query option '$format' must be either 'json', 'xml', 'atom', or a valid content type; the value '%1$s' is neither. UriParserSyntaxException.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT=The system query option '$format' must be either 'json', 'xml', 'atom', or a valid content type; the value '%1$s' is neither.
UriParserSyntaxException.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE=The system query option '$levels' is not allowed here. UriParserSyntaxException.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE=The system query option '$levels' is not allowed here.
UriParserSyntaxException.SYNTAX=The URI is malformed. UriParserSyntaxException.SYNTAX=The URI is malformed.
UriParserSyntaxException.DUPLICATED_ALIAS=Duplicated alias. An alias '%1$s' was already specified!.
UriParserSemanticException.FUNCTION_NOT_FOUND=The function import '%1$s' has no function with parameters '%2$s'. UriParserSemanticException.FUNCTION_NOT_FOUND=The function import '%1$s' has no function with parameters '%2$s'.
UriParserSemanticException.RESOURCE_PART_ONLY_FOR_TYPED_PARTS='%1$s' is only allowed for typed parts. UriParserSemanticException.RESOURCE_PART_ONLY_FOR_TYPED_PARTS='%1$s' is only allowed for typed parts.
@ -68,6 +69,8 @@ UriParserSemanticException.PREVIOUS_PART_TYPED=The previous part is typed.
UriParserSemanticException.RESOURCE_NOT_FOUND=Cannot find EntitySet, Singleton, ActionImport or FunctionImport with name '%1$s'. UriParserSemanticException.RESOURCE_NOT_FOUND=Cannot find EntitySet, Singleton, ActionImport or FunctionImport with name '%1$s'.
UriParserSemanticException.NOT_IMPLEMENTED=%1$s is not implemented! UriParserSemanticException.NOT_IMPLEMENTED=%1$s is not implemented!
UriParserSemanticException.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT=Namespace is not allowed for Entity Sets, Singeltons, Action Imports and Function Imports. Found '%1$s'. UriParserSemanticException.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT=Namespace is not allowed for Entity Sets, Singeltons, Action Imports and Function Imports. Found '%1$s'.
UriParserSemanticException.COMPLEX_PARAMETER_IN_RESOURCE_PATH=Complex parameters must not appear in resource path segments. Found: '%1$s'.
UriParserSemanticException.FUNCTION_IMPORT_NOT_ALLOWED=Function Imports are not allowed in $filter or $orderby. Found: '%1$s'.
UriValidationException.UNSUPPORTED_QUERY_OPTION=The query option '%1$s' is not supported. UriValidationException.UNSUPPORTED_QUERY_OPTION=The query option '%1$s' is not supported.
UriValidationException.UNSUPPORTED_URI_KIND=The URI kind '%1$s' is not supported. UriValidationException.UNSUPPORTED_URI_KIND=The URI kind '%1$s' is not supported.
@ -75,6 +78,7 @@ UriValidationException.UNSUPPORTED_URI_RESOURCE_KIND=The URI resource kind '%1$s
UriValidationException.UNSUPPORTED_FUNCTION_RETURN_TYPE=The function return type '%1$s' is not supported. UriValidationException.UNSUPPORTED_FUNCTION_RETURN_TYPE=The function return type '%1$s' is not supported.
UriValidationException.UNSUPPORTED_ACTION_RETURN_TYPE=The action return type '%1$s' is not supported. UriValidationException.UNSUPPORTED_ACTION_RETURN_TYPE=The action return type '%1$s' is not supported.
UriValidationException.UNSUPPORTED_HTTP_METHOD=The HTTP method '%1$s' is not supported. UriValidationException.UNSUPPORTED_HTTP_METHOD=The HTTP method '%1$s' is not supported.
UriValidationException.UNSUPPORTED_PARAMETER=The parameter '%1$s' is not supported.
UriValidationException.SYSTEM_QUERY_OPTION_NOT_ALLOWED=The system query option '%1$s' is not allowed. UriValidationException.SYSTEM_QUERY_OPTION_NOT_ALLOWED=The system query option '%1$s' is not allowed.
UriValidationException.SYSTEM_QUERY_OPTION_NOT_ALLOWED_FOR_HTTP_METHOD=The system query option '%1$s' is not allowed for HTTP method '%2$s'. UriValidationException.SYSTEM_QUERY_OPTION_NOT_ALLOWED_FOR_HTTP_METHOD=The system query option '%1$s' is not allowed for HTTP method '%2$s'.
UriValidationException.INVALID_KEY_PROPERTY=The key property '%1$s' is invalid. UriValidationException.INVALID_KEY_PROPERTY=The key property '%1$s' is invalid.
@ -84,6 +88,7 @@ UriValidationException.SECOND_LAST_SEGMENT_NOT_TYPED=The second last segment '%1
UriValidationException.UNALLOWED_KIND_BEFORE_VALUE=The kind '%1$s' is not allowed before '$value'. UriValidationException.UNALLOWED_KIND_BEFORE_VALUE=The kind '%1$s' is not allowed before '$value'.
UriValidationException.UNALLOWED_KIND_BEFORE_COUNT=The kind '%1$s' is not allowed before '$count'. UriValidationException.UNALLOWED_KIND_BEFORE_COUNT=The kind '%1$s' is not allowed before '$count'.
UriValidationException.UNALLOWED_RESOURCE_PATH=The resource part '%1$s' is not allowed. UriValidationException.UNALLOWED_RESOURCE_PATH=The resource part '%1$s' is not allowed.
UriValidationException.MISSING_PARAMETER=Missing mandatory parameter '%1$s'.
ContentNegotiatorException.UNSUPPORTED_ACCEPT_TYPES=The content-type range '%1$s' is not supported as value of the Accept header. ContentNegotiatorException.UNSUPPORTED_ACCEPT_TYPES=The content-type range '%1$s' is not supported as value of the Accept header.
ContentNegotiatorException.UNSUPPORTED_CONTENT_TYPE=The content type '%1$s' is not supported. ContentNegotiatorException.UNSUPPORTED_CONTENT_TYPE=The content type '%1$s' is not supported.

View File

@ -2036,7 +2036,8 @@ public class TestFullResourcePath {
testUri.run("FICRTCollESTwoKeyNavParam(ParameterInt16=@parameterAlias)", "@parameterAlias=1"); testUri.run("FICRTCollESTwoKeyNavParam(ParameterInt16=@parameterAlias)", "@parameterAlias=1");
testUri.run("FICRTCollESTwoKeyNavParam(ParameterInt16=@parameterAlias)/$count", "@parameterAlias=1"); testUri.run("FICRTCollESTwoKeyNavParam(ParameterInt16=@parameterAlias)/$count", "@parameterAlias=1");
testUri.run("FICRTCollESTwoKeyNavParam(ParameterInt16=@invalidAlias)", "@validAlias=1"); testUri.runEx("FICRTCollESTwoKeyNavParam(ParameterInt16=@invalidAlias)", "@validAlias=1")
.isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
} }
@Test @Test
@ -5659,6 +5660,93 @@ public class TestFullResourcePath {
.right().isLiteral("" + Long.MAX_VALUE).isLiteralType(EdmInt64.getInstance()); .right().isLiteral("" + Long.MAX_VALUE).isLiteralType(EdmInt64.getInstance());
} }
@Test
public void parameterAliasLiteralValidation() throws Exception {
testUri.run("ESAllPrim(PropertyInt16=@p1)", "@p1=1");
testUri.run("ESAllPrim(PropertyInt16=@p1)", "@p1=-2");
testUri.runEx("ESAllPrim(PropertyInt16=@p1)", "@p1='ewe'")
.isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
testUri.runEx("ESAllPrim(PropertyInt16=@p1)", "@p1='ewe")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
}
@Test
public void functionsWithComplexParameters() throws Exception {
testUri.run("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
+ "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"}")
.goPath()
.at(0).isEntitySet("ESTwoKeyNav")
.at(1).isFunction("BFCESTwoKeyNavRTStringParam").isParameterAlias(0, "ParameterComp", "@p1")
.isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"ProperyString\":\"1\"}");
// Test JSON String lexer rule =\"3,Int16=abc},\\\nabc&test%test\b\f\r\t\u0022}
final String stringValueEncoded = "=\\\"3,Int16=abc},\\\\\\nabc%26test%25test\\b\\f\\r\\t\\u0022}";
final String stringValueDecoded = "=\\\"3,Int16=abc},\\\\\\nabc&test%test\\b\\f\\r\\t\\u0022}";
testUri.run("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
+ "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"ProperyString\":\"" + stringValueEncoded + "\"}")
.goPath()
.at(0).isEntitySet("ESTwoKeyNav")
.at(1).isFunction("BFCESTwoKeyNavRTStringParam").isParameterAlias(0, "ParameterComp", "@p1")
.isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"ProperyString\":\"" + stringValueDecoded + "\"}");
testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
+ "(ParameterComp={\"PropertyString\":\"Test\",\"PropertyInt16\":1}) eq 'Test'")
.goFilter().left().is("<<BFCESTwoKeyNavRTStringParam> eq <'Test'>>")
.isParameterText(0, "{\"PropertyString\":\"Test\",\"PropertyInt16\":1}");
testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
+ "(ParameterComp={\"PropertyString\":\"" + stringValueEncoded + "\",\"PropertyInt16\":1}) eq 'Test'")
.goFilter().left().is("<<BFCESTwoKeyNavRTStringParam> eq <'Test'>>")
.isParameterText(0, "{\"PropertyString\":\"=\\\"3,Int16=abc},\\\\\\nabc&test%test\\b\\f\\r\\t\\u0022}\","
+ "\"PropertyInt16\":1}");
testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"}");
testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
+ "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"ProperyString\":'1'}")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
+ "(ParameterComp={\"PropertyInt16\":1,\"PropertyString\":\"Test\"})")
.isExSemantic(UriParserSemanticException.MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH);
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=null)")
.isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)")
.isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test=null")
.isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
testUri.run("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test='null'");
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test, UnknownParam=1)", "@test='null'")
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND);
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test='null'");
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test=null");
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)");
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=null)");
testUri.runEx("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test=null&@test='1'")
.isExSyntax(UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS);
testUri.runEx("ESAllPrim", "$filter=FINRTInt16() eq 0")
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED);
}
@Test
@Ignore("Key predicates in filter/orderby expression are not validated currently")
public void testKeyPredicatesInExpressions() throws Exception {
testUri.run("ESTwoKeyNav", "$filter=NavPropertyETTwoKeyNavMany(PropertyString='1',PropertyInt16=1)"
+ "/PropertyInt16 eq 1");
testUri.runEx("ESTwoKeyNav", "$filter=NavPropertyETTwoKeyNavMany(Prop='22',P=2)/PropertyInt16 eq 0")
.isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
}
public static String encode(final String decoded) throws UnsupportedEncodingException { public static String encode(final String decoded) throws UnsupportedEncodingException {
return Encoder.encode(decoded); return Encoder.encode(decoded);
} }

View File

@ -1061,7 +1061,7 @@ public class TestUriParserImpl {
@Test @Test
public void testAlias() throws Exception { public void testAlias() throws Exception {
testUri.run("ESAllPrim", "$filter=PropertyInt16 eq @p1&@p1=1)") testUri.run("ESAllPrim", "$filter=PropertyInt16 eq @p1&@p1=1")
.goFilter().is("<<PropertyInt16> eq <@p1>>"); .goFilter().is("<<PropertyInt16> eq <@p1>>");
} }

View File

@ -27,6 +27,7 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.edm.provider.CsdlComplexType; import org.apache.olingo.commons.api.edm.provider.CsdlComplexType;
import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet; import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityType; import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
import org.apache.olingo.commons.api.edm.provider.CsdlFunctionImport;
import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty; import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty;
import org.apache.olingo.commons.api.edm.provider.CsdlProperty; import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef; import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef;
@ -116,4 +117,12 @@ public class EdmTechTestProvider extends EdmTechProvider {
return super.getEntityType(entityTypeName); return super.getEntityType(entityTypeName);
} }
@Override
public CsdlFunctionImport getFunctionImport(FullQualifiedName entityContainer, String functionImportName)
throws ODataException {
return super.getFunctionImport(entityContainer, functionImportName);
}
} }

View File

@ -31,12 +31,14 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriInfoKind; import org.apache.olingo.server.api.uri.UriInfoKind;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind; import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression; import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException; import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
import org.apache.olingo.server.api.uri.queryoption.expression.Member; import org.apache.olingo.server.api.uri.queryoption.expression.Member;
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind; import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
import org.apache.olingo.server.core.uri.UriInfoImpl; import org.apache.olingo.server.core.uri.UriInfoImpl;
import org.apache.olingo.server.core.uri.UriResourceFunctionImpl;
import org.apache.olingo.server.core.uri.parser.Parser; import org.apache.olingo.server.core.uri.parser.Parser;
import org.apache.olingo.server.core.uri.parser.UriParserException; import org.apache.olingo.server.core.uri.parser.UriParserException;
import org.apache.olingo.server.core.uri.parser.UriParserSemanticException; import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
@ -403,15 +405,25 @@ public class FilterValidator implements TestValidator {
public FilterValidator isParameterText(final int parameterIndex, final String parameterText) public FilterValidator isParameterText(final int parameterIndex, final String parameterText)
throws ExpressionVisitException, ODataApplicationException { throws ExpressionVisitException, ODataApplicationException {
if (!(curExpression instanceof MethodImpl)) { if (curExpression instanceof MethodImpl) {
fail("Current expression is not a method");
}
MethodImpl methodCall = (MethodImpl) curExpression; MethodImpl methodCall = (MethodImpl) curExpression;
Expression parameter = methodCall.getParameters().get(parameterIndex); Expression parameter = methodCall.getParameters().get(parameterIndex);
String actualParameterText = FilterTreeToText.Serialize(parameter); String actualParameterText = FilterTreeToText.Serialize(parameter);
assertEquals(parameterText, actualParameterText); assertEquals(parameterText, actualParameterText);
} else if (curExpression instanceof MemberImpl) {
final MemberImpl member = (MemberImpl) curExpression;
final List<UriResource> uriResourceParts = member.getResourcePath().getUriResourceParts();
if (!uriResourceParts.isEmpty() && uriResourceParts.get(0) instanceof UriResourceFunctionImpl) {
assertEquals(parameterText, ((UriResourceFunctionImpl) uriResourceParts.get(0)).getParameters()
.get(parameterIndex).getText());
} else {
fail("Current expression is not a method or function");
}
} else {
fail("Current expression is not a method or function");
}
return this; return this;
} }