You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2016/02/13 07:33:59 UTC
[05/22] olingo-odata4 git commit: [OLINGO-834] better alias support
in URI parser
[OLINGO-834] better alias support in URI parser
Signed-off-by: Christian Amend <ch...@sap.com>
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/110c7b0e
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/110c7b0e
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/110c7b0e
Branch: refs/heads/OLINGO-832_StreamSerializerPoC
Commit: 110c7b0e5afa1f9f717d95ca48bd5c695821db06
Parents: b317b90
Author: Klaus Straubinger <kl...@sap.com>
Authored: Thu Feb 4 12:24:38 2016 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Thu Feb 4 12:38:10 2016 +0100
----------------------------------------------------------------------
.../uri/queryoption/SystemQueryOptionKind.java | 22 +-
.../apache/olingo/server/core/ODataHandler.java | 4 +-
.../server/core/ODataHttpHandlerImpl.java | 19 +-
.../olingo/server/core/uri/UriInfoImpl.java | 37 +-
.../server/core/uri/parser/ExpandParser.java | 30 +-
.../core/uri/parser/ExpressionParser.java | 85 ++-
.../server/core/uri/parser/FilterParser.java | 6 +-
.../server/core/uri/parser/OrderByParser.java | 6 +-
.../olingo/server/core/uri/parser/Parser.java | 354 +++++++------
.../server/core/uri/parser/ParserHelper.java | 168 ++++--
.../core/uri/parser/ResourcePathParser.java | 38 +-
.../server/core/uri/parser/SelectParser.java | 12 +-
.../server/core/uri/parser/UriTokenizer.java | 12 +-
.../uri/queryoption/expression/AliasImpl.java | 9 +-
.../uri/validator/UriValidationException.java | 4 +-
.../server/core/uri/validator/UriValidator.java | 513 +++++--------------
.../server-core-exceptions-i18n.properties | 1 +
.../olingo/server/core/uri/UriInfoImplTest.java | 50 +-
.../core/uri/parser/ExpressionParserTest.java | 2 +-
.../core/uri/parser/UriTokenizerTest.java | 3 +
.../olingo/server/tecsvc/data/DataProvider.java | 12 +-
.../SystemQueryOptionsRuntimeException.java | 3 +-
.../tecsvc/provider/ContainerProvider.java | 6 +-
.../core/uri/parser/TestFullResourcePath.java | 112 ++--
.../core/uri/queryoption/QueryOptionTest.java | 4 +-
.../queryoption/expression/ExpressionTest.java | 6 +-
.../core/uri/testutil/FilterValidator.java | 51 +-
.../core/uri/validator/UriValidatorTest.java | 68 +--
28 files changed, 797 insertions(+), 840 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/110c7b0e/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/SystemQueryOptionKind.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/SystemQueryOptionKind.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/SystemQueryOptionKind.java
index f0c907b..d5d60a1 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/SystemQueryOptionKind.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/SystemQueryOptionKind.java
@@ -18,10 +18,10 @@
*/
package org.apache.olingo.server.api.uri.queryoption;
+
/**
* Defines the supported system query options.
*/
-
public enum SystemQueryOptionKind {
/**
@@ -84,12 +84,30 @@ public enum SystemQueryOptionKind {
*/
LEVELS("$levels");
- private String syntax;
+ private final String syntax;
SystemQueryOptionKind(final String syntax) {
this.syntax = syntax;
}
+ /**
+ * Converts the URI syntax to an enumeration value.
+ * @param option option in the syntax used in the URI
+ * @return system query option kind representing the given option
+ * (or <code>null</code> if the option does not represent a system query option)
+ */
+ public static SystemQueryOptionKind get(final String option) {
+ for (final SystemQueryOptionKind kind : values()) {
+ if (kind.syntax.equals(option)) {
+ return kind;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @return URI syntax for this system query option
+ */
@Override
public String toString() {
return syntax;
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/110c7b0e/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
index 96b419c..3baaac7 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
@@ -160,6 +160,7 @@ public class ODataHandler {
public void handleException(final ODataRequest request, final ODataResponse response,
final ODataServerError serverError, final Exception exception) {
+ final int measurementHandle = debugger.startRuntimeMeasurement("ODataHandler", "handleException");
lastThrownException = exception;
ErrorProcessor exceptionProcessor;
try {
@@ -176,8 +177,9 @@ public class ODataHandler {
} catch (final ContentNegotiatorException e) {
requestedContentType = ContentType.JSON;
}
- final int measurementHandle = debugger.startRuntimeMeasurement("ErrorProcessor", "processError");
+ final int measurementError = debugger.startRuntimeMeasurement("ErrorProcessor", "processError");
exceptionProcessor.processError(request, response, serverError, requestedContentType);
+ debugger.stopRuntimeMeasurement(measurementError);
debugger.stopRuntimeMeasurement(measurementHandle);
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/110c7b0e/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
index 55c1194..61581c0 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
@@ -24,7 +24,7 @@ import java.nio.channels.Channel;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
-import java.util.ArrayList;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
@@ -191,8 +191,12 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
odRequest.setBody(httpRequest.getInputStream());
odRequest.setProtocol(httpRequest.getProtocol());
odRequest.setMethod(extractMethod(httpRequest));
+ int innerHandle = debugger.startRuntimeMeasurement("ODataHttpHandlerImpl", "copyHeaders");
copyHeaders(odRequest, httpRequest);
+ debugger.stopRuntimeMeasurement(innerHandle);
+ innerHandle = debugger.startRuntimeMeasurement("ODataHttpHandlerImpl", "fillUriInformation");
fillUriInformation(odRequest, httpRequest, split);
+ debugger.stopRuntimeMeasurement(innerHandle);
return odRequest;
} catch (final IOException e) {
@@ -273,14 +277,11 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
odRequest.setRawServiceResolutionUri(rawServiceResolutionUri);
}
- static void copyHeaders(final ODataRequest odRequest, final HttpServletRequest req) {
- for (Enumeration<?> headerNames = req.getHeaderNames(); headerNames.hasMoreElements();) {
- String headerName = (String) headerNames.nextElement();
- List<String> headerValues = new ArrayList<String>();
- for (Enumeration<?> headers = req.getHeaders(headerName); headers.hasMoreElements();) {
- String value = (String) headers.nextElement();
- headerValues.add(value);
- }
+ static void copyHeaders(ODataRequest odRequest, final HttpServletRequest req) {
+ for (final Enumeration<?> headerNames = req.getHeaderNames(); headerNames.hasMoreElements();) {
+ final String headerName = (String) headerNames.nextElement();
+ @SuppressWarnings("unchecked") // getHeaders() says it returns an Enumeration of String.
+ final List<String> headerValues = Collections.list(req.getHeaders(headerName));
odRequest.addHeader(headerName, headerValues);
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/110c7b0e/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriInfoImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriInfoImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriInfoImpl.java
index e6fe057..7183bde 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriInfoImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriInfoImpl.java
@@ -20,6 +20,7 @@ package org.apache.olingo.server.core.uri;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -64,7 +65,7 @@ public class UriInfoImpl implements UriInfo {
private List<UriResource> pathParts = new ArrayList<UriResource>();
private Map<SystemQueryOptionKind, SystemQueryOption> systemQueryOptions =
- new HashMap<SystemQueryOptionKind, SystemQueryOption>();
+ new EnumMap<SystemQueryOptionKind, SystemQueryOption>(SystemQueryOptionKind.class);
private Map<String, AliasQueryOption> aliases = new HashMap<String, AliasQueryOption>();
private List<CustomQueryOption> customQueryOptions = new ArrayList<CustomQueryOption>();
@@ -155,15 +156,13 @@ public class UriInfoImpl implements UriInfo {
return Collections.unmodifiableList(pathParts);
}
- public UriInfoImpl setQueryOptions(final List<QueryOption> list) {
- for (final QueryOption item : list) {
- if (item instanceof SystemQueryOption) {
- setSystemQueryOption((SystemQueryOption) item);
- } else if (item instanceof AliasQueryOption) {
- addAlias((AliasQueryOption) item);
- } else if (item instanceof CustomQueryOption) {
- addCustomQueryOption((CustomQueryOption) item);
- }
+ public UriInfoImpl setQueryOption(final QueryOption option) {
+ if (option instanceof SystemQueryOption) {
+ setSystemQueryOption((SystemQueryOption) option);
+ } else if (option instanceof AliasQueryOption) {
+ addAlias((AliasQueryOption) option);
+ } else if (option instanceof CustomQueryOption) {
+ addCustomQueryOption((CustomQueryOption) option);
}
return this;
}
@@ -263,18 +262,22 @@ public class UriInfoImpl implements UriInfo {
}
public UriInfoImpl addAlias(final AliasQueryOption alias) {
- aliases.put(alias.getName(), alias);
+ if (aliases.containsKey(alias.getName())) {
+ throw new ODataRuntimeException("Alias " + alias.getName() + " is already there.");
+ } else {
+ aliases.put(alias.getName(), alias);
+ }
return this;
}
@Override
public String getValueForAlias(final String alias) {
- final AliasQueryOption aliasQueryOption = getAlias(alias);
+ final AliasQueryOption aliasQueryOption = aliases.get(alias);
return aliasQueryOption == null ? null : aliasQueryOption.getText();
}
- public AliasQueryOption getAlias(final String key) {
- return aliases.get(key);
+ public Map<String, AliasQueryOption> getAliasMap() {
+ return Collections.unmodifiableMap(aliases);
}
@Override
@@ -282,8 +285,10 @@ public class UriInfoImpl implements UriInfo {
return Collections.unmodifiableList(new ArrayList<AliasQueryOption>(aliases.values()));
}
- public UriInfoImpl addCustomQueryOption(final CustomQueryOption item) {
- customQueryOptions.add(item);
+ public UriInfoImpl addCustomQueryOption(final CustomQueryOption option) {
+ if (option.getName() != null && !option.getName().isEmpty()) {
+ customQueryOptions.add(option);
+ }
return this;
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/110c7b0e/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java
index d8209d8..03750a5 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java
@@ -18,6 +18,8 @@
*/
package org.apache.olingo.server.core.uri.parser;
+import java.util.Map;
+
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
@@ -30,6 +32,7 @@ import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.uri.UriInfoKind;
import org.apache.olingo.server.api.uri.UriResourceNavigation;
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
+import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.LevelsExpandOption;
@@ -53,10 +56,12 @@ public class ExpandParser {
private final Edm edm;
private final OData odata;
+ private final Map<String, AliasQueryOption> aliases;
- public ExpandParser(final Edm edm, final OData odata) {
+ public ExpandParser(final Edm edm, final OData odata, final Map<String, AliasQueryOption> aliases) {
this.edm = edm;
this.odata = odata;
+ this.aliases = aliases;
}
public ExpandOption parse(UriTokenizer tokenizer, final EdmStructuredType referencedType)
@@ -92,7 +97,7 @@ public class ExpandParser {
ParserHelper.requireNext(tokenizer, TokenKind.SLASH);
}
- UriInfoImpl resource = parseExpandPath(tokenizer, referencedType);
+ UriInfoImpl resource = parseExpandPath(tokenizer, referencedType, item);
UriResourcePartTyped lastPart = (UriResourcePartTyped) resource.getLastResourcePart();
@@ -156,8 +161,8 @@ public class ExpandParser {
return null;
}
- private UriInfoImpl parseExpandPath(UriTokenizer tokenizer, final EdmStructuredType referencedType)
- throws UriParserException {
+ private UriInfoImpl parseExpandPath(UriTokenizer tokenizer, final EdmStructuredType referencedType,
+ ExpandItemImpl item) throws UriParserException {
UriInfoImpl resource = new UriInfoImpl().setKind(UriInfoKind.resource);
EdmStructuredType type = referencedType;
@@ -181,10 +186,13 @@ public class ExpandParser {
final EdmNavigationProperty navigationProperty = type.getNavigationProperty(name);
if (navigationProperty == null) {
- // TODO: could also have been star after complex property (and maybe type cast)
- throw new UriParserSemanticException(
- "Navigation Property '" + name + "' not found in type '" + type.getFullQualifiedName() + "'.",
- UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE, type.getName(), name);
+ if (tokenizer.next(TokenKind.STAR)) {
+ item.setIsStar(true);
+ } else {
+ throw new UriParserSemanticException(
+ "Navigation Property '" + name + "' not found in type '" + type.getFullQualifiedName() + "'.",
+ UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE, type.getName(), name);
+ }
} else {
resource.addResourcePart(new UriResourceNavigationPropertyImpl(navigationProperty));
}
@@ -209,11 +217,11 @@ public class ExpandParser {
} else if (!forRef && !forCount && tokenizer.next(TokenKind.EXPAND)) {
ParserHelper.requireNext(tokenizer, TokenKind.EQ);
- systemQueryOption = new ExpandParser(edm, odata).parse(tokenizer, referencedType);
+ systemQueryOption = new ExpandParser(edm, odata, aliases).parse(tokenizer, referencedType);
} else if (tokenizer.next(TokenKind.FILTER)) {
ParserHelper.requireNext(tokenizer, TokenKind.EQ);
- systemQueryOption = new FilterParser(edm, odata).parse(tokenizer, referencedType, null);
+ systemQueryOption = new FilterParser(edm, odata).parse(tokenizer, referencedType, null, aliases);
} else if (!forRef && !forCount && tokenizer.next(TokenKind.LEVELS)) {
ParserHelper.requireNext(tokenizer, TokenKind.EQ);
@@ -221,7 +229,7 @@ public class ExpandParser {
} else if (!forCount && tokenizer.next(TokenKind.ORDERBY)) {
ParserHelper.requireNext(tokenizer, TokenKind.EQ);
- systemQueryOption = new OrderByParser(edm, odata).parse(tokenizer, referencedType, null);
+ systemQueryOption = new OrderByParser(edm, odata).parse(tokenizer, referencedType, null, aliases);
} else if (tokenizer.next(TokenKind.SEARCH)) {
ParserHelper.requireNext(tokenizer, TokenKind.EQ);
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/110c7b0e/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
index 1cf279e..a0ec676 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
@@ -24,7 +24,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
-import java.util.HashMap;
+import java.util.EnumMap;
import java.util.List;
import java.util.Map;
@@ -53,6 +53,7 @@ import org.apache.olingo.server.api.uri.UriResourceFunction;
import org.apache.olingo.server.api.uri.UriResourceLambdaVariable;
import org.apache.olingo.server.api.uri.UriResourceNavigation;
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
+import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
import org.apache.olingo.server.api.uri.queryoption.expression.Alias;
import org.apache.olingo.server.api.uri.queryoption.expression.Binary;
import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
@@ -96,7 +97,7 @@ import org.apache.olingo.server.core.uri.validator.UriValidationException;
public class ExpressionParser {
private static final Map<TokenKind, BinaryOperatorKind> tokenToBinaryOperator;
static {
- Map<TokenKind, BinaryOperatorKind> temp = new HashMap<TokenKind, BinaryOperatorKind>();
+ Map<TokenKind, BinaryOperatorKind> temp = new EnumMap<TokenKind, BinaryOperatorKind>(TokenKind.class);
temp.put(TokenKind.OrOperator, BinaryOperatorKind.OR);
temp.put(TokenKind.AndOperator, BinaryOperatorKind.AND);
@@ -121,7 +122,7 @@ public class ExpressionParser {
// 'cast' and 'isof' are handled specially.
private static final Map<TokenKind, MethodKind> tokenToMethod;
static {
- Map<TokenKind, MethodKind> temp = new HashMap<TokenKind, MethodKind>();
+ Map<TokenKind, MethodKind> temp = new EnumMap<TokenKind, MethodKind>(TokenKind.class);
temp.put(TokenKind.CeilingMethod, MethodKind.CEILING);
temp.put(TokenKind.ConcatMethod, MethodKind.CONCAT);
temp.put(TokenKind.ContainsMethod, MethodKind.CONTAINS);
@@ -163,6 +164,7 @@ public class ExpressionParser {
private Deque<UriResourceLambdaVariable> lambdaVariables = new ArrayDeque<UriResourceLambdaVariable>();
private EdmType referringType;
private Collection<String> crossjoinEntitySetNames;
+ private Map<String, AliasQueryOption> aliases;
public ExpressionParser(final Edm edm, final OData odata) {
this.edm = edm;
@@ -170,12 +172,13 @@ public class ExpressionParser {
}
public Expression parse(UriTokenizer tokenizer, final EdmType referringType,
- final Collection<String> crossjoinEntitySetNames)
+ final Collection<String> crossjoinEntitySetNames, final Map<String, AliasQueryOption> aliases)
throws UriParserException, UriValidationException {
// Initialize tokenizer.
this.tokenizer = tokenizer;
this.referringType = referringType;
this.crossjoinEntitySetNames = crossjoinEntitySetNames;
+ this.aliases = aliases;
return parseExpression();
}
@@ -339,7 +342,14 @@ public class ExpressionParser {
}
if (tokenizer.next(TokenKind.ParameterAliasName)) {
- return new AliasImpl(tokenizer.getText());
+ final String name = tokenizer.getText();
+ if (aliases.containsKey(name)) {
+ return new AliasImpl(name,
+ ParserHelper.parseAliasValue(name, null, true, true, edm, referringType, aliases));
+ } else {
+ throw new UriValidationException("Alias '" + name + "' not found.",
+ UriValidationException.MessageKeys.MISSING_ALIAS, name);
+ }
}
if (tokenizer.next(TokenKind.jsonArrayOrObject)) {
@@ -360,7 +370,8 @@ public class ExpressionParser {
return parsePrimitive(nextPrimitive);
}
- final TokenKind nextMethod = nextMethod();
+ final TokenKind nextMethod =
+ ParserHelper.next(tokenizer, tokenToMethod.keySet().toArray(new TokenKind[tokenToMethod.size()]));
if (nextMethod != null) {
return parseMethod(nextMethod);
}
@@ -630,7 +641,7 @@ public class ExpressionParser {
} else {
ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
final List<UriParameter> keyPredicates =
- ParserHelper.parseKeyPredicate(tokenizer, entitySet.getEntityType(), null);
+ ParserHelper.parseKeyPredicate(tokenizer, entitySet.getEntityType(), null, edm, referringType, aliases);
resource = new UriResourceEntitySetImpl(entitySet).setKeyPredicates(keyPredicates);
}
uriInfo.addResourcePart(resource);
@@ -777,7 +788,8 @@ public class ExpressionParser {
final UriResourceNavigationPropertyImpl navigationResource =
new UriResourceNavigationPropertyImpl((EdmNavigationProperty) property);
navigationResource.setKeyPredicates(
- ParserHelper.parseNavigationKeyPredicate(tokenizer, (EdmNavigationProperty) property));
+ ParserHelper.parseNavigationKeyPredicate(tokenizer, (EdmNavigationProperty) property,
+ edm, referringType, aliases));
uriInfo.addResourcePart(navigationResource);
if (navigationResource.isCollection()) {
@@ -830,13 +842,16 @@ public class ExpressionParser {
if (lastResource instanceof UriResourceNavigation) {
((UriResourceNavigationPropertyImpl) lastResource).setKeyPredicates(
ParserHelper.parseNavigationKeyPredicate(tokenizer,
- ((UriResourceNavigationPropertyImpl) lastResource).getProperty()));
+ ((UriResourceNavigationPropertyImpl) lastResource).getProperty(), edm, referringType, aliases));
} else if (lastResource instanceof UriResourceFunction
&& ((UriResourceFunction) lastResource).getType() instanceof EdmEntityType) {
((UriResourceFunctionImpl) lastResource).setKeyPredicates(
ParserHelper.parseKeyPredicate(tokenizer,
(EdmEntityType) ((UriResourceFunction) lastResource).getType(),
- null));
+ null,
+ edm,
+ referringType,
+ aliases));
} else {
throw new UriParserSemanticException("Unknown or wrong resource type.",
UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, lastResource.toString());
@@ -911,18 +926,21 @@ public class ExpressionParser {
private void parseFunction(final FullQualifiedName fullQualifiedName, UriInfoImpl uriInfo,
final EdmType lastType, final boolean lastIsCollection) throws UriParserException, UriValidationException {
- final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, edm, referringType, true);
+ final List<UriParameter> parameters =
+ ParserHelper.parseFunctionParameters(tokenizer, edm, referringType, true, aliases);
final List<String> parameterNames = ParserHelper.getParameterNames(parameters);
final EdmFunction boundFunction = edm.getBoundFunction(fullQualifiedName,
lastType.getFullQualifiedName(), lastIsCollection, parameterNames);
if (boundFunction != null) {
+ ParserHelper.validateFunctionParameters(boundFunction, parameters, edm, referringType, aliases);
parseFunctionRest(uriInfo, boundFunction, parameters);
return;
}
final EdmFunction unboundFunction = edm.getUnboundFunction(fullQualifiedName, parameterNames);
if (unboundFunction != null) {
+ ParserHelper.validateFunctionParameters(unboundFunction, parameters, edm, referringType, aliases);
parseFunctionRest(uriInfo, unboundFunction, parameters);
return;
}
@@ -934,7 +952,8 @@ public class ExpressionParser {
private void parseBoundFunction(final FullQualifiedName fullQualifiedName, UriInfoImpl uriInfo,
final UriResourcePartTyped lastResource) throws UriParserException, UriValidationException {
final EdmType type = lastResource.getType();
- final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, edm, referringType, true);
+ final List<UriParameter> parameters =
+ ParserHelper.parseFunctionParameters(tokenizer, edm, referringType, true, aliases);
final List<String> parameterNames = ParserHelper.getParameterNames(parameters);
final EdmFunction boundFunction = edm.getBoundFunction(fullQualifiedName,
type.getFullQualifiedName(), lastResource.isCollection(), parameterNames);
@@ -942,6 +961,7 @@ public class ExpressionParser {
throw new UriParserSemanticException("Bound function '" + fullQualifiedName + "' not found.",
UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND, fullQualifiedName.getFullQualifiedNameAsString());
}
+ ParserHelper.validateFunctionParameters(boundFunction, parameters, edm, referringType, aliases);
parseFunctionRest(uriInfo, boundFunction, parameters);
}
@@ -1010,40 +1030,6 @@ public class ExpressionParser {
}
}
- private TokenKind nextMethod() {
- return ParserHelper.next(tokenizer,
- TokenKind.CeilingMethod,
- TokenKind.ConcatMethod,
- TokenKind.ContainsMethod,
- TokenKind.DateMethod,
- TokenKind.DayMethod,
- TokenKind.EndswithMethod,
- TokenKind.FloorMethod,
- TokenKind.FractionalsecondsMethod,
- TokenKind.GeoDistanceMethod,
- TokenKind.GeoIntersectsMethod,
- TokenKind.GeoLengthMethod,
- TokenKind.HourMethod,
- TokenKind.IndexofMethod,
- TokenKind.LengthMethod,
- TokenKind.MaxdatetimeMethod,
- TokenKind.MindatetimeMethod,
- TokenKind.MinuteMethod,
- TokenKind.MonthMethod,
- TokenKind.NowMethod,
- TokenKind.RoundMethod,
- TokenKind.SecondMethod,
- TokenKind.StartswithMethod,
- TokenKind.SubstringMethod,
- TokenKind.TimeMethod,
- TokenKind.TolowerMethod,
- TokenKind.TotaloffsetminutesMethod,
- TokenKind.TotalsecondsMethod,
- TokenKind.ToupperMethod,
- TokenKind.TrimMethod,
- TokenKind.YearMethod);
- }
-
protected static EdmType getType(final Expression expression) throws UriParserException {
EdmType type;
if (expression instanceof Literal) {
@@ -1060,11 +1046,12 @@ public class ExpressionParser {
type = ((BinaryImpl) expression).getType();
} else if (expression instanceof Method) {
type = ((MethodImpl) expression).getType();
+ } else if (expression instanceof Alias) {
+ final AliasQueryOption alias = ((AliasImpl) expression).getAlias();
+ type = alias == null || alias.getValue() == null ? null : getType(alias.getValue());
} else if (expression instanceof LambdaRef) {
throw new UriParserSemanticException("Type determination not implemented.",
UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, expression.toString());
- } else if (expression instanceof Alias) {
- type = null; // The alias would have to be available already parsed.
} else {
throw new UriParserSemanticException("Unknown expression type.",
UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, expression.toString());
@@ -1142,7 +1129,7 @@ public class ExpressionParser {
private Enumeration createEnumExpression(final String primitiveValueLiteral) throws UriParserException {
final EdmEnumType enumType = getEnumType(primitiveValueLiteral);
- // TODO: Can the Enumeration interface be changed to handle the value as a whole?
+ // The Enumeration interface could be extended to handle the value as a whole, in line with the primitive type.
try {
return new EnumerationImpl(enumType,
Arrays.asList(enumType.fromUriLiteral(primitiveValueLiteral).split(",")));
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/110c7b0e/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
index dd73009..f20b029 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
@@ -19,11 +19,13 @@
package org.apache.olingo.server.core.uri.parser;
import java.util.Collection;
+import java.util.Map;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.core.uri.queryoption.FilterOptionImpl;
@@ -40,10 +42,10 @@ public class FilterParser {
}
public FilterOption parse(UriTokenizer tokenizer, final EdmType referencedType,
- final Collection<String> crossjoinEntitySetNames)
+ final Collection<String> crossjoinEntitySetNames, final Map<String, AliasQueryOption> aliases)
throws UriParserException, UriValidationException {
final Expression filterExpression = new ExpressionParser(edm, odata)
- .parse(tokenizer, referencedType, crossjoinEntitySetNames);
+ .parse(tokenizer, referencedType, crossjoinEntitySetNames, aliases);
final EdmType type = ExpressionParser.getType(filterExpression);
if (type == null || type.equals(odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean))) {
return new FilterOptionImpl().setExpression(filterExpression);
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/110c7b0e/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/OrderByParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/OrderByParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/OrderByParser.java
index 5ea8cb7..b008ed6 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/OrderByParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/OrderByParser.java
@@ -19,10 +19,12 @@
package org.apache.olingo.server.core.uri.parser;
import java.util.Collection;
+import java.util.Map;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmStructuredType;
import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
import org.apache.olingo.server.api.uri.queryoption.OrderByOption;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
@@ -41,12 +43,12 @@ public class OrderByParser {
}
public OrderByOption parse(UriTokenizer tokenizer, final EdmStructuredType referencedType,
- final Collection<String> crossjoinEntitySetNames)
+ final Collection<String> crossjoinEntitySetNames, final Map<String, AliasQueryOption> aliases)
throws UriParserException, UriValidationException {
OrderByOptionImpl orderByOption = new OrderByOptionImpl();
do {
final Expression orderByExpression = new ExpressionParser(edm, odata)
- .parse(tokenizer, referencedType, crossjoinEntitySetNames);
+ .parse(tokenizer, referencedType, crossjoinEntitySetNames, aliases);
OrderByItemImpl item = new OrderByItemImpl();
item.setExpression(orderByExpression);
if (tokenizer.next(TokenKind.AscSuffix)) {
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/110c7b0e/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
index 586cb10..e1313c1 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
@@ -20,8 +20,10 @@ package org.apache.olingo.server.core.uri.parser;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmStructuredType;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
@@ -36,21 +38,30 @@ import org.apache.olingo.server.api.uri.UriResourcePartTyped;
import org.apache.olingo.server.api.uri.UriResourceRef;
import org.apache.olingo.server.api.uri.UriResourceValue;
import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
-import org.apache.olingo.server.api.uri.queryoption.CustomQueryOption;
+import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
+import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
+import org.apache.olingo.server.api.uri.queryoption.FilterOption;
+import org.apache.olingo.server.api.uri.queryoption.OrderByItem;
+import org.apache.olingo.server.api.uri.queryoption.OrderByOption;
import org.apache.olingo.server.api.uri.queryoption.QueryOption;
+import org.apache.olingo.server.api.uri.queryoption.SelectOption;
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOption;
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
-import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.core.uri.UriInfoImpl;
import org.apache.olingo.server.core.uri.UriResourceStartingTypeFilterImpl;
import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
import org.apache.olingo.server.core.uri.parser.search.SearchParser;
import org.apache.olingo.server.core.uri.queryoption.AliasQueryOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.FilterOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.FormatOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.IdOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.OrderByOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.SelectOptionImpl;
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.SystemQueryOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.TopOptionImpl;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
@@ -74,6 +85,32 @@ public class Parser {
throws UriParserException, UriValidationException {
UriInfoImpl contextUriInfo = new UriInfoImpl();
+
+ // Read the query options (system and custom options).
+ // This is done before parsing the resource path because the aliases have to be available there.
+ // System query options that can only be parsed with context from the resource path will be post-processed later.
+ final List<QueryOption> options =
+ query == null ? Collections.<QueryOption> emptyList() : UriDecoder.splitAndDecodeOptions(query);
+ for (final QueryOption option : options) {
+ final String optionName = option.getName();
+ // Parse the untyped option and retrieve a system-option or alias-option instance (or null for a custom option).
+ final QueryOption parsedOption = parseOption(optionName, option.getText());
+ try {
+ contextUriInfo.setQueryOption(parsedOption == null ? option : parsedOption);
+ } catch (final ODataRuntimeException e) {
+ throw new UriParserSyntaxException(
+ parsedOption instanceof SystemQueryOption ?
+ "Double system query option!" :
+ "Alias already specified! Name: " + optionName,
+ e,
+ parsedOption instanceof SystemQueryOption ?
+ UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION :
+ UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS,
+ optionName);
+ }
+ }
+
+ // Read the decoded path segments.
EdmType contextType = null;
boolean contextIsCollection = false;
@@ -85,7 +122,6 @@ public class Parser {
numberOfSegments--;
}
- // first, read the decoded path segments
final String firstSegment = pathSegmentsDecoded.get(0);
if (firstSegment.isEmpty()) {
@@ -107,24 +143,29 @@ public class Parser {
contextIsCollection = true;
} else if (firstSegment.equals("$entity")) {
+ contextUriInfo.setKind(UriInfoKind.entityId);
if (numberOfSegments > 1) {
final String typeCastSegment = pathSegmentsDecoded.get(1);
ensureLastSegment(typeCastSegment, 2, numberOfSegments);
- contextUriInfo = new ResourcePathParser(edm).parseDollarEntityTypeCast(typeCastSegment);
- contextType = contextUriInfo.getEntityTypeCast();
- } else {
- contextUriInfo.setKind(UriInfoKind.entityId);
+ contextType = new ResourcePathParser(edm, contextUriInfo.getAliasMap())
+ .parseDollarEntityTypeCast(typeCastSegment);
+ contextUriInfo.setEntityTypeCast((EdmEntityType) contextType);
}
contextIsCollection = false;
} else if (firstSegment.startsWith("$crossjoin")) {
ensureLastSegment(firstSegment, 1, numberOfSegments);
- contextUriInfo = new ResourcePathParser(edm).parseCrossjoinSegment(firstSegment);
+ contextUriInfo.setKind(UriInfoKind.crossjoin);
+ final List<String> entitySetNames = new ResourcePathParser(edm, contextUriInfo.getAliasMap())
+ .parseCrossjoinSegment(firstSegment);
+ for (final String name : entitySetNames) {
+ contextUriInfo.addEntitySetName(name);
+ }
contextIsCollection = true;
} else {
contextUriInfo.setKind(UriInfoKind.resource);
- final ResourcePathParser resourcePathParser = new ResourcePathParser(edm);
+ final ResourcePathParser resourcePathParser = new ResourcePathParser(edm, contextUriInfo.getAliasMap());
int count = 0;
UriResource lastSegment = null;
for (final String pathSegment : pathSegmentsDecoded) {
@@ -162,161 +203,168 @@ public class Parser {
}
}
- // second, read the system query options and the custom query options
- final List<QueryOption> options =
- query == null ? Collections.<QueryOption> emptyList() : UriDecoder.splitAndDecodeOptions(query);
- for (final QueryOption option : options) {
- final String optionName = option.getName();
- final String optionValue = option.getText();
- if (optionName.startsWith(DOLLAR)) {
- SystemQueryOption systemOption = null;
- if (optionName.equals(SystemQueryOptionKind.FILTER.toString())) {
- UriTokenizer filterTokenizer = new UriTokenizer(optionValue);
- // The referring type could be a primitive type or a structured type.
- systemOption = new FilterParser(edm, odata).parse(filterTokenizer,
- contextType,
- contextUriInfo.getEntitySetNames());
- checkOptionEOF(filterTokenizer, optionName, optionValue);
-
- } else if (optionName.equals(SystemQueryOptionKind.FORMAT.toString())) {
- FormatOptionImpl formatOption = new FormatOptionImpl();
- formatOption.setText(optionValue);
- if (optionValue.equalsIgnoreCase(JSON)
- || optionValue.equalsIgnoreCase(XML)
- || optionValue.equalsIgnoreCase(ATOM)
- || isFormatSyntaxValid(optionValue)) {
- formatOption.setFormat(optionValue);
- } else {
- throw new UriParserSyntaxException("Illegal value of $format option!",
- UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT, optionValue);
- }
- systemOption = formatOption;
-
- } else if (optionName.equals(SystemQueryOptionKind.EXPAND.toString())) {
- if (contextType instanceof EdmStructuredType
- || !contextUriInfo.getEntitySetNames().isEmpty()
- || contextUriInfo.getKind() == UriInfoKind.all) {
- UriTokenizer expandTokenizer = new UriTokenizer(optionValue);
- systemOption = new ExpandParser(edm, odata).parse(expandTokenizer,
- contextType instanceof EdmStructuredType ? (EdmStructuredType) contextType : null);
- checkOptionEOF(expandTokenizer, optionName, optionValue);
- } else {
- throw new UriValidationException("Expand is only allowed on structured types!",
- UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED, optionName);
- }
-
- } else if (optionName.equals(SystemQueryOptionKind.ID.toString())) {
- IdOptionImpl idOption = new IdOptionImpl();
- idOption.setText(optionValue);
- if (optionValue == null || optionValue.isEmpty()) {
- throw new UriParserSyntaxException("Illegal value of $id option!",
- UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
- optionName, optionValue);
- }
- idOption.setValue(optionValue);
- systemOption = idOption;
-
- } else if (optionName.equals(SystemQueryOptionKind.LEVELS.toString())) {
- throw new UriParserSyntaxException("System query option '$levels' is allowed only inside '$expand'!",
- UriParserSyntaxException.MessageKeys.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE);
-
- } else if (optionName.equals(SystemQueryOptionKind.ORDERBY.toString())) {
- UriTokenizer orderByTokenizer = new UriTokenizer(optionValue);
- systemOption = new OrderByParser(edm, odata).parse(orderByTokenizer,
- contextType instanceof EdmStructuredType ? (EdmStructuredType) contextType : null,
- contextUriInfo.getEntitySetNames());
- checkOptionEOF(orderByTokenizer, optionName, optionValue);
-
- } else if (optionName.equals(SystemQueryOptionKind.SEARCH.toString())) {
- systemOption = new SearchParser().parse(optionValue);
-
- } else if (optionName.equals(SystemQueryOptionKind.SELECT.toString())) {
- UriTokenizer selectTokenizer = new UriTokenizer(optionValue);
- systemOption = new SelectParser(edm).parse(selectTokenizer,
- contextType instanceof EdmStructuredType ? (EdmStructuredType) contextType : null,
- contextIsCollection);
- checkOptionEOF(selectTokenizer, optionName, optionValue);
-
- } else if (optionName.equals(SystemQueryOptionKind.SKIP.toString())) {
- SkipOptionImpl skipOption = new SkipOptionImpl();
- skipOption.setText(optionValue);
- skipOption.setValue(ParserHelper.parseNonNegativeInteger(optionName, optionValue, true));
- systemOption = skipOption;
+ // Post-process system query options that need context information from the resource path.
+ parseFilterOption(contextUriInfo.getFilterOption(), contextType,
+ contextUriInfo.getEntitySetNames(), contextUriInfo.getAliasMap());
+ parseOrderByOption(contextUriInfo.getOrderByOption(), contextType,
+ contextUriInfo.getEntitySetNames(), contextUriInfo.getAliasMap());
+ parseExpandOption(contextUriInfo.getExpandOption(), contextType,
+ !contextUriInfo.getEntitySetNames().isEmpty() || contextUriInfo.getKind() == UriInfoKind.all,
+ contextUriInfo.getAliasMap());
+ parseSelectOption(contextUriInfo.getSelectOption(), contextType, contextIsCollection);
- } else if (optionName.equals(SystemQueryOptionKind.SKIPTOKEN.toString())) {
- SkipTokenOptionImpl skipTokenOption = new SkipTokenOptionImpl();
- skipTokenOption.setText(optionValue);
- if (optionValue == null || optionValue.isEmpty()) {
- throw new UriParserSyntaxException("Illegal value of $skiptoken option!",
- UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
- optionName, optionValue);
- }
- skipTokenOption.setValue(optionValue);
- systemOption = skipTokenOption;
-
- } else if (optionName.equals(SystemQueryOptionKind.TOP.toString())) {
- TopOptionImpl topOption = new TopOptionImpl();
- topOption.setText(optionValue);
- topOption.setValue(ParserHelper.parseNonNegativeInteger(optionName, optionValue, true));
- systemOption = topOption;
-
- } else if (optionName.equals(SystemQueryOptionKind.COUNT.toString())) {
- CountOptionImpl inlineCountOption = new CountOptionImpl();
- inlineCountOption.setText(optionValue);
- if (optionValue.equals("true") || optionValue.equals("false")) {
- inlineCountOption.setValue(Boolean.parseBoolean(optionValue));
- } else {
- throw new UriParserSyntaxException("Illegal value of $count option!",
- UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
- optionName, optionValue);
- }
- systemOption = inlineCountOption;
+ return contextUriInfo;
+ }
+ private QueryOption parseOption(final String optionName, final String optionValue)
+ throws UriParserException, UriValidationException {
+ if (optionName.startsWith(DOLLAR)) {
+ final SystemQueryOptionKind kind = SystemQueryOptionKind.get(optionName);
+ if (kind == null) {
+ throw new UriParserSyntaxException("Unknown system query option!",
+ UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION, optionName);
+ }
+ SystemQueryOption systemOption = null;
+ switch (kind) {
+ case SEARCH:
+ systemOption = new SearchParser().parse(optionValue);
+ break;
+ case FILTER:
+ systemOption = new FilterOptionImpl();
+ break;
+ case COUNT:
+ if (optionValue.equals("true") || optionValue.equals("false")) {
+ systemOption = new CountOptionImpl().setValue(Boolean.parseBoolean(optionValue));
} else {
- throw new UriParserSyntaxException("Unknown system query option!",
- UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION, optionName);
+ throw new UriParserSyntaxException("Illegal value of $count option!",
+ UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+ optionName, optionValue);
}
- try {
- contextUriInfo.setSystemQueryOption(systemOption);
- } catch (final ODataRuntimeException e) {
- throw new UriParserSyntaxException("Double system query option!", e,
- UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, optionName);
+ break;
+ case ORDERBY:
+ systemOption = new OrderByOptionImpl();
+ break;
+ case SKIP:
+ systemOption = new SkipOptionImpl()
+ .setValue(ParserHelper.parseNonNegativeInteger(optionName, optionValue, true));
+ break;
+ case SKIPTOKEN:
+ if (optionValue.isEmpty()) {
+ throw new UriParserSyntaxException("Illegal value of $skiptoken option!",
+ UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+ optionName, optionValue);
}
-
- } else if (optionName.startsWith(AT)) {
- if (contextUriInfo.getAlias(optionName) == null) {
- // TODO: Aliases can only be parsed in the context of their usage.
- Expression expression = null;
- UriTokenizer aliasTokenizer = new UriTokenizer(optionValue);
- if (aliasTokenizer.next(TokenKind.jsonArrayOrObject)) {
- if (!aliasTokenizer.next(TokenKind.EOF)) {
- throw new UriParserSyntaxException("Illegal value for alias '" + optionName + "'.",
- UriParserSyntaxException.MessageKeys.SYNTAX);
- }
- } else {
- UriTokenizer aliasValueTokenizer = new UriTokenizer(optionValue);
- expression = new ExpressionParser(edm, odata).parse(aliasValueTokenizer, null,
- contextUriInfo.getEntitySetNames());
- if (!aliasValueTokenizer.next(TokenKind.EOF)) {
- throw new UriParserSyntaxException("Illegal value for alias '" + optionName + "'.",
- UriParserSyntaxException.MessageKeys.SYNTAX);
- }
- }
- contextUriInfo.addAlias((AliasQueryOption) new AliasQueryOptionImpl()
- .setAliasValue(expression)
- .setName(optionName)
- .setText(NULL.equals(optionValue) ? null : optionValue));
+ systemOption = new SkipTokenOptionImpl().setValue(optionValue);
+ break;
+ case TOP:
+ systemOption = new TopOptionImpl()
+ .setValue(ParserHelper.parseNonNegativeInteger(optionName, optionValue, true));
+ break;
+ case EXPAND:
+ systemOption = new ExpandOptionImpl();
+ break;
+ case SELECT:
+ systemOption = new SelectOptionImpl();
+ break;
+ case FORMAT:
+ if (optionValue.equalsIgnoreCase(JSON)
+ || optionValue.equalsIgnoreCase(XML)
+ || optionValue.equalsIgnoreCase(ATOM)
+ || isFormatSyntaxValid(optionValue)) {
+ systemOption = new FormatOptionImpl().setFormat(optionValue);
} else {
- throw new UriParserSyntaxException("Alias already specified! Name: " + optionName,
- UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS, optionName);
+ throw new UriParserSyntaxException("Illegal value of $format option!",
+ UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT, optionValue);
}
+ break;
+ case ID:
+ if (optionValue.isEmpty()) {
+ throw new UriParserSyntaxException("Illegal value of $id option!",
+ UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+ optionName, optionValue);
+ }
+ systemOption = new IdOptionImpl().setValue(optionValue);
+ break;
+ case LEVELS:
+ throw new UriParserSyntaxException("System query option '$levels' is allowed only inside '$expand'!",
+ UriParserSyntaxException.MessageKeys.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE);
+ }
+ ((SystemQueryOptionImpl) systemOption).setText(optionValue);
+ return systemOption;
- } else if (!optionName.isEmpty()) {
- contextUriInfo.addCustomQueryOption((CustomQueryOption) option);
+ } else if (optionName.startsWith(AT)) {
+ // Aliases can only be parsed in the context of their usage, so the value is not checked here.
+ return new AliasQueryOptionImpl()
+ .setName(optionName)
+ .setText(NULL.equals(optionValue) ? null : optionValue);
+
+ } else {
+ // The option is a custom query option; the caller can re-use its query option.
+ return null;
+ }
+ }
+
+ private void parseFilterOption(FilterOption filterOption, final EdmType contextType,
+ final List<String> entitySetNames, final Map<String, AliasQueryOption> aliases)
+ throws UriParserException, UriValidationException {
+ if (filterOption != null) {
+ final String optionValue = filterOption.getText();
+ UriTokenizer filterTokenizer = new UriTokenizer(optionValue);
+ // The referring type could be a primitive type or a structured type.
+ ((FilterOptionImpl) filterOption).setExpression(
+ new FilterParser(edm, odata).parse(filterTokenizer, contextType, entitySetNames, aliases)
+ .getExpression());
+ checkOptionEOF(filterTokenizer, filterOption.getName(), optionValue);
+ }
+ }
+
+ private void parseOrderByOption(OrderByOption orderByOption, final EdmType contextType,
+ final List<String> entitySetNames, final Map<String, AliasQueryOption> aliases)
+ throws UriParserException, UriValidationException {
+ if (orderByOption != null) {
+ final String optionValue = orderByOption.getText();
+ UriTokenizer orderByTokenizer = new UriTokenizer(optionValue);
+ final OrderByOption option = new OrderByParser(edm, odata).parse(orderByTokenizer,
+ contextType instanceof EdmStructuredType ? (EdmStructuredType) contextType : null,
+ entitySetNames,
+ aliases);
+ checkOptionEOF(orderByTokenizer, orderByOption.getName(), optionValue);
+ for (final OrderByItem item : option.getOrders()) {
+ ((OrderByOptionImpl) orderByOption).addOrder(item);
}
}
+ }
- return contextUriInfo;
+ private void parseExpandOption(ExpandOption expandOption, final EdmType contextType, final boolean isCrossjoinOrAll,
+ final Map<String, AliasQueryOption> aliases) throws UriParserException, UriValidationException {
+ if (expandOption != null) {
+ if (!(contextType instanceof EdmStructuredType || isCrossjoinOrAll)) {
+ throw new UriValidationException("Expand is only allowed on structured types!",
+ UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED, expandOption.getName());
+ }
+ final String optionValue = expandOption.getText();
+ UriTokenizer expandTokenizer = new UriTokenizer(optionValue);
+ final ExpandOption option = new ExpandParser(edm, odata, aliases).parse(expandTokenizer,
+ contextType instanceof EdmStructuredType ? (EdmStructuredType) contextType : null);
+ checkOptionEOF(expandTokenizer, expandOption.getName(), optionValue);
+ for (final ExpandItem item : option.getExpandItems()) {
+ ((ExpandOptionImpl) expandOption).addExpandItem(item);
+ }
+ }
+ }
+
+ private void parseSelectOption(SelectOption selectOption, final EdmType contextType,
+ final boolean contextIsCollection) throws UriParserException, UriValidationException {
+ if (selectOption != null) {
+ final String optionValue = selectOption.getText();
+ UriTokenizer selectTokenizer = new UriTokenizer(optionValue);
+ ((SelectOptionImpl) selectOption).setSelectItems(
+ new SelectParser(edm).parse(selectTokenizer,
+ contextType instanceof EdmStructuredType ? (EdmStructuredType) contextType : null,
+ contextIsCollection)
+ .getSelectItems());
+ checkOptionEOF(selectTokenizer, selectOption.getName(), optionValue);
+ }
}
private void ensureLastSegment(final String segment, final int pos, final int size)
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/110c7b0e/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
index b0c2972..9986542 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
@@ -20,6 +20,7 @@ package org.apache.olingo.server.core.uri.parser;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -27,8 +28,10 @@ import java.util.Map.Entry;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmFunction;
import org.apache.olingo.commons.api.edm.EdmKeyPropertyRef;
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.commons.api.edm.EdmParameter;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
@@ -39,6 +42,7 @@ import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
+import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.api.uri.queryoption.expression.Literal;
import org.apache.olingo.server.core.ODataImpl;
@@ -46,6 +50,8 @@ import org.apache.olingo.server.core.uri.UriParameterImpl;
import org.apache.olingo.server.core.uri.UriResourceTypedImpl;
import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
+import org.apache.olingo.server.core.uri.queryoption.AliasQueryOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.LiteralImpl;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
public class ParserHelper {
@@ -55,7 +61,7 @@ public class ParserHelper {
protected static final Map<TokenKind, EdmPrimitiveTypeKind> tokenToPrimitiveType;
static {
/* Enum and null are not present in the map. These have to be handled differently. */
- Map<TokenKind, EdmPrimitiveTypeKind> temp = new HashMap<TokenKind, EdmPrimitiveTypeKind>();
+ Map<TokenKind, EdmPrimitiveTypeKind> temp = new EnumMap<TokenKind, EdmPrimitiveTypeKind>(TokenKind.class);
temp.put(TokenKind.BooleanValue, EdmPrimitiveTypeKind.Boolean);
temp.put(TokenKind.StringValue, EdmPrimitiveTypeKind.String);
// Very large integer values are of type Edm.Decimal but this is handled elsewhere.
@@ -87,18 +93,18 @@ public class ParserHelper {
tokenToPrimitiveType = Collections.unmodifiableMap(temp);
}
- public static void requireNext(UriTokenizer tokenizer, final TokenKind required) throws UriParserException {
+ protected static void requireNext(UriTokenizer tokenizer, final TokenKind required) throws UriParserException {
if (!tokenizer.next(required)) {
throw new UriParserSyntaxException("Expected token '" + required.toString() + "' not found.",
UriParserSyntaxException.MessageKeys.SYNTAX);
}
}
- public static void requireTokenEnd(UriTokenizer tokenizer) throws UriParserException {
+ protected static void requireTokenEnd(UriTokenizer tokenizer) throws UriParserException {
requireNext(tokenizer, TokenKind.EOF);
}
- public static TokenKind next(UriTokenizer tokenizer, final TokenKind... kinds) {
+ protected static TokenKind next(UriTokenizer tokenizer, final TokenKind... kinds) {
for (final TokenKind kind : kinds) {
if (tokenizer.next(kind)) {
return kind;
@@ -107,7 +113,7 @@ public class ParserHelper {
return null;
}
- public static TokenKind nextPrimitiveValue(UriTokenizer tokenizer) {
+ protected static TokenKind nextPrimitiveValue(UriTokenizer tokenizer) {
return next(tokenizer,
TokenKind.NULL,
TokenKind.BooleanValue,
@@ -146,7 +152,8 @@ public class ParserHelper {
}
protected static List<UriParameter> parseFunctionParameters(UriTokenizer tokenizer,
- final Edm edm, final EdmType referringType, final boolean withComplex)
+ final Edm edm, final EdmType referringType, final boolean withComplex,
+ final Map<String, AliasQueryOption> aliases)
throws UriParserException, UriValidationException {
List<UriParameter> parameters = new ArrayList<UriParameter>();
ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
@@ -164,40 +171,105 @@ public class ParserHelper {
if (tokenizer.next(TokenKind.COMMA) || tokenizer.next(TokenKind.CLOSE) || tokenizer.next(TokenKind.EOF)) {
throw new UriParserSyntaxException("Parameter value expected.", UriParserSyntaxException.MessageKeys.SYNTAX);
}
+ UriParameterImpl parameter = new UriParameterImpl().setName(name);
if (tokenizer.next(TokenKind.ParameterAliasName)) {
- parameters.add(new UriParameterImpl().setName(name).setAlias(tokenizer.getText()));
+ final String aliasName = tokenizer.getText();
+ parameter.setAlias(aliasName)
+ .setExpression(aliases.containsKey(aliasName) ? aliases.get(aliasName).getValue() : null);
} else if (tokenizer.next(TokenKind.jsonArrayOrObject)) {
if (withComplex) {
- parameters.add(new UriParameterImpl().setName(name).setText(tokenizer.getText()));
+ parameter.setText(tokenizer.getText());
} else {
throw new UriParserSemanticException("A JSON array or object is not allowed as parameter value.",
UriParserSemanticException.MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH, tokenizer.getText());
}
} else if (withComplex) {
- final Expression expression = new ExpressionParser(edm, odata).parse(tokenizer, referringType, null);
- parameters.add(new UriParameterImpl().setName(name)
- .setText(expression instanceof Literal ?
- "null".equals(((Literal) expression).getText()) ? null : ((Literal) expression).getText() :
- null)
- .setExpression(expression instanceof Literal ? null : expression));
+ final Expression expression = new ExpressionParser(edm, odata).parse(tokenizer, referringType, null, aliases);
+ parameter.setText(expression instanceof Literal ?
+ "null".equals(((Literal) expression).getText()) ? null : ((Literal) expression).getText() :
+ null)
+ .setExpression(expression instanceof Literal ? null : expression);
} else if (nextPrimitiveValue(tokenizer) == null) {
throw new UriParserSemanticException("Wrong parameter value.",
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, "");
} else {
final String literalValue = tokenizer.getText();
- parameters.add(new UriParameterImpl().setName(name)
- .setText("null".equals(literalValue) ? null : literalValue));
+ parameter.setText("null".equals(literalValue) ? null : literalValue);
}
+ parameters.add(parameter);
} while (tokenizer.next(TokenKind.COMMA));
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
return parameters;
}
+ protected static void validateFunctionParameters(final EdmFunction function, final List<UriParameter> parameters,
+ final Edm edm, final EdmType referringType, final Map<String, AliasQueryOption> aliases)
+ throws UriParserException, UriValidationException {
+ for (final UriParameter parameter : parameters) {
+ final String parameterName = parameter.getName();
+ final EdmParameter edmParameter = function.getParameter(parameterName);
+ final boolean isNullable = edmParameter.isNullable();
+ if (parameter.getText() == null && parameter.getExpression() == null && !isNullable) {
+ if (parameter.getAlias() == null) {
+ // No alias, value is explicitly null.
+ throw new UriValidationException("Missing non-nullable parameter " + parameterName,
+ UriValidationException.MessageKeys.MISSING_PARAMETER, parameterName);
+ } else {
+ final String valueForAlias = aliases.containsKey(parameter.getAlias()) ?
+ parseAliasValue(parameter.getAlias(),
+ edmParameter.getType(), edmParameter.isNullable(), edmParameter.isCollection(),
+ edm, referringType, aliases).getText() :
+ null;
+ // Alias value is missing or explicitly null.
+ if (valueForAlias == null) {
+ throw new UriValidationException("Missing alias for " + parameterName,
+ UriValidationException.MessageKeys.MISSING_ALIAS, parameter.getAlias());
+ }
+ }
+ }
+ }
+ }
+
+ protected static AliasQueryOption parseAliasValue(final String name, final EdmType type, final boolean isNullable,
+ final boolean isCollection, final Edm edm, final EdmType referringType,
+ final Map<String, AliasQueryOption> aliases) throws UriParserException, UriValidationException {
+ final EdmTypeKind kind = type == null ? null : type.getKind();
+ final AliasQueryOption alias = aliases.get(name);
+ if (alias != null && alias.getText() != null) {
+ UriTokenizer aliasTokenizer = new UriTokenizer(alias.getText());
+ if (kind == null
+ || !((isCollection || kind == EdmTypeKind.COMPLEX || kind == EdmTypeKind.ENTITY ?
+ aliasTokenizer.next(TokenKind.jsonArrayOrObject) :
+ nextPrimitiveTypeValue(aliasTokenizer, (EdmPrimitiveType) type, isNullable))
+ && aliasTokenizer.next(TokenKind.EOF))) {
+ // The alias value is not an allowed literal value, so parse it again as expression.
+ aliasTokenizer = new UriTokenizer(alias.getText());
+ // Don't pass on the current alias to avoid circular references.
+ Map<String, AliasQueryOption> aliasesInner = new HashMap<String, AliasQueryOption>(aliases);
+ aliasesInner.remove(name);
+ final Expression expression = new ExpressionParser(edm, odata)
+ .parse(aliasTokenizer, referringType, null, aliasesInner);
+ final EdmType expressionType = ExpressionParser.getType(expression);
+ if (aliasTokenizer.next(TokenKind.EOF)
+ && (expressionType == null || type == null || expressionType.equals(type))) {
+ ((AliasQueryOptionImpl) alias).setAliasValue(expression);
+ } else {
+ throw new UriParserSemanticException("Illegal value for alias '" + alias.getName() + "'.",
+ UriParserSemanticException.MessageKeys.UNKNOWN_PART, alias.getText());
+ }
+ }
+ }
+ return alias;
+ }
+
protected static List<UriParameter> parseNavigationKeyPredicate(UriTokenizer tokenizer,
- final EdmNavigationProperty navigationProperty) throws UriParserException, UriValidationException {
+ final EdmNavigationProperty navigationProperty,
+ final Edm edm, final EdmType referringType, final Map<String, AliasQueryOption> aliases)
+ throws UriParserException, UriValidationException {
if (tokenizer.next(TokenKind.OPEN)) {
if (navigationProperty.isCollection()) {
- return parseKeyPredicate(tokenizer, navigationProperty.getType(), navigationProperty.getPartner());
+ return parseKeyPredicate(tokenizer, navigationProperty.getType(), navigationProperty.getPartner(),
+ edm, referringType, aliases);
} else {
throw new UriParserSemanticException("A key is not allowed on non-collection navigation properties.",
UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
@@ -207,7 +279,9 @@ public class ParserHelper {
}
protected static List<UriParameter> parseKeyPredicate(UriTokenizer tokenizer, final EdmEntityType edmEntityType,
- final EdmNavigationProperty partner) throws UriParserException, UriValidationException {
+ final EdmNavigationProperty partner,
+ final Edm edm, final EdmType referringType, final Map<String, AliasQueryOption> aliases)
+ throws UriParserException, UriValidationException {
final List<EdmKeyPropertyRef> keyPropertyRefs = edmEntityType.getKeyPropertyRefs();
if (tokenizer.next(TokenKind.CLOSE)) {
throw new UriParserSemanticException(
@@ -229,11 +303,11 @@ public class ParserHelper {
}
if (tokenizer.next(TokenKind.ODataIdentifier)) {
- keys.addAll(compoundKey(tokenizer, edmEntityType));
+ keys.addAll(compoundKey(tokenizer, edmEntityType, edm, referringType, aliases));
} else if (keyPropertyRefs.size() - referencedNames.size() == 1) {
for (final EdmKeyPropertyRef candidate : keyPropertyRefs) {
if (referencedNames.get(candidate.getName()) == null) {
- keys.add(simpleKey(tokenizer, candidate));
+ keys.add(simpleKey(tokenizer, candidate, edm, referringType, aliases));
break;
}
}
@@ -271,7 +345,8 @@ public class ParserHelper {
}
}
- private static UriParameter simpleKey(UriTokenizer tokenizer, final EdmKeyPropertyRef edmKeyPropertyRef)
+ private static UriParameter simpleKey(UriTokenizer tokenizer, final EdmKeyPropertyRef edmKeyPropertyRef,
+ final Edm edm, final EdmType referringType, final Map<String, AliasQueryOption> aliases)
throws UriParserException, UriValidationException {
final EdmProperty edmProperty = edmKeyPropertyRef == null ? null : edmKeyPropertyRef.getProperty();
if (nextPrimitiveTypeValue(tokenizer,
@@ -279,14 +354,15 @@ public class ParserHelper {
edmProperty == null ? false : edmProperty.isNullable())) {
final String literalValue = tokenizer.getText();
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
- return createUriParameter(edmProperty, edmKeyPropertyRef.getName(), literalValue);
+ return createUriParameter(edmProperty, edmKeyPropertyRef.getName(), literalValue, edm, referringType, aliases);
} else {
throw new UriParserSemanticException("The key value is not valid.",
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, edmKeyPropertyRef.getName());
}
}
- private static List<UriParameter> compoundKey(UriTokenizer tokenizer, final EdmEntityType edmEntityType)
+ private static List<UriParameter> compoundKey(UriTokenizer tokenizer, final EdmEntityType edmEntityType,
+ final Edm edm, final EdmType referringType, final Map<String, AliasQueryOption> aliases)
throws UriParserException, UriValidationException {
List<UriParameter> parameters = new ArrayList<UriParameter>();
@@ -312,7 +388,7 @@ public class ParserHelper {
throw new UriValidationException("Unknown key property " + keyPredicateName,
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, keyPredicateName);
}
- parameters.add(keyValuePair(tokenizer, keyPredicateName, edmEntityType));
+ parameters.add(keyValuePair(tokenizer, keyPredicateName, edmEntityType, edm, referringType, aliases));
parameterNames.add(keyPredicateName);
hasComma = tokenizer.next(TokenKind.COMMA);
if (hasComma) {
@@ -324,8 +400,9 @@ public class ParserHelper {
return parameters;
}
- protected static UriParameter keyValuePair(UriTokenizer tokenizer,
- final String keyPredicateName, final EdmEntityType edmEntityType)
+ private static UriParameter keyValuePair(UriTokenizer tokenizer,
+ final String keyPredicateName, final EdmEntityType edmEntityType,
+ final Edm edm, final EdmType referringType, final Map<String, AliasQueryOption> aliases)
throws UriParserException, UriValidationException {
final EdmKeyPropertyRef keyPropertyRef = edmEntityType.getKeyPropertyRef(keyPredicateName);
final EdmProperty edmProperty = keyPropertyRef == null ? null : keyPropertyRef.getProperty();
@@ -338,7 +415,7 @@ public class ParserHelper {
throw new UriParserSyntaxException("Key value expected.", UriParserSyntaxException.MessageKeys.SYNTAX);
}
if (nextPrimitiveTypeValue(tokenizer, (EdmPrimitiveType) edmProperty.getType(), edmProperty.isNullable())) {
- return createUriParameter(edmProperty, keyPredicateName, tokenizer.getText());
+ return createUriParameter(edmProperty, keyPredicateName, tokenizer.getText(), edm, referringType, aliases);
} else {
throw new UriParserSemanticException(keyPredicateName + " has not a valid key value.",
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, keyPredicateName);
@@ -346,28 +423,43 @@ public class ParserHelper {
}
private static UriParameter createUriParameter(final EdmProperty edmProperty, final String parameterName,
- final String literalValue) throws UriParserException, UriValidationException {
- if (literalValue.startsWith("@")) {
- return new UriParameterImpl()
- .setName(parameterName)
- .setAlias(literalValue);
- }
-
+ final String literalValue, final Edm edm, final EdmType referringType,
+ final Map<String, AliasQueryOption> aliases) throws UriParserException, UriValidationException {
+ final AliasQueryOption alias = literalValue.startsWith("@") ?
+ getKeyAlias(literalValue, edmProperty, edm, referringType, aliases) :
+ null;
+ final String value = alias == null ? literalValue : alias.getText();
final EdmPrimitiveType primitiveType = (EdmPrimitiveType) edmProperty.getType();
try {
- if (!(primitiveType.validate(primitiveType.fromUriLiteral(literalValue), edmProperty.isNullable(),
+ if (!(primitiveType.validate(primitiveType.fromUriLiteral(value), edmProperty.isNullable(),
edmProperty.getMaxLength(), edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode()))) {
throw new UriValidationException("Invalid key property",
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, parameterName);
}
} catch (final EdmPrimitiveTypeException e) {
- throw new UriValidationException("Invalid key property",
+ throw new UriValidationException("Invalid key property", e,
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, parameterName);
}
return new UriParameterImpl()
.setName(parameterName)
- .setText("null".equals(literalValue) ? null : literalValue);
+ .setText("null".equals(literalValue) ? null : literalValue)
+ .setAlias(alias == null ? null : literalValue)
+ .setExpression(alias == null ? null :
+ alias.getValue() == null ? new LiteralImpl(value, primitiveType) : alias.getValue());
+ }
+
+ private static AliasQueryOption getKeyAlias(final String name, final EdmProperty edmProperty,
+ final Edm edm, final EdmType referringType, final Map<String, AliasQueryOption> aliases)
+ throws UriParserException, UriValidationException {
+ if (aliases.containsKey(name)) {
+ return parseAliasValue(name,
+ edmProperty.getType(), edmProperty.isNullable(), edmProperty.isCollection(),
+ edm, referringType, aliases);
+ } else {
+ throw new UriValidationException("Alias '" + name + "' for key value not found.",
+ UriValidationException.MessageKeys.MISSING_ALIAS, name);
+ }
}
private static boolean nextPrimitiveTypeValue(UriTokenizer tokenizer,
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/110c7b0e/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java
index 87cb91a..8d6d52d 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java
@@ -18,7 +18,9 @@
*/
package org.apache.olingo.server.core.uri.parser;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmAction;
@@ -35,11 +37,10 @@ import org.apache.olingo.commons.api.edm.EdmStructuredType;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
-import org.apache.olingo.server.api.uri.UriInfoKind;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
-import org.apache.olingo.server.core.uri.UriInfoImpl;
+import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
import org.apache.olingo.server.core.uri.UriResourceActionImpl;
import org.apache.olingo.server.core.uri.UriResourceComplexPropertyImpl;
import org.apache.olingo.server.core.uri.UriResourceCountImpl;
@@ -59,10 +60,12 @@ public class ResourcePathParser {
private final Edm edm;
private final EdmEntityContainer edmEntityContainer;
+ private final Map<String, AliasQueryOption> aliases;
private UriTokenizer tokenizer;
- public ResourcePathParser(final Edm edm) {
+ public ResourcePathParser(final Edm edm, final Map<String, AliasQueryOption> aliases) {
this.edm = edm;
+ this.aliases = aliases;
edmEntityContainer = edm.getEntityContainer();
}
@@ -100,8 +103,7 @@ public class ResourcePathParser {
UriParserSyntaxException.MessageKeys.SYNTAX);
}
- public UriInfoImpl parseDollarEntityTypeCast(final String pathSegment) throws UriParserException {
- UriInfoImpl uriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
+ public EdmEntityType parseDollarEntityTypeCast(final String pathSegment) throws UriParserException {
tokenizer = new UriTokenizer(pathSegment);
ParserHelper.requireNext(tokenizer, TokenKind.QualifiedName);
final String name = tokenizer.getText();
@@ -110,18 +112,16 @@ public class ResourcePathParser {
if (type == null) {
throw new UriParserSemanticException("Type '" + name + "' not found.",
UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, name);
- } else {
- uriInfo.setEntityTypeCast(type);
}
- return uriInfo;
+ return type;
}
- public UriInfoImpl parseCrossjoinSegment(final String pathSegment) throws UriParserException {
- UriInfoImpl uriInfo = new UriInfoImpl().setKind(UriInfoKind.crossjoin);
+ public List<String> parseCrossjoinSegment(final String pathSegment) throws UriParserException {
tokenizer = new UriTokenizer(pathSegment);
ParserHelper.requireNext(tokenizer, TokenKind.CROSSJOIN);
ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
// At least one entity-set name is mandatory. Try to fetch all.
+ List<String> entitySetNames = new ArrayList<String>();
do {
ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
final String name = tokenizer.getText();
@@ -130,12 +130,12 @@ public class ResourcePathParser {
throw new UriParserSemanticException("Expected Entity Set Name.",
UriParserSemanticException.MessageKeys.UNKNOWN_PART, name);
} else {
- uriInfo.addEntitySetName(name);
+ entitySetNames.add(name);
}
} while (tokenizer.next(TokenKind.COMMA));
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
ParserHelper.requireTokenEnd(tokenizer);
- return uriInfo;
+ return entitySetNames;
}
private UriResource ref(final UriResource previous) throws UriParserException {
@@ -180,7 +180,7 @@ public class ResourcePathParser {
if (tokenizer.next(TokenKind.OPEN)) {
final List<UriParameter> keyPredicates =
- ParserHelper.parseKeyPredicate(tokenizer, entitySetResource.getEntityType(), null);
+ ParserHelper.parseKeyPredicate(tokenizer, entitySetResource.getEntityType(), null, edm, null, aliases);
entitySetResource.setKeyPredicates(keyPredicates);
}
@@ -251,7 +251,8 @@ public class ResourcePathParser {
UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE,
structType.getFullQualifiedName().getFullQualifiedNameAsString(), name);
}
- List<UriParameter> keyPredicate = ParserHelper.parseNavigationKeyPredicate(tokenizer, navigationProperty);
+ List<UriParameter> keyPredicate =
+ ParserHelper.parseNavigationKeyPredicate(tokenizer, navigationProperty, edm, null, aliases);
ParserHelper.requireTokenEnd(tokenizer);
return new UriResourceNavigationPropertyImpl(navigationProperty)
.setKeyPredicates(keyPredicate);
@@ -320,7 +321,8 @@ public class ResourcePathParser {
((UriResourceWithKeysImpl) previousTyped).setEntryTypeFilter(type);
}
if (tokenizer.next(TokenKind.OPEN)) {
- final List<UriParameter> keys = ParserHelper.parseKeyPredicate(tokenizer, (EdmEntityType) type, null);
+ final List<UriParameter> keys =
+ ParserHelper.parseKeyPredicate(tokenizer, (EdmEntityType) type, null, edm, null, aliases);
if (previousTyped.isCollection()) {
((UriResourceWithKeysImpl) previousTyped).setKeyPredicates(keys);
} else {
@@ -359,7 +361,7 @@ public class ResourcePathParser {
private UriResource functionCall(final EdmFunctionImport edmFunctionImport,
final FullQualifiedName boundFunctionName, final FullQualifiedName bindingParameterTypeName,
final boolean isBindingParameterCollection) throws UriParserException, UriValidationException {
- final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, edm, null, false);
+ final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, edm, null, false, aliases);
final List<String> names = ParserHelper.getParameterNames(parameters);
EdmFunction function = null;
if (edmFunctionImport != null) {
@@ -379,13 +381,15 @@ public class ResourcePathParser {
UriParserSemanticException.MessageKeys.UNKNOWN_PART, boundFunctionName.getFullQualifiedNameAsString());
}
}
+ ParserHelper.validateFunctionParameters(function, parameters, edm, null, aliases);
UriResourceFunctionImpl resource = new UriResourceFunctionImpl(edmFunctionImport, function, parameters);
if (tokenizer.next(TokenKind.OPEN)) {
if (function.getReturnType() != null
&& function.getReturnType().getType().getKind() == EdmTypeKind.ENTITY
&& function.getReturnType().isCollection()) {
resource.setKeyPredicates(
- ParserHelper.parseKeyPredicate(tokenizer, (EdmEntityType) function.getReturnType().getType(), null));
+ ParserHelper.parseKeyPredicate(tokenizer,
+ (EdmEntityType) function.getReturnType().getType(), null, edm, null, aliases));
} else {
throw new UriParserSemanticException("A key is not allowed.",
UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/110c7b0e/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
index 00f3673..9ec29e3 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
@@ -123,11 +123,17 @@ public class SelectParser {
}
private FullQualifiedName parseAllOperationsInSchema(UriTokenizer tokenizer) throws UriParserException {
- final String name = tokenizer.getText();
+ final String namespace = tokenizer.getText();
if (tokenizer.next(TokenKind.DOT)) {
if (tokenizer.next(TokenKind.STAR)) {
- // TODO: Validate the namespace without loading the whole schema.
- return new FullQualifiedName(name, tokenizer.getText());
+ // Validate the namespace. Currently a namespace from a non-default schema is not supported.
+ // There is no direct access to the namespace without loading the whole schema;
+ // however, the default entity container should always be there, so its access methods can be used.
+ if (edm.getEntityContainer(new FullQualifiedName(namespace, edm.getEntityContainer().getName())) == null) {
+ throw new UriParserSemanticException("Wrong namespace '" + namespace + "'.",
+ UriParserSemanticException.MessageKeys.UNKNOWN_PART, namespace);
+ }
+ return new FullQualifiedName(namespace, tokenizer.getText());
} else {
throw new UriParserSemanticException("Expected star after dot.",
UriParserSemanticException.MessageKeys.UNKNOWN_PART, "");
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/110c7b0e/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
index 0504473..d218666 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
@@ -1311,8 +1311,18 @@ public class UriTokenizer {
|| nextJsonArrayOrObject();
}
+ /**
+ * Moves past a JSON object member if found; otherwise leaves the index unchanged.
+ * @return whether a JSON object member has been found at the current index
+ */
private boolean nextJsonMember() {
- return nextJsonString() && nextCharacter(':') && nextJsonValue();
+ final int lastGoodIndex = index;
+ if (nextJsonString() && nextCharacter(':') && nextJsonValue()) {
+ return true;
+ } else {
+ index = lastGoodIndex;
+ return false;
+ }
}
/**