You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2016/01/20 15:42:08 UTC
olingo-odata4 git commit: [OLINGO-834] small URI parser improvements
Repository: olingo-odata4
Updated Branches:
refs/heads/master 27e17aba9 -> 8537f3a51
[OLINGO-834] small URI parser improvements
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/8537f3a5
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/8537f3a5
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/8537f3a5
Branch: refs/heads/master
Commit: 8537f3a5127519555bf5e5fb8b1fb7b6e2ad3c9c
Parents: 27e17ab
Author: Klaus Straubinger <kl...@sap.com>
Authored: Wed Jan 20 15:22:42 2016 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Wed Jan 20 15:30:39 2016 +0100
----------------------------------------------------------------------
.../core/uri/parser/ExpressionParser.java | 13 +-
.../olingo/server/core/uri/parser/Parser.java | 32 ++---
.../server/core/uri/parser/ParserHelper.java | 14 +-
.../server/core/uri/parser/UriTokenizer.java | 124 +++++++++++++++---
.../core/uri/parser/search/SearchTokenizer.java | 49 +++----
.../core/uri/parser/ExpressionParserTest.java | 129 ++++++-------------
.../core/uri/parser/UriTokenizerTest.java | 15 +++
.../core/uri/parser/TestFullResourcePath.java | 5 +-
.../core/uri/parser/TestUriParserImpl.java | 46 +++----
.../core/uri/validator/UriValidatorTest.java | 4 +-
10 files changed, 230 insertions(+), 201 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8537f3a5/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 8b28f6a..1cf279e 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
@@ -343,7 +343,7 @@ public class ExpressionParser {
}
if (tokenizer.next(TokenKind.jsonArrayOrObject)) {
- // TODO: Can the type be determined?
+ // There is no obvious way how the type could be determined.
return new LiteralImpl(tokenizer.getText(), null);
}
@@ -417,9 +417,9 @@ public class ExpressionParser {
typeKind = EdmPrimitiveTypeKind.Int64;
}
} catch (final NumberFormatException e) {
- // This should never happen because the tokenizer has figured out that the literal is an integer.
- throw new UriParserSyntaxException("'" + intValueAsString + "' is not an integer.", e,
- UriParserSyntaxException.MessageKeys.SYNTAX);
+ // The number cannot be formatted wrongly because the tokenizer already checked the format
+ // but it is too large for Long and therefore too large for Edm.Int64.
+ typeKind = EdmPrimitiveTypeKind.Decimal;
}
return typeKind;
}
@@ -686,7 +686,7 @@ public class ExpressionParser {
}
} else {
// Must be a property.
- parseMemberExpression(TokenKind.ODataIdentifier, uriInfo, null, true); // TODO: Find last resource.
+ parseMemberExpression(TokenKind.ODataIdentifier, uriInfo, null, true);
}
}
@@ -996,9 +996,10 @@ public class ExpressionParser {
ParserHelper.requireNext(tokenizer, TokenKind.COLON);
lambdaVariables.addFirst(new UriResourceLambdaVarImpl(lambbdaVariable,
lastResource == null ? referringType : lastResource.getType()));
+ // The ABNF suggests that the "lambaPredicateExpr" must contain at least one lambdaVariable,
+ // so arguably this could be checked in expression parsing or later in validation.
final Expression lambdaPredicateExpr = parseExpression();
lambdaVariables.removeFirst();
- // TODO: The ABNF suggests that the "lambaPredicateExpr" must contain at least one lambdaVariable.
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
if (lastTokenKind == TokenKind.ALL) {
return new UriResourceLambdaAllImpl(lambbdaVariable, lambdaPredicateExpr);
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8537f3a5/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 34944c8..586cb10 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
@@ -18,13 +18,10 @@
*/
package org.apache.olingo.server.core.uri.parser;
-import java.util.ArrayDeque;
import java.util.Collections;
-import java.util.Deque;
import java.util.List;
import org.apache.olingo.commons.api.edm.Edm;
-import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmStructuredType;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
@@ -77,7 +74,7 @@ public class Parser {
throws UriParserException, UriValidationException {
UriInfoImpl contextUriInfo = new UriInfoImpl();
- Deque<EdmType> contextTypes = new ArrayDeque<EdmType>();
+ EdmType contextType = null;
boolean contextIsCollection = false;
List<String> pathSegmentsDecoded = UriDecoder.splitAndDecodePath(path);
@@ -107,10 +104,6 @@ public class Parser {
} else if (firstSegment.equals("$all")) {
ensureLastSegment(firstSegment, 1, numberOfSegments);
contextUriInfo.setKind(UriInfoKind.all);
- // This loads nearly the whole schema, but sooner or later '$all' needs all entity sets anyway.
- for (final EdmEntitySet entitySet : edm.getEntityContainer().getEntitySets()) {
- contextTypes.push(entitySet.getEntityType());
- }
contextIsCollection = true;
} else if (firstSegment.equals("$entity")) {
@@ -118,11 +111,9 @@ public class Parser {
final String typeCastSegment = pathSegmentsDecoded.get(1);
ensureLastSegment(typeCastSegment, 2, numberOfSegments);
contextUriInfo = new ResourcePathParser(edm).parseDollarEntityTypeCast(typeCastSegment);
- contextTypes.push(contextUriInfo.getEntityTypeCast());
+ contextType = contextUriInfo.getEntityTypeCast();
} else {
contextUriInfo.setKind(UriInfoKind.entityId);
- // The type of the entity is not known until the $id query option has been parsed.
- // TODO: Set the type (needed for the evaluation of system query options).
}
contextIsCollection = false;
@@ -166,10 +157,7 @@ public class Parser {
if (lastSegment instanceof UriResourcePartTyped) {
final UriResourcePartTyped typed = (UriResourcePartTyped) lastSegment;
- final EdmType type = ParserHelper.getTypeInformation(typed);
- if (type != null) { // could be null for, e.g., actions without return type
- contextTypes.push(type);
- }
+ contextType = ParserHelper.getTypeInformation(typed);
contextIsCollection = typed.isCollection();
}
}
@@ -186,7 +174,7 @@ public class Parser {
UriTokenizer filterTokenizer = new UriTokenizer(optionValue);
// The referring type could be a primitive type or a structured type.
systemOption = new FilterParser(edm, odata).parse(filterTokenizer,
- contextTypes.peek(),
+ contextType,
contextUriInfo.getEntitySetNames());
checkOptionEOF(filterTokenizer, optionName, optionValue);
@@ -205,12 +193,12 @@ public class Parser {
systemOption = formatOption;
} else if (optionName.equals(SystemQueryOptionKind.EXPAND.toString())) {
- if (contextTypes.peek() instanceof EdmStructuredType
+ if (contextType instanceof EdmStructuredType
|| !contextUriInfo.getEntitySetNames().isEmpty()
- || contextUriInfo.getKind() == UriInfoKind.entityId) { // TODO: Remove once the type has been set above.
+ || contextUriInfo.getKind() == UriInfoKind.all) {
UriTokenizer expandTokenizer = new UriTokenizer(optionValue);
systemOption = new ExpandParser(edm, odata).parse(expandTokenizer,
- contextTypes.peek() instanceof EdmStructuredType ? (EdmStructuredType) contextTypes.peek() : null);
+ contextType instanceof EdmStructuredType ? (EdmStructuredType) contextType : null);
checkOptionEOF(expandTokenizer, optionName, optionValue);
} else {
throw new UriValidationException("Expand is only allowed on structured types!",
@@ -235,7 +223,7 @@ public class Parser {
} else if (optionName.equals(SystemQueryOptionKind.ORDERBY.toString())) {
UriTokenizer orderByTokenizer = new UriTokenizer(optionValue);
systemOption = new OrderByParser(edm, odata).parse(orderByTokenizer,
- contextTypes.peek() instanceof EdmStructuredType ? (EdmStructuredType) contextTypes.peek() : null,
+ contextType instanceof EdmStructuredType ? (EdmStructuredType) contextType : null,
contextUriInfo.getEntitySetNames());
checkOptionEOF(orderByTokenizer, optionName, optionValue);
@@ -245,7 +233,7 @@ public class Parser {
} else if (optionName.equals(SystemQueryOptionKind.SELECT.toString())) {
UriTokenizer selectTokenizer = new UriTokenizer(optionValue);
systemOption = new SelectParser(edm).parse(selectTokenizer,
- contextTypes.peek() instanceof EdmStructuredType ? (EdmStructuredType) contextTypes.peek() : null,
+ contextType instanceof EdmStructuredType ? (EdmStructuredType) contextType : null,
contextIsCollection);
checkOptionEOF(selectTokenizer, optionName, optionValue);
@@ -297,7 +285,7 @@ public class Parser {
} else if (optionName.startsWith(AT)) {
if (contextUriInfo.getAlias(optionName) == null) {
- // TODO: Create a proper alias-value parser that can parse also common expressions.
+ // 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)) {
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8537f3a5/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 0ac888f..b0c2972 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
@@ -58,7 +58,7 @@ public class ParserHelper {
Map<TokenKind, EdmPrimitiveTypeKind> temp = new HashMap<TokenKind, EdmPrimitiveTypeKind>();
temp.put(TokenKind.BooleanValue, EdmPrimitiveTypeKind.Boolean);
temp.put(TokenKind.StringValue, EdmPrimitiveTypeKind.String);
- // TODO: Check if int64 is correct here or if it has to be decimal or single or double instead.
+ // Very large integer values are of type Edm.Decimal but this is handled elsewhere.
temp.put(TokenKind.IntegerValue, EdmPrimitiveTypeKind.Int64);
temp.put(TokenKind.GuidValue, EdmPrimitiveTypeKind.Guid);
temp.put(TokenKind.DateValue, EdmPrimitiveTypeKind.Date);
@@ -81,9 +81,8 @@ public class ParserHelper {
temp.put(TokenKind.GeometryMultiLineString, EdmPrimitiveTypeKind.GeometryMultiLineString);
temp.put(TokenKind.GeographyMultiPolygon, EdmPrimitiveTypeKind.GeographyMultiPolygon);
temp.put(TokenKind.GeometryMultiPolygon, EdmPrimitiveTypeKind.GeometryMultiPolygon);
- // TODO: Geo collections
-// temp.put(TokenKind.GeographyCollection, EdmPrimitiveTypeKind.GeographyCollection);
-// temp.put(TokenKind.GeometryCollection, EdmPrimitiveTypeKind.GeometryCollection);
+ temp.put(TokenKind.GeographyCollection, EdmPrimitiveTypeKind.GeographyCollection);
+ temp.put(TokenKind.GeometryCollection, EdmPrimitiveTypeKind.GeometryCollection);
tokenToPrimitiveType = Collections.unmodifiableMap(temp);
}
@@ -141,10 +140,9 @@ public class ParserHelper {
TokenKind.GeographyMultiLineString,
TokenKind.GeometryMultiLineString,
TokenKind.GeographyMultiPolygon,
- TokenKind.GeometryMultiPolygon);
- // TODO: Geo collections
-// TokenKind.GeographyCollection,
-// TokenKind.GeometryCollection);
+ TokenKind.GeometryMultiPolygon,
+ TokenKind.GeographyCollection,
+ TokenKind.GeometryCollection);
}
protected static List<UriParameter> parseFunctionParameters(UriTokenizer tokenizer,
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8537f3a5/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 5a48cc1..0504473 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
@@ -96,6 +96,8 @@ public class UriTokenizer {
GeometryMultiLineString,
GeographyMultiPolygon,
GeometryMultiPolygon,
+ GeographyCollection,
+ GeometryCollection,
jsonArrayOrObject,
@@ -372,6 +374,12 @@ public class UriTokenizer {
case GeometryMultiPolygon:
found = nextGeoMultiPolygon(false);
break;
+ case GeographyCollection:
+ found = nextGeoCollection(true);
+ break;
+ case GeometryCollection:
+ found = nextGeoCollection(false);
+ break;
// Complex or Collection Value
case jsonArrayOrObject:
@@ -1057,10 +1065,13 @@ public class UriTokenizer {
}
}
+ private boolean nextPoint() {
+ return nextConstantIgnoreCase("Point") && nextPointData();
+ }
+
private boolean nextGeoPoint(final boolean isGeography) {
return nextGeoPrefix(isGeography) && nextCharacter('\'')
- && nextSrid() && nextCharacter(';')
- && nextConstantIgnoreCase("Point") && nextPointData()
+ && nextSrid() && nextCharacter(';') && nextPoint()
&& nextCharacter('\'');
}
@@ -1074,7 +1085,10 @@ public class UriTokenizer {
final int lastGoodIndex = index;
if (nextCharacter('(') && nextPosition()) {
int count = 1;
+ final String firstPosition = isRing ? parseString.substring(lastGoodIndex + 1, index) : null;
+ int positionStart = -1;
while (nextCharacter(',')) {
+ positionStart = index;
if (nextPosition()) {
count++;
} else {
@@ -1082,11 +1096,17 @@ public class UriTokenizer {
return false;
}
}
- // TODO: Check that the first and last ring positions are identical.
if (count < (isRing ? 4 : 2)) {
index = lastGoodIndex;
return false;
}
+ if (isRing) {
+ final String lastPosition = parseString.substring(positionStart, index);
+ if (!lastPosition.equals(firstPosition)) {
+ index = lastGoodIndex;
+ return false;
+ }
+ }
if (!nextCharacter(')')) {
index = lastGoodIndex;
return false;
@@ -1098,10 +1118,13 @@ public class UriTokenizer {
}
}
+ private boolean nextLineString() {
+ return nextConstantIgnoreCase("LineString") && nextLineStringData(false);
+ }
+
private boolean nextGeoLineString(final boolean isGeography) {
return nextGeoPrefix(isGeography) && nextCharacter('\'')
- && nextSrid() && nextCharacter(';')
- && nextConstantIgnoreCase("LineString") && nextLineStringData(false)
+ && nextSrid() && nextCharacter(';') && nextLineString()
&& nextCharacter('\'');
}
@@ -1130,66 +1153,125 @@ public class UriTokenizer {
}
}
+ private boolean nextPolygon() {
+ return nextConstantIgnoreCase("Polygon") && nextPolygonData();
+ }
+
private boolean nextGeoPolygon(final boolean isGeography) {
return nextGeoPrefix(isGeography) && nextCharacter('\'')
- && nextSrid() && nextCharacter(';')
- && nextConstantIgnoreCase("Polygon") && nextPolygonData()
+ && nextSrid() && nextCharacter(';') && nextPolygon()
&& nextCharacter('\'');
}
private boolean nextMultiPoint() {
- if (nextPointData()) {
+ if (nextConstantIgnoreCase("MultiPoint") && nextCharacter('(') && nextPointData()) {
while (nextCharacter(',')) {
if (!nextPointData()) {
return false;
}
}
}
- return true;
+ return nextCharacter(')');
}
private boolean nextGeoMultiPoint(final boolean isGeography) {
return nextGeoPrefix(isGeography) && nextCharacter('\'')
- && nextSrid() && nextCharacter(';')
- && nextConstantIgnoreCase("MultiPoint") && nextCharacter('(') && nextMultiPoint() && nextCharacter(')')
+ && nextSrid() && nextCharacter(';') && nextMultiPoint()
&& nextCharacter('\'');
}
private boolean nextMultiLineString() {
- if (nextLineStringData(false)) {
+ if (nextConstantIgnoreCase("MultiLineString") && nextCharacter('(') && nextLineStringData(false)) {
while (nextCharacter(',')) {
if (!nextLineStringData(false)) {
return false;
}
}
}
- return true;
+ return nextCharacter(')');
}
private boolean nextGeoMultiLineString(final boolean isGeography) {
return nextGeoPrefix(isGeography) && nextCharacter('\'')
- && nextSrid() && nextCharacter(';')
- && nextConstantIgnoreCase("MultiLineString")
- && nextCharacter('(') && nextMultiLineString() && nextCharacter(')')
+ && nextSrid() && nextCharacter(';') && nextMultiLineString()
&& nextCharacter('\'');
}
private boolean nextMultiPolygon() {
- if (nextPolygonData()) {
+ if (nextConstantIgnoreCase("MultiPolygon") && nextCharacter('(') && nextPolygonData()) {
while (nextCharacter(',')) {
if (!nextPolygonData()) {
return false;
}
}
}
- return true;
+ return nextCharacter(')');
}
private boolean nextGeoMultiPolygon(final boolean isGeography) {
return nextGeoPrefix(isGeography) && nextCharacter('\'')
- && nextSrid() && nextCharacter(';')
- && nextConstantIgnoreCase("MultiPolygon")
- && nextCharacter('(') && nextMultiPolygon() && nextCharacter(')')
+ && nextSrid() && nextCharacter(';') && nextMultiPolygon()
+ && nextCharacter('\'');
+ }
+
+ /**
+ * Moves past geo data if found; otherwise leaves the index unchanged.
+ * @return whether geo data has been found at the current index
+ */
+ private boolean nextGeo() {
+ final int lastGoodIndex = index;
+ if (nextPoint()) {
+ return true;
+ } else {
+ index = lastGoodIndex;
+ }
+ if (nextLineString()) {
+ return true;
+ } else {
+ index = lastGoodIndex;
+ }
+ if (nextPolygon()) {
+ return true;
+ } else {
+ index = lastGoodIndex;
+ }
+ if (nextMultiPoint()) {
+ return true;
+ } else {
+ index = lastGoodIndex;
+ }
+ if (nextMultiLineString()) {
+ return true;
+ } else {
+ index = lastGoodIndex;
+ }
+ if (nextMultiPolygon()) {
+ return true;
+ } else {
+ index = lastGoodIndex;
+ }
+ if (nextCollection()) {
+ return true;
+ } else {
+ index = lastGoodIndex;
+ return false;
+ }
+ }
+
+ private boolean nextCollection() {
+ if (nextConstantIgnoreCase("Collection") && nextCharacter('(') && nextGeo()) {
+ while (nextCharacter(',')) {
+ if (!nextGeo()) {
+ return false;
+ }
+ }
+ }
+ return nextCharacter(')');
+ }
+
+ private boolean nextGeoCollection(final boolean isGeography) {
+ return nextGeoPrefix(isGeography) && nextCharacter('\'')
+ && nextSrid() && nextCharacter(';') && nextCollection()
&& nextCharacter('\'');
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8537f3a5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
index 4b88869..5d7c948 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -22,28 +22,20 @@ import java.util.ArrayList;
import java.util.List;
/**
- * <code>
- * searchExpr = ( OPEN BWS searchExpr BWS CLOSE
- * / searchTerm
- * ) [ searchOrExpr
- * / searchAndExpr
- * ]
- *
- * searchOrExpr = RWS 'OR' RWS searchExpr
+ * <pre>
+ * searchExpr = ( OPEN BWS searchExpr BWS CLOSE / searchTerm )
+ * [ searchOrExpr / searchAndExpr ]
+ * searchOrExpr = RWS 'OR' RWS searchExpr
* searchAndExpr = RWS [ 'AND' RWS ] searchExpr
+ * searchTerm = [ 'NOT' RWS ] ( searchPhrase / searchWord )
+ * searchPhrase = quotation-mark 1*qchar-no-AMP-DQUOTE quotation-mark
+ * searchWord = 1*ALPHA ; Actually: any character from the Unicode categories L or Nl,
+ * but not the words AND, OR, and NOT
+ * </pre>
*
- * searchTerm = [ 'NOT' RWS ] ( searchPhrase / searchWord )
- * searchPhrase = quotation-mark 1*qchar-no-AMP-DQUOTE quotation-mark
- * searchWord = 1*ALPHA ; Actually: any character from the Unicode categories L or Nl,
- * ; but not the words AND, OR, and NOT
- * </code>
- *
- * <b>ATTENTION:</b> For a <code>searchPhrase</code> the percent encoding is not supported by the
- * <code>SearchTokenizer</code>.<br/>
- * This was a decision based on that the <code>org.apache.olingo.server.core.uri.parser.Parser</code>
- * already handles in his <code>parseUri</code> method each query as <code>percent decoded</code> strings (see
- * line <i>177ff</i> (<code>for (RawUri.QueryOption option : uri.queryOptionListDecoded)</code>).
- *
+ * <b>ATTENTION:</b> This class does not support a percent-encoded <code>searchPhrase</code> because the URI parser's
+ * {@link org.apache.olingo.server.core.uri.parser.Parser#parseUri(String, String, String) parseUri} method
+ * <em>percent decodes</em> each query before calling parsers of query options.
*/
public class SearchTokenizer {
@@ -75,17 +67,18 @@ public class SearchTokenizer {
protected abstract State nextChar(char c) throws SearchTokenizerException;
+ /** @param c allowed character */
public State allowed(final char c) {
return this;
}
public State forbidden(final char c) throws SearchTokenizerException {
- throw new SearchTokenizerException("Forbidden character in state " + getToken() + "->" + c,
+ throw new SearchTokenizerException("Forbidden character in state " + token + "->" + c,
SearchTokenizerException.MessageKeys.FORBIDDEN_CHARACTER, "" + c);
}
public State invalid() throws SearchTokenizerException {
- throw new SearchTokenizerException("Token " + getToken() + " is in invalid state.",
+ throw new SearchTokenizerException("Token " + token + " is in invalid state.",
SearchTokenizerException.MessageKeys.INVALID_TOKEN_STATE);
}
@@ -243,7 +236,7 @@ public class SearchTokenizer {
@Override
public String toString() {
- return getToken() + "=>{" + getLiteral() + "}";
+ return token + "=>{" + getLiteral() + "}";
}
}
@@ -597,16 +590,14 @@ public class SearchTokenizer {
}
/**
- * Take the search query and split into according SearchQueryToken.
- * Before split into tokens the given search query is 'trimmed'.
+ * Takes the search query and splits it into a list of corresponding {@link SearchQueryToken}s.
+ * Before splitting it into tokens, leading and trailing whitespace in the given search query string is removed.
*
* @param searchQuery search query to be tokenized
* @return list of tokens
- * @throws SearchTokenizerException if something in query is not valid
- * (based on OData search query ABNF)
+ * @throws SearchTokenizerException if something in query is not valid (based on OData search query ABNF)
*/
- public List<SearchQueryToken> tokenize(final String searchQuery)
- throws SearchTokenizerException {
+ public List<SearchQueryToken> tokenize(final String searchQuery) throws SearchTokenizerException {
char[] chars = searchQuery.trim().toCharArray();
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8537f3a5/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
index c764999..a5fda50 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
+import java.util.Arrays;
import java.util.Locale;
import org.apache.olingo.commons.api.edm.Edm;
@@ -158,14 +159,9 @@ public class ExpressionParserTest {
@Test
public void noParameterMethods() throws Exception {
- Expression expression = parseMethod(TokenKind.NowMethod);
- assertEquals("{now []}", expression.toString());
-
- expression = parseMethod(TokenKind.MaxdatetimeMethod);
- assertEquals("{maxdatetime []}", expression.toString());
-
- expression = parseMethod(TokenKind.MindatetimeMethod);
- assertEquals("{mindatetime []}", expression.toString());
+ parseMethod(TokenKind.NowMethod);
+ parseMethod(TokenKind.MaxdatetimeMethod);
+ parseMethod(TokenKind.MindatetimeMethod);
wrongExpression("now(1)");
}
@@ -176,46 +172,21 @@ public class ExpressionParserTest {
final String dateValue = "1234-12-25";
final String dateTimeOffsetValue = "1234-12-25T11:12:13.456Z";
- Expression expression = parseMethod(TokenKind.LengthMethod, stringValue);
- assertEquals("{length [" + stringValue + "]}", expression.toString());
-
- expression = parseMethod(TokenKind.TolowerMethod, stringValue);
- assertEquals("{tolower [" + stringValue + "]}", expression.toString());
-
- expression = parseMethod(TokenKind.ToupperMethod, stringValue);
- assertEquals("{toupper [" + stringValue + "]}", expression.toString());
-
- expression = parseMethod(TokenKind.TrimMethod, stringValue);
- assertEquals("{trim [" + stringValue + "]}", expression.toString());
-
- expression = parseMethod(TokenKind.YearMethod, dateValue);
- assertEquals("{year [" + dateValue + "]}", expression.toString());
-
- expression = parseMethod(TokenKind.MonthMethod, dateValue);
- assertEquals("{month [" + dateValue + "]}", expression.toString());
-
- expression = parseMethod(TokenKind.DayMethod, dateValue);
- assertEquals("{day [" + dateValue + "]}", expression.toString());
-
- expression = parseMethod(TokenKind.HourMethod, dateTimeOffsetValue);
- assertEquals("{hour [" + dateTimeOffsetValue + "]}", expression.toString());
-
- expression = parseMethod(TokenKind.MinuteMethod, dateTimeOffsetValue);
- assertEquals("{minute [" + dateTimeOffsetValue + "]}", expression.toString());
-
- expression = parseMethod(TokenKind.SecondMethod, dateTimeOffsetValue);
- assertEquals("{second [" + dateTimeOffsetValue + "]}", expression.toString());
-
- expression = parseMethod(TokenKind.DateMethod, dateTimeOffsetValue);
- assertEquals("{date [" + dateTimeOffsetValue + "]}", expression.toString());
-
- expression = parseMethod(TokenKind.TotalsecondsMethod, "duration'PT1H'");
- assertEquals("{totalseconds [duration'PT1H']}", expression.toString());
-
- expression = parseMethod(TokenKind.RoundMethod, "3.141592653589793");
- assertEquals("{round [3.141592653589793]}", expression.toString());
-
- assertEquals("{hour [null]}", parseMethod(TokenKind.HourMethod, new String[] { null }).toString());
+ parseMethod(TokenKind.LengthMethod, stringValue);
+ parseMethod(TokenKind.TolowerMethod, stringValue);
+ parseMethod(TokenKind.ToupperMethod, stringValue);
+ parseMethod(TokenKind.TrimMethod, stringValue);
+ parseMethod(TokenKind.YearMethod, dateValue);
+ parseMethod(TokenKind.MonthMethod, dateValue);
+ parseMethod(TokenKind.DayMethod, dateValue);
+ parseMethod(TokenKind.HourMethod, dateTimeOffsetValue);
+ parseMethod(TokenKind.MinuteMethod, dateTimeOffsetValue);
+ parseMethod(TokenKind.SecondMethod, dateTimeOffsetValue);
+ parseMethod(TokenKind.DateMethod, dateTimeOffsetValue);
+ parseMethod(TokenKind.TotalsecondsMethod, "duration'PT1H'");
+ parseMethod(TokenKind.RoundMethod, "3.141592653589793");
+ parseMethod(TokenKind.GeoLengthMethod, "geometry'SRID=0;LineString(0 0,4 0,4 4,0 4,0 0)'");
+ parseMethod(TokenKind.HourMethod, new String[] { null });
wrongExpression("trim()");
wrongExpression("trim(1)");
@@ -224,35 +195,17 @@ public class ExpressionParserTest {
@Test
public void twoParameterMethods() throws Exception {
- Expression expression = parseMethod(TokenKind.ContainsMethod, "'a'", "'b'");
- assertEquals("{contains ['a', 'b']}", expression.toString());
-
- expression = parseMethod(TokenKind.EndswithMethod, "'a'", "'b'");
- assertEquals("{endswith ['a', 'b']}", expression.toString());
-
- expression = parseMethod(TokenKind.StartswithMethod, "'a'", "'b'");
- assertEquals("{startswith ['a', 'b']}", expression.toString());
-
- expression = parseMethod(TokenKind.IndexofMethod, "'a'", "'b'");
- assertEquals("{indexof ['a', 'b']}", expression.toString());
-
- expression = parseMethod(TokenKind.ConcatMethod, "'a'", "'b'");
- assertEquals("{concat ['a', 'b']}", expression.toString());
-
- expression = parseMethod(TokenKind.GeoDistanceMethod,
- "geography'SRID=0;Point(1.2 3.4)'", "geography'SRID=0;Point(5.6 7.8)'");
- assertEquals("{geo.distance [geography'SRID=0;Point(1.2 3.4)', geography'SRID=0;Point(5.6 7.8)']}",
- expression.toString());
-
- expression = parseMethod(TokenKind.GeoIntersectsMethod,
+ parseMethod(TokenKind.ContainsMethod, "'a'", "'b'");
+ parseMethod(TokenKind.EndswithMethod, "'a'", "'b'");
+ parseMethod(TokenKind.StartswithMethod, "'a'", "'b'");
+ parseMethod(TokenKind.IndexofMethod, "'a'", "'b'");
+ parseMethod(TokenKind.ConcatMethod, "'a'", "'b'");
+ parseMethod(TokenKind.GeoDistanceMethod, "geography'SRID=0;Point(1.2 3.4)'", "geography'SRID=0;Point(5.6 7.8)'");
+ parseMethod(TokenKind.GeoIntersectsMethod,
"geometry'SRID=0;Point(1.2 3.4)'",
"geometry'SRID=0;Polygon((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1))'");
- assertEquals("{geo.intersects [geometry'SRID=0;Point(1.2 3.4)', "
- + "geometry'SRID=0;Polygon((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1))']}",
- expression.toString());
-
- assertEquals("{startswith [null, 'b']}", parseMethod(TokenKind.StartswithMethod, null, "'b'").toString());
- assertEquals("{indexof ['a', null]}", parseMethod(TokenKind.IndexofMethod, "'a'", null).toString());
+ parseMethod(TokenKind.StartswithMethod, null, "'b'");
+ parseMethod(TokenKind.IndexofMethod, "'a'", null);
wrongExpression("concat('a')");
wrongExpression("endswith('a',1)");
@@ -260,16 +213,14 @@ public class ExpressionParserTest {
@Test
public void variableParameterNumberMethods() throws Exception {
- Expression expression = parseMethod(TokenKind.SubstringMethod, "'abc'", "1", "2");
- assertEquals("{substring ['abc', 1, 2]}", expression.toString());
- expression = parseMethod(TokenKind.SubstringMethod, "'abc'", "1");
- assertEquals("{substring ['abc', 1]}", expression.toString());
+ parseMethod(TokenKind.SubstringMethod, "'abc'", "1", "2");
+ parseMethod(TokenKind.SubstringMethod, "'abc'", "1");
- assertEquals("{cast [Edm.SByte]}", parseMethod(TokenKind.CastMethod, "Edm.SByte").toString());
- assertEquals("{cast [42, Edm.SByte]}", parseMethod(TokenKind.CastMethod, "42", "Edm.SByte").toString());
+ parseMethod(TokenKind.CastMethod, "Edm.SByte");
+ parseMethod(TokenKind.CastMethod, "42", "Edm.SByte");
- assertEquals("{isof [Edm.SByte]}", parseMethod(TokenKind.IsofMethod, "Edm.SByte").toString());
- assertEquals("{isof [42, Edm.SByte]}", parseMethod(TokenKind.IsofMethod, "42", "Edm.SByte").toString());
+ parseMethod(TokenKind.IsofMethod, "Edm.SByte");
+ parseMethod(TokenKind.IsofMethod, "42", "Edm.SByte");
wrongExpression("substring('abc')");
wrongExpression("substring('abc',1,2,3)");
@@ -278,10 +229,10 @@ public class ExpressionParserTest {
wrongExpression("isof(Edm.Int16,2)");
}
- private Expression parseMethod(TokenKind kind, String... parameters)
- throws UriParserException, UriValidationException {
- String expressionString = kind.name().substring(0, kind.name().indexOf("Method"))
- .toLowerCase(Locale.ROOT).replace("geo", "geo.") + '(';
+ private void parseMethod(TokenKind kind, String... parameters) throws UriParserException, UriValidationException {
+ final String methodName = kind.name().substring(0, kind.name().indexOf("Method")).toLowerCase(Locale.ROOT)
+ .replace("geo", "geo.");
+ String expressionString = methodName + '(';
boolean first = true;
for (final String parameter : parameters) {
if (first) {
@@ -293,7 +244,9 @@ public class ExpressionParserTest {
}
expressionString += ')';
- return parseExpression(expressionString);
+ final Expression expression = parseExpression(expressionString);
+ assertEquals('{' + methodName + ' ' + Arrays.toString(parameters) + '}',
+ expression.toString());
}
private Expression parseExpression(final String expressionString)
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8537f3a5/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
index 78c6204..3ca49c8 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
@@ -624,6 +624,21 @@ public class UriTokenizerTest {
'x');
}
+ @Test
+ public void geoCollection() {
+ assertTrue(new UriTokenizer("geography'SRID=4326;Collection(Point(1 2))'").next(TokenKind.GeographyCollection));
+ assertTrue(new UriTokenizer("geography'SRID=4326;Collection(Collection(Point(1 2),Point(3 4)))'")
+ .next(TokenKind.GeographyCollection));
+ assertTrue(new UriTokenizer("geography'SRID=4326;Collection(LineString(1 2,3 4))'")
+ .next(TokenKind.GeographyCollection));
+ assertTrue(new UriTokenizer("geography'SRID=4326;Collection(Polygon((0 0,1 0,0 1,0 0)))'")
+ .next(TokenKind.GeographyCollection));
+ assertTrue(new UriTokenizer("geography'SRID=4326;Collection(MultiPoint(),MultiLineString(),MultiPolygon())'")
+ .next(TokenKind.GeographyCollection));
+
+ wrongToken(TokenKind.GeometryCollection, "geometry'SRID=0;Collection(Point(1 2),Point(3 4))'", 'x');
+ }
+
private void wrongToken(final TokenKind kind, final String value, final char disturbCharacter) {
assertFalse(new UriTokenizer(disturbCharacter + value).next(kind));
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8537f3a5/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/TestFullResourcePath.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/TestFullResourcePath.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/TestFullResourcePath.java
index 828be80..5a03676 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/TestFullResourcePath.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/TestFullResourcePath.java
@@ -5698,12 +5698,13 @@ public class TestFullResourcePath {
.root()
.right().isLiteral("3.4E37").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Double));
- testFilter.runOnETAllPrim("15.55555555555555555555555555555555555555555555 eq 3.1")
+ testFilter.runOnETAllPrim("15.55555555555555555555555555555555555555555555 eq -12345678901234567890")
.isBinary(BinaryOperatorKind.EQ)
.left().isLiteral("15.55555555555555555555555555555555555555555555")
.isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal))
.root()
- .right().isLiteral("3.1").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal));
+ .right().isLiteral("-12345678901234567890")
+ .isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal));
testFilter.runOnETAllPrim("duration'PT1H2S' eq duration'PT3602S'")
.isBinary(BinaryOperatorKind.EQ)
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8537f3a5/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/TestUriParserImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/TestUriParserImpl.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/TestUriParserImpl.java
index 138e598..1b8c398 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/TestUriParserImpl.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/TestUriParserImpl.java
@@ -225,74 +225,74 @@ public class TestUriParserImpl {
@Test
public void entityFailOnValidation() throws Exception {
// simple entity set; with qualifiedentityTypeName; with filter
- testUri.runEx("$entity/olingo.odata.test1.ETTwoPrim", "$filter=PropertyInt16 eq 123&$id=ESAllKey")
+ testUri.runEx("$entity/olingo.odata.test1.ETTwoPrim", "$filter=PropertyInt16 eq 123&$id=ESAllPrim(1)")
.isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
}
@Test
public void entity() throws Exception {
// simple entity set
- testUri.run("$entity", "$id=ESAllPrim").isKind(UriInfoKind.entityId)
+ testUri.run("$entity", "$id=ESAllPrim(1)").isKind(UriInfoKind.entityId)
.isKind(UriInfoKind.entityId)
- .isIdText("ESAllPrim");
+ .isIdText("ESAllPrim(1)");
// simple entity set; $format before $id
- testUri.run("$entity", "$format=xml&$id=ETAllPrim").isKind(UriInfoKind.entityId)
+ testUri.run("$entity", "$format=xml&$id=ESAllPrim(1)").isKind(UriInfoKind.entityId)
.isFormatText("xml")
- .isIdText("ETAllPrim");
+ .isIdText("ESAllPrim(1)");
- testUri.run("$entity", "$format=xml&abc=123&$id=ESAllKey").isKind(UriInfoKind.entityId)
+ testUri.run("$entity", "$format=xml&abc=123&$id=ESAllPrim(1)").isKind(UriInfoKind.entityId)
.isFormatText("xml")
.isCustomParameter(0, "abc", "123")
- .isIdText("ESAllKey");
+ .isIdText("ESAllPrim(1)");
// simple entity set; $format after $id
- testUri.run("$entity", "$id=ETAllPrim&$format=xml").isKind(UriInfoKind.entityId)
- .isIdText("ETAllPrim")
+ testUri.run("$entity", "$id=ESAllPrim(1)&$format=xml").isKind(UriInfoKind.entityId)
+ .isIdText("ESAllPrim(1)")
.isFormatText("xml");
// simple entity set; $format and custom parameter after $id
- testUri.run("$entity", "$id=ETAllPrim&$format=xml&abc=123").isKind(UriInfoKind.entityId)
- .isIdText("ETAllPrim")
+ testUri.run("$entity", "$id=ESAllPrim(1)&$format=xml&abc=123").isKind(UriInfoKind.entityId)
+ .isIdText("ESAllPrim(1)")
.isFormatText("xml")
.isCustomParameter(0, "abc", "123");
// simple entity set; $format before $id and custom parameter after $id
- testUri.run("$entity", "$format=xml&$id=ETAllPrim&abc=123").isKind(UriInfoKind.entityId)
+ testUri.run("$entity", "$format=xml&$id=ESAllPrim(1)&abc=123").isKind(UriInfoKind.entityId)
.isFormatText("xml")
- .isIdText("ETAllPrim")
+ .isIdText("ESAllPrim(1)")
.isCustomParameter(0, "abc", "123");
// simple entity set; with qualifiedentityTypeName
- testUri.run("$entity/olingo.odata.test1.ETTwoPrim", "$id=ESBase")
+ testUri.run("$entity/olingo.odata.test1.ETTwoPrim", "$id=ESBase(111)")
.isEntityType(EntityTypeProvider.nameETTwoPrim)
- .isIdText("ESBase");
+ .isIdText("ESBase(111)");
// simple entity set; with qualifiedentityTypeName;
- testUri.run("$entity/olingo.odata.test1.ETBase", "$id=ESTwoPrim")
+ testUri.run("$entity/olingo.odata.test1.ETBase", "$id=ESTwoPrim(1)")
.isEntityType(EntityTypeProvider.nameETBase)
.isKind(UriInfoKind.entityId)
- .isIdText("ESTwoPrim");
+ .isIdText("ESTwoPrim(1)");
// simple entity set; with qualifiedentityTypeName; with format
- testUri.run("$entity/olingo.odata.test1.ETBase", "$id=ESTwoPrim&$format=atom")
+ testUri.run("$entity/olingo.odata.test1.ETBase", "$id=ESTwoPrim(1)&$format=atom")
.isKind(UriInfoKind.entityId)
.isEntityType(EntityTypeProvider.nameETBase)
- .isIdText("ESTwoPrim")
+ .isIdText("ESTwoPrim(1)")
.isFormatText("atom");
// simple entity set; with qualifiedentityTypeName; with select
- testUri.run("$entity/olingo.odata.test1.ETBase", "$id=ESTwoPrim&$select=*")
+ testUri.run("$entity/olingo.odata.test1.ETBase", "$id=ESTwoPrim(1)&$select=*")
.isKind(UriInfoKind.entityId)
.isEntityType(EntityTypeProvider.nameETBase)
- .isIdText("ESTwoPrim")
+ .isIdText("ESTwoPrim(1)")
.isSelectItemStar(0);
// simple entity set; with qualifiedentityTypeName; with expand
- testUri.run("$entity/olingo.odata.test1.ETBase", "$id=ESTwoPrim&$expand=*")
+ testUri.run("$entity/olingo.odata.test1.ETBase", "$id=ESTwoPrim(1)&$expand=*")
.isKind(UriInfoKind.entityId)
.isEntityType(EntityTypeProvider.nameETBase)
- .isIdText("ESTwoPrim")
+ .isIdText("ESTwoPrim(1)")
.goExpand().first().isSegmentStar();
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8537f3a5/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java
index 868f9b8..673b8ff 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java
@@ -52,7 +52,7 @@ public class UriValidatorTest {
private static final String URI_ALL = "$all";
private static final String URI_BATCH = "$batch";
private static final String URI_CROSSJOIN = "$crossjoin(ESAllPrim)";
- private static final String URI_ENTITY_ID = "$entity";
+ private static final String URI_ENTITY_ID = "$entity/Namespace1_Alias.ETBase";
private static final String URI_METADATA = "$metadata";
private static final String URI_SERVICE = "";
private static final String URI_ENTITY_SET = "ESAllPrim";
@@ -81,7 +81,7 @@ public class UriValidatorTest {
private static final String QO_FILTER = "$filter='1' eq '1'";
private static final String QO_FORMAT = "$format=bla/bla";
private static final String QO_EXPAND = "$expand=*";
- private static final String QO_ID = "$id=Products(0)";
+ private static final String QO_ID = "$id=ESAllPrim(1)";
private static final String QO_COUNT = "$count=true";
private static final String QO_ORDERBY = "$orderby=true";
private static final String QO_SEARCH = "$search=bla";