[OLINGO-801] UriParser supports Complex / Entity Parameters.
This commit is contained in:
parent
f221962f72
commit
3584e1d71d
|
@ -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 | .;
|
||||||
|
|
||||||
//;==============================================================================
|
//;==============================================================================
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue