[OLINGO-834] $select parser in Java + clean-up

Signed-off-by: Christian Amend <christian.amend@sap.com>
This commit is contained in:
Klaus Straubinger 2015-12-10 14:56:58 +01:00 committed by Christian Amend
parent ef19c9be1f
commit d7e23bf89a
19 changed files with 993 additions and 1166 deletions

View File

@ -1,60 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.uri.parser;
import java.util.BitSet;
import org.antlr.v4.runtime.DiagnosticErrorListener;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import org.antlr.v4.runtime.atn.ATNConfigSet;
import org.antlr.v4.runtime.dfa.DFA;
class CheckFullContextListener extends DiagnosticErrorListener {
@Override
public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol, final int line,
final int charPositionInLine,
final String msg, final RecognitionException e) {
// System.err.println("syntaxError detected");
}
@Override
public void reportAmbiguity(final Parser recognizer, final DFA dfa, final int startIndex, final int stopIndex,
final boolean exact,
final BitSet ambigAlts, final ATNConfigSet configs) {
// System.err.println("reportAmbiguity detected");
}
@Override
public void reportAttemptingFullContext(final Parser recognizer, final DFA dfa, final int startIndex,
final int stopIndex,
final BitSet conflictingAlts, final ATNConfigSet configs) {
// System.err.println("reportAttemptingFullContext detected");
}
@Override
public void reportContextSensitivity(final Parser recognizer, final DFA dfa, final int startIndex,
final int stopIndex, final int prediction,
final ATNConfigSet configs) {
// System.err.println("reportContextSensitivity detected");
}
}

View File

@ -26,11 +26,13 @@ import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.atn.PredictionMode;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmEntityContainer;
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;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.uri.UriInfo;
@ -45,28 +47,28 @@ import org.apache.olingo.server.api.uri.UriResourceValue;
import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
import org.apache.olingo.server.api.uri.queryoption.CustomQueryOption;
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
import org.apache.olingo.server.api.uri.queryoption.QueryOption;
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOption;
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.core.uri.UriInfoImpl;
import org.apache.olingo.server.core.uri.UriResourceStartingTypeFilterImpl;
import org.apache.olingo.server.core.uri.UriResourceTypedImpl;
import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
import org.apache.olingo.server.core.uri.antlr.UriLexer;
import org.apache.olingo.server.core.uri.antlr.UriParserParser;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemsEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.FilterExpressionEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.SelectEOFContext;
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.CustomQueryOptionImpl;
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.TopOptionImpl;
@ -79,12 +81,11 @@ public class Parser {
private static final String AT = "@";
private static final String NULL = "null";
int logLevel = 0;
private final Edm edm;
private final OData odata;
private enum ParserEntryRules {
ExpandItems, FilterExpression, Orderby, Select
ExpandItems, FilterExpression, Orderby
}
public Parser(final Edm edm, final OData odata) {
@ -98,242 +99,268 @@ public class Parser {
UriContext context = new UriContext();
UriParseTreeVisitor uriParseTreeVisitor = new UriParseTreeVisitor(edm, context);
try {
final RawUri uri = UriDecoder.decodeUri(path, query, fragment, 0); // -> 0 segments are before the service url
final List<String> pathSegmentsDecoded = UriDecoder.splitAndDecodePath(path);
final int numberOfSegments = pathSegmentsDecoded.size();
// first, read the decoded path segments
final String firstSegment = uri.pathSegmentListDecoded.isEmpty() ? "" : uri.pathSegmentListDecoded.get(0);
// first, read the decoded path segments
final String firstSegment = numberOfSegments == 0 ? "" : pathSegmentsDecoded.get(0);
if (firstSegment.isEmpty()) {
ensureLastSegment(firstSegment, 0, uri.pathSegmentListDecoded.size());
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.service);
if (firstSegment.isEmpty()) {
ensureLastSegment(firstSegment, 0, numberOfSegments);
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.service);
} else if (firstSegment.equals("$batch")) {
ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.batch);
} else if (firstSegment.equals("$batch")) {
ensureLastSegment(firstSegment, 1, numberOfSegments);
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.batch);
} else if (firstSegment.equals("$metadata")) {
ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.metadata);
context.contextUriInfo.setFragment(uri.fragment);
} else if (firstSegment.equals("$metadata")) {
ensureLastSegment(firstSegment, 1, numberOfSegments);
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.metadata);
context.contextUriInfo.setFragment(fragment);
} else if (firstSegment.equals("$all")) {
ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.all);
} else if (firstSegment.equals("$all")) {
ensureLastSegment(firstSegment, 1, numberOfSegments);
context.contextUriInfo = new UriInfoImpl().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()) {
context.contextTypes.push(entitySet.getEntityType());
}
context.isCollection = true;
} else if (firstSegment.equals("$entity")) {
if (numberOfSegments > 1) {
final String typeCastSegment = pathSegmentsDecoded.get(1);
ensureLastSegment(typeCastSegment, 2, numberOfSegments);
context.contextUriInfo = new ResourcePathParser(edm, odata).parseDollarEntityTypeCast(typeCastSegment);
context.contextTypes.push(context.contextUriInfo.getEntityTypeCast());
} else {
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
// The type of the entity is not known until the $id query option has been parsed.
}
context.isCollection = false;
} else if (firstSegment.startsWith("$crossjoin")) {
ensureLastSegment(firstSegment, 1, numberOfSegments);
context.contextUriInfo = new ResourcePathParser(edm, odata).parseCrossjoinSegment(firstSegment);
final EdmEntityContainer container = edm.getEntityContainer();
for (final String name : context.contextUriInfo.getEntitySetNames()) {
context.contextTypes.push(container.getEntitySet(name).getEntityType());
}
context.isCollection = true;
} else {
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
final ResourcePathParser resourcePathParser = new ResourcePathParser(edm, odata);
int count = 0;
UriResource lastSegment = null;
for (final String pathSegment : pathSegmentsDecoded) {
count++;
final UriResource segment = resourcePathParser.parsePathSegment(pathSegment, lastSegment);
if (segment != null) {
if (segment instanceof UriResourceCount
|| segment instanceof UriResourceRef
|| segment instanceof UriResourceValue) {
ensureLastSegment(pathSegment, count, numberOfSegments);
} else if (segment instanceof UriResourceAction
|| segment instanceof UriResourceFunction
&& !((UriResourceFunction) segment).getFunction().isComposable()) {
if (count < numberOfSegments) {
throw new UriValidationException(
"The segment of an action or of a non-composable function must be the last resource-path segment.",
UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH,
pathSegmentsDecoded.get(count));
}
lastSegment = segment;
} else if (segment instanceof UriResourceStartingTypeFilterImpl) {
throw new UriParserSemanticException("First resource-path segment must not be namespace-qualified.",
UriParserSemanticException.MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT);
} else {
lastSegment = segment;
}
context.contextUriInfo.addResourcePart(segment);
}
}
if (lastSegment instanceof UriResourcePartTyped) {
final UriResourcePartTyped typed = (UriResourcePartTyped) lastSegment;
final EdmType type = getTypeInformation(typed);
if (type != null) { // could be null for, e.g., actions without return type
context.contextTypes.push(type);
}
context.isCollection = typed.isCollection();
}
}
// second, read the system query options and the custom query options
final List<QueryOption> options = UriDecoder.splitAndDecodeOptions(query);
for (final QueryOption option : options) {
final String optionName = option.getName();
final String optionValue = option.getText();
if (optionName.startsWith("$")) {
SystemQueryOption systemOption = null;
if (optionName.equals(SystemQueryOptionKind.FILTER.toString())) {
try {
FilterExpressionEOFContext ctxFilterExpression =
(FilterExpressionEOFContext) parseRule(optionValue, ParserEntryRules.FilterExpression);
systemOption = (FilterOptionImpl) uriParseTreeVisitor.visitFilterExpressionEOF(ctxFilterExpression);
} catch (final ParseCancellationException e) {
throw e.getCause() instanceof UriParserException ?
(UriParserException) e.getCause() :
new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
}
} 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())) {
try {
ExpandItemsEOFContext ctxExpandItems =
(ExpandItemsEOFContext) parseRule(optionValue, ParserEntryRules.ExpandItems);
systemOption = (ExpandOptionImpl) uriParseTreeVisitor.visitExpandItemsEOF(ctxExpandItems);
} catch (final ParseCancellationException e) {
throw e.getCause() instanceof UriParserException ?
(UriParserException) e.getCause() :
new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
}
} else if (optionName.equals(SystemQueryOptionKind.ID.toString())) {
IdOptionImpl idOption = new IdOptionImpl();
idOption.setText(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())) {
try {
OrderByEOFContext ctxOrderByExpression =
(OrderByEOFContext) parseRule(optionValue, ParserEntryRules.Orderby);
systemOption = (OrderByOptionImpl) uriParseTreeVisitor.visitOrderByEOF(ctxOrderByExpression);
} catch (final ParseCancellationException e) {
throw e.getCause() instanceof UriParserException ?
(UriParserException) e.getCause() :
new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
}
} 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,
context.contextTypes.peek() instanceof EdmStructuredType ?
(EdmStructuredType) context.contextTypes.peek() :
null,
context.isCollection);
if (!selectTokenizer.next(TokenKind.EOF)) {
throw new UriParserSyntaxException("Illegal value of $select option!",
UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
optionName, optionValue);
}
} else if (optionName.equals(SystemQueryOptionKind.SKIP.toString())) {
SkipOptionImpl skipOption = new SkipOptionImpl();
skipOption.setText(optionValue);
try {
skipOption.setValue(Integer.parseInt(optionValue));
} catch (final NumberFormatException e) {
throw new UriParserSyntaxException("Illegal value of $skip option!", e,
UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
optionName, optionValue);
}
systemOption = skipOption;
} else if (optionName.equals(SystemQueryOptionKind.SKIPTOKEN.toString())) {
SkipTokenOptionImpl skipTokenOption = new SkipTokenOptionImpl();
skipTokenOption.setText(optionValue);
skipTokenOption.setValue(optionValue);
systemOption = skipTokenOption;
} else if (optionName.equals(SystemQueryOptionKind.TOP.toString())) {
TopOptionImpl topOption = new TopOptionImpl();
topOption.setText(optionValue);
try {
topOption.setValue(Integer.parseInt(optionValue));
} catch (final NumberFormatException e) {
throw new UriParserSyntaxException("Illegal value of $top option!", e,
UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
optionName, optionValue);
}
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;
} else if (firstSegment.equals("$entity")) {
if (uri.pathSegmentListDecoded.size() > 1) {
final String typeCastSegment = uri.pathSegmentListDecoded.get(1);
ensureLastSegment(typeCastSegment, 2, uri.pathSegmentListDecoded.size());
context.contextUriInfo = new ResourcePathParser(edm, odata).parseDollarEntityTypeCast(typeCastSegment);
context.contextTypes.push(
uriParseTreeVisitor.new TypeInformation(context.contextUriInfo.getEntityTypeCast(), false));
} else {
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
throw new UriParserSyntaxException("Unknown system query option!",
UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION, optionName);
}
try {
context.contextUriInfo.setSystemQueryOption(systemOption);
} catch (final ODataRuntimeException e) {
throw new UriParserSyntaxException("Double system query option!", e,
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, optionName);
}
} else if (firstSegment.startsWith("$crossjoin")) {
ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
context.contextUriInfo = new ResourcePathParser(edm, odata)
.parseCrossjoinSegment(uri.pathSegmentListDecoded.get(0));
final EdmEntityContainer container = edm.getEntityContainer();
for (final String name : context.contextUriInfo.getEntitySetNames()) {
context.contextTypes.push(
uriParseTreeVisitor.new TypeInformation(container.getEntitySet(name).getEntityType(), true));
} else if (optionName.startsWith(AT)) {
if (context.contextUriInfo.getAlias(optionName) == null) {
// TODO: Create a proper alias-value parser that can parse also common expressions.
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 {
try {
final FilterExpressionEOFContext filterExpCtx =
(FilterExpressionEOFContext) parseRule(optionValue, ParserEntryRules.FilterExpression);
expression = ((FilterOption) uriParseTreeVisitor.visitFilterExpressionEOF(filterExpCtx))
.getExpression();
} catch (final ParseCancellationException e) {
throw e.getCause() instanceof UriParserException ?
(UriParserException) e.getCause() :
new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
}
}
context.contextUriInfo.addAlias((AliasQueryOption) new AliasQueryOptionImpl()
.setAliasValue(expression)
.setName(optionName)
.setText(NULL.equals(optionValue) ? null : optionValue));
} else {
throw new UriParserSyntaxException("Alias already specified! Name: " + optionName,
UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS, optionName);
}
} else {
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
final ResourcePathParser resourcePathParser = new ResourcePathParser(edm, odata);
int count = 0;
UriResource lastSegment = null;
for (final String pathSegment : uri.pathSegmentListDecoded) {
count++;
final UriResource segment = resourcePathParser.parsePathSegment(pathSegment, lastSegment);
if (segment != null) {
if (segment instanceof UriResourceCount
|| segment instanceof UriResourceRef
|| segment instanceof UriResourceValue) {
ensureLastSegment(pathSegment, count, uri.pathSegmentListDecoded.size());
} else if (segment instanceof UriResourceAction
|| segment instanceof UriResourceFunction
&& !((UriResourceFunction) segment).getFunction().isComposable()) {
if (count < uri.pathSegmentListDecoded.size()) {
throw new UriValidationException(
"The segment of an action or of a non-composable function must be the last resource-path segment.",
UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH,
uri.pathSegmentListDecoded.get(count));
}
lastSegment = segment;
} else if (segment instanceof UriResourceStartingTypeFilterImpl) {
throw new UriParserSemanticException("First resource-path segment must not be namespace-qualified.",
UriParserSemanticException.MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT);
} else {
lastSegment = segment;
}
context.contextUriInfo.addResourcePart(segment);
}
}
if (lastSegment instanceof UriResourcePartTyped) {
UriResourcePartTyped typed = (UriResourcePartTyped) lastSegment;
UriParseTreeVisitor.TypeInformation myType = uriParseTreeVisitor.getTypeInformation(typed);
UriParseTreeVisitor.TypeInformation typeInfo =
uriParseTreeVisitor.new TypeInformation(myType.type, typed.isCollection());
context.contextTypes.push(typeInfo);
}
context.contextUriInfo.addCustomQueryOption((CustomQueryOption) option);
}
// second, read the system query options and the custom query options
for (final RawUri.QueryOption option : uri.queryOptionListDecoded) {
if (option.name.startsWith("$")) {
SystemQueryOption systemOption = null;
if (option.name.equals(SystemQueryOptionKind.FILTER.toString())) {
FilterExpressionEOFContext ctxFilterExpression =
(FilterExpressionEOFContext) parseRule(option.value, ParserEntryRules.FilterExpression);
systemOption = (FilterOptionImpl) uriParseTreeVisitor.visitFilterExpressionEOF(ctxFilterExpression);
} else if (option.name.equals(SystemQueryOptionKind.FORMAT.toString())) {
FormatOptionImpl formatOption = new FormatOptionImpl();
formatOption.setName(option.name);
formatOption.setText(option.value);
if (option.value.equalsIgnoreCase(JSON)
|| option.value.equalsIgnoreCase(XML)
|| option.value.equalsIgnoreCase(ATOM)
|| isFormatSyntaxValid(option.value)) {
formatOption.setFormat(option.value);
} else {
throw new UriParserSyntaxException("Illegal value of $format option!",
UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT, option.value);
}
systemOption = formatOption;
} else if (option.name.equals(SystemQueryOptionKind.EXPAND.toString())) {
ExpandItemsEOFContext ctxExpandItems =
(ExpandItemsEOFContext) parseRule(option.value, ParserEntryRules.ExpandItems);
systemOption = (ExpandOptionImpl) uriParseTreeVisitor.visitExpandItemsEOF(ctxExpandItems);
} else if (option.name.equals(SystemQueryOptionKind.ID.toString())) {
IdOptionImpl idOption = new IdOptionImpl();
idOption.setName(option.name);
idOption.setText(option.value);
idOption.setValue(option.value);
systemOption = idOption;
} else if (option.name.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 (option.name.equals(SystemQueryOptionKind.ORDERBY.toString())) {
OrderByEOFContext ctxOrderByExpression =
(OrderByEOFContext) parseRule(option.value, ParserEntryRules.Orderby);
systemOption = (OrderByOptionImpl) uriParseTreeVisitor.visitOrderByEOF(ctxOrderByExpression);
} else if (option.name.equals(SystemQueryOptionKind.SEARCH.toString())) {
systemOption = new SearchParser().parse(option.value);
} else if (option.name.equals(SystemQueryOptionKind.SELECT.toString())) {
SelectEOFContext ctxSelectEOF =
(SelectEOFContext) parseRule(option.value, ParserEntryRules.Select);
systemOption = (SelectOptionImpl) uriParseTreeVisitor.visitSelectEOF(ctxSelectEOF);
} else if (option.name.equals(SystemQueryOptionKind.SKIP.toString())) {
SkipOptionImpl skipOption = new SkipOptionImpl();
skipOption.setName(option.name);
skipOption.setText(option.value);
try {
skipOption.setValue(Integer.parseInt(option.value));
} catch (final NumberFormatException e) {
throw new UriParserSyntaxException("Illegal value of $skip option!", e,
UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
option.name, option.value);
}
systemOption = skipOption;
} else if (option.name.equals(SystemQueryOptionKind.SKIPTOKEN.toString())) {
SkipTokenOptionImpl skipTokenOption = new SkipTokenOptionImpl();
skipTokenOption.setName(option.name);
skipTokenOption.setText(option.value);
skipTokenOption.setValue(option.value);
systemOption = skipTokenOption;
} else if (option.name.equals(SystemQueryOptionKind.TOP.toString())) {
TopOptionImpl topOption = new TopOptionImpl();
topOption.setName(option.name);
topOption.setText(option.value);
try {
topOption.setValue(Integer.parseInt(option.value));
} catch (final NumberFormatException e) {
throw new UriParserSyntaxException("Illegal value of $top option!", e,
UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
option.name, option.value);
}
systemOption = topOption;
} else if (option.name.equals(SystemQueryOptionKind.COUNT.toString())) {
CountOptionImpl inlineCountOption = new CountOptionImpl();
inlineCountOption.setName(option.name);
inlineCountOption.setText(option.value);
if (option.value.equals("true") || option.value.equals("false")) {
inlineCountOption.setValue(Boolean.parseBoolean(option.value));
} else {
throw new UriParserSyntaxException("Illegal value of $count option!",
UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
option.name, option.value);
}
systemOption = inlineCountOption;
} else {
throw new UriParserSyntaxException("Unknown system query option!",
UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION, option.name);
}
try {
context.contextUriInfo.setSystemQueryOption(systemOption);
} catch (final ODataRuntimeException e) {
throw new UriParserSyntaxException("Double system query option!", e,
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, option.name);
}
} else if (option.name.startsWith(AT)) {
if (context.contextUriInfo.getAlias(option.name) == null) {
// TODO: Create a proper alias-value parser that can parse also common expressions.
Expression expression = null;
if (!option.value.isEmpty() && (option.value.charAt(0) == '[' || option.value.charAt(0) == '{')) {
UriTokenizer tokenizer = new UriTokenizer(option.value);
if (!(tokenizer.next(TokenKind.jsonArrayOrObject) && tokenizer.next(TokenKind.EOF))) {
throw new UriParserSyntaxException("Illegal value for alias '" + option.name + "'.",
UriParserSyntaxException.MessageKeys.SYNTAX);
}
} else {
final FilterExpressionEOFContext filterExpCtx =
(FilterExpressionEOFContext) parseRule(option.value, ParserEntryRules.FilterExpression);
expression = ((FilterOption) uriParseTreeVisitor.visitFilterExpressionEOF(filterExpCtx))
.getExpression();
}
context.contextUriInfo.addAlias((AliasQueryOption) new AliasQueryOptionImpl()
.setAliasValue(expression)
.setName(option.name)
.setText(NULL.equals(option.value) ? null : option.value));
} else {
throw new UriParserSyntaxException("Alias already specified! Name: " + option.name,
UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS, option.name);
}
} else {
context.contextUriInfo.addCustomQueryOption((CustomQueryOption)
new CustomQueryOptionImpl()
.setName(option.name)
.setText(option.value));
}
}
return context.contextUriInfo;
} catch (ParseCancellationException e) {
throw e.getCause() instanceof UriParserException ?
(UriParserException) e.getCause() :
new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
}
return context.contextUriInfo;
}
private void ensureLastSegment(final String segment, final int pos, final int size)
@ -349,6 +376,30 @@ public class Parser {
return index > 0 && index < value.length() - 1 && index == value.lastIndexOf('/');
}
protected static EdmType getTypeInformation(final UriResourcePartTyped resourcePart) {
EdmType type = null;
if (resourcePart instanceof UriResourceWithKeysImpl) {
final UriResourceWithKeysImpl lastPartWithKeys = (UriResourceWithKeysImpl) resourcePart;
if (lastPartWithKeys.getTypeFilterOnEntry() != null) {
type = lastPartWithKeys.getTypeFilterOnEntry();
} else if (lastPartWithKeys.getTypeFilterOnCollection() != null) {
type = lastPartWithKeys.getTypeFilterOnCollection();
} else {
type = lastPartWithKeys.getType();
}
} else if (resourcePart instanceof UriResourceTypedImpl) {
final UriResourceTypedImpl lastPartTyped = (UriResourceTypedImpl) resourcePart;
type = lastPartTyped.getTypeFilter() == null ?
lastPartTyped.getType() :
lastPartTyped.getTypeFilter();
} else {
type = resourcePart.getType();
}
return type;
}
private ParserRuleContext parseRule(final String input, final ParserEntryRules entryPoint)
throws UriParserSyntaxException {
UriParserParser parser = null;
@ -362,17 +413,11 @@ public class Parser {
try {
// create parser
if (logLevel > 0) {
//TODO: Discuss if we should keep this code
lexer = new UriLexer(new ANTLRInputStream(input));
showTokens(input, lexer.getAllTokens());
}
lexer = new UriLexer(new ANTLRInputStream(input));
parser = new UriParserParser(new CommonTokenStream(lexer));
// Set error strategy
addStage1ErrorStategy(parser);
addStage1ErrorStrategy(parser);
// Set error collector
addStage1ErrorListener(parser);
@ -394,9 +439,6 @@ public class Parser {
lexer.mode(Lexer.DEFAULT_MODE);
ret = parser.expandItemsEOF();
break;
case Select:
ret = parser.selectEOF();
break;
default:
break;
@ -411,7 +453,7 @@ public class Parser {
parser = new UriParserParser(new CommonTokenStream(lexer));
// Set error strategy
addStage2ErrorStategy(parser);
addStage2ErrorStrategy(parser);
// Set error collector
addStage2ErrorListener(parser);
@ -433,9 +475,6 @@ public class Parser {
lexer.mode(Lexer.DEFAULT_MODE);
ret = parser.expandItemsEOF();
break;
case Select:
ret = parser.selectEOF();
break;
default:
break;
}
@ -454,13 +493,13 @@ public class Parser {
return ret;
}
protected void addStage1ErrorStategy(final UriParserParser parser) {
protected void addStage1ErrorStrategy(final UriParserParser parser) {
// Throw exception at first syntax error
parser.setErrorHandler(new BailErrorStrategy());
}
protected void addStage2ErrorStategy(final UriParserParser parser) {
protected void addStage2ErrorStrategy(final UriParserParser parser) {
// Throw exception at first syntax error
parser.setErrorHandler(new BailErrorStrategy());
}
@ -468,36 +507,10 @@ public class Parser {
protected void addStage1ErrorListener(final UriParserParser parser) {
// No error logging to System.out or System.err, only exceptions used (depending on ErrorStrategy)
parser.removeErrorListeners();
parser.addErrorListener(new CheckFullContextListener());
}
protected void addStage2ErrorListener(final UriParserParser parser) {
// No error logging to System.out or System.err, only exceptions used (depending on ErrorStrategy)
parser.removeErrorListeners();
}
public void showTokens(final String input, final List<? extends Token> list) {
boolean first = true;
System.out.println("input: " + input);
String nL = "\n";
StringBuilder out = new StringBuilder("[").append(nL);
for (Token token : list) {
if (!first) {
out.append(",");
first = false;
}
int index = token.getType();
out.append("\"").append(token.getText()).append("\"").append(" ");
if (index != -1) {
out.append(UriLexer.VOCABULARY.getDisplayName(index));
} else {
out.append(index);
}
out.append(nL);
}
out.append(']');
System.out.println("tokens: " + out.toString());
}
}

View File

@ -1,46 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.uri.parser;
import java.util.List;
public class RawUri {
public String uri;
public String scheme;
public String authority;
public String path;
public String queryOptionString;
public String fragment;
public List<QueryOption> queryOptionList;
public List<QueryOption> queryOptionListDecoded;
public List<String> pathSegmentList;
public List<String> pathSegmentListDecoded;
public static class QueryOption {
public String name;
public String value;
QueryOption(final String name, final String value) {
this.name = name;
this.value = value;
}
}
}

View File

@ -0,0 +1,241 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.uri.parser;
import java.util.ArrayList;
import java.util.List;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmAction;
import org.apache.olingo.commons.api.edm.EdmComplexType;
import org.apache.olingo.commons.api.edm.EdmFunction;
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmStructuredType;
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.UriResourcePartTyped;
import org.apache.olingo.server.api.uri.queryoption.SelectItem;
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
import org.apache.olingo.server.core.uri.UriInfoImpl;
import org.apache.olingo.server.core.uri.UriResourceActionImpl;
import org.apache.olingo.server.core.uri.UriResourceComplexPropertyImpl;
import org.apache.olingo.server.core.uri.UriResourceFunctionImpl;
import org.apache.olingo.server.core.uri.UriResourceNavigationPropertyImpl;
import org.apache.olingo.server.core.uri.UriResourcePrimitivePropertyImpl;
import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
import org.apache.olingo.server.core.uri.queryoption.SelectItemImpl;
import org.apache.olingo.server.core.uri.queryoption.SelectOptionImpl;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
public class SelectParser {
private final Edm edm;
public SelectParser(final Edm edm) {
this.edm = edm;
}
public SelectOption parse(UriTokenizer tokenizer, final EdmStructuredType referencedType,
final boolean referencedIsCollection) throws UriParserException, UriValidationException {
List<SelectItem> selectItems = new ArrayList<SelectItem>();
SelectItem item;
do {
item = parseItem(tokenizer, referencedType, referencedIsCollection);
selectItems.add(item);
} while (tokenizer.next(TokenKind.COMMA));
return new SelectOptionImpl().setSelectItems(selectItems);
}
private SelectItem parseItem(UriTokenizer tokenizer,
final EdmStructuredType referencedType, final boolean referencedIsCollection) throws UriParserException {
SelectItemImpl item = new SelectItemImpl();
if (tokenizer.next(TokenKind.STAR)) {
item.setStar(true);
} else if (tokenizer.next(TokenKind.QualifiedName)) {
// The namespace or its alias could consist of dot-separated OData identifiers.
final FullQualifiedName allOperationsInSchema = parseAllOperationsInSchema(tokenizer);
if (allOperationsInSchema != null) {
item.addAllOperationsInSchema(allOperationsInSchema);
} else {
ensureReferencedTypeNotNull(referencedType);
final FullQualifiedName qualifiedName = new FullQualifiedName(tokenizer.getText());
EdmStructuredType type = edm.getEntityType(qualifiedName);
if (type == null) {
type = edm.getComplexType(qualifiedName);
}
if (type == null) {
item.setResourcePath(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
parseBoundOperation(tokenizer, qualifiedName, referencedType, referencedIsCollection)));
} else {
if (type.compatibleTo(referencedType)) {
item.setTypeFilter(type);
if (tokenizer.next(TokenKind.SLASH)) {
requireNext(tokenizer, TokenKind.ODataIdentifier);
UriInfoImpl resource = new UriInfoImpl().setKind(UriInfoKind.resource);
addSelectPath(tokenizer, type, resource);
item.setResourcePath(resource);
}
} else {
throw new UriParserSemanticException("The type cast is not compatible.",
UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, type.getName());
}
}
}
} else {
requireNext(tokenizer, TokenKind.ODataIdentifier);
// The namespace or its alias could be a single OData identifier.
final FullQualifiedName allOperationsInSchema = parseAllOperationsInSchema(tokenizer);
if (allOperationsInSchema != null) {
item.addAllOperationsInSchema(allOperationsInSchema);
} else {
ensureReferencedTypeNotNull(referencedType);
UriInfoImpl resource = new UriInfoImpl().setKind(UriInfoKind.resource);
addSelectPath(tokenizer, referencedType, resource);
item.setResourcePath(resource);
}
}
return item;
}
private FullQualifiedName parseAllOperationsInSchema(UriTokenizer tokenizer) throws UriParserException {
final String name = 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());
} else {
throw new UriParserSemanticException("Expected star after dot.",
UriParserSemanticException.MessageKeys.UNKNOWN_PART, "");
}
}
return null;
}
private void ensureReferencedTypeNotNull(final EdmStructuredType referencedType) throws UriParserException {
if (referencedType == null) {
throw new UriParserSemanticException("The referenced part is not typed.",
UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "select");
}
}
private UriResourcePartTyped parseBoundOperation(UriTokenizer tokenizer, final FullQualifiedName qualifiedName,
final EdmStructuredType referencedType, final boolean referencedIsCollection) throws UriParserException {
final EdmAction boundAction = edm.getBoundAction(qualifiedName,
referencedType.getFullQualifiedName(),
referencedIsCollection);
if (boundAction == null) {
final List<String> parameterNames = parseFunctionParameterNames(tokenizer);
final EdmFunction boundFunction = edm.getBoundFunction(qualifiedName,
referencedType.getFullQualifiedName(), referencedIsCollection, parameterNames);
if (boundFunction == null) {
throw new UriParserSemanticException("Function not found.",
UriParserSemanticException.MessageKeys.UNKNOWN_PART, qualifiedName.getFullQualifiedNameAsString());
} else {
return new UriResourceFunctionImpl().setFunction(boundFunction);
}
} else {
return new UriResourceActionImpl().setAction(boundAction);
}
}
private List<String> parseFunctionParameterNames(UriTokenizer tokenizer) throws UriParserException {
List<String> names = new ArrayList<String>();
if (tokenizer.next(TokenKind.OPEN)) {
do {
requireNext(tokenizer, TokenKind.ODataIdentifier);
names.add(tokenizer.getText());
} while (tokenizer.next(TokenKind.COMMA));
requireNext(tokenizer, TokenKind.CLOSE);
}
return names;
}
private void addSelectPath(UriTokenizer tokenizer, final EdmStructuredType referencedType, UriInfoImpl resource)
throws UriParserException {
final String name = tokenizer.getText();
final EdmProperty property = referencedType.getStructuralProperty(name);
if (property == null) {
final EdmNavigationProperty navigationProperty = referencedType.getNavigationProperty(name);
if (navigationProperty == null) {
throw new UriParserSemanticException("Selected property not found.",
UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE,
referencedType.getName(), name);
} else {
resource.addResourcePart(new UriResourceNavigationPropertyImpl().setNavigationProperty(navigationProperty));
}
} else if (property.isPrimitive()
|| property.getType().getKind() == EdmTypeKind.ENUM
|| property.getType().getKind() == EdmTypeKind.DEFINITION) {
resource.addResourcePart(new UriResourcePrimitivePropertyImpl().setProperty(property));
} else {
UriResourceComplexPropertyImpl complexPart = new UriResourceComplexPropertyImpl().setProperty(property);
resource.addResourcePart(complexPart);
if (tokenizer.next(TokenKind.SLASH)) {
if (tokenizer.next(TokenKind.QualifiedName)) {
final FullQualifiedName qualifiedName = new FullQualifiedName(tokenizer.getText());
final EdmComplexType type = edm.getComplexType(qualifiedName);
if (type == null) {
throw new UriParserSemanticException("Type not found.",
UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, qualifiedName.getFullQualifiedNameAsString());
} else if (type.compatibleTo(property.getType())) {
complexPart.setTypeFilter(type);
if (tokenizer.next(TokenKind.SLASH)) {
if (tokenizer.next(TokenKind.ODataIdentifier)) {
addSelectPath(tokenizer, type, resource);
} else {
throw new UriParserSemanticException("Unknown part after '/'.",
UriParserSemanticException.MessageKeys.UNKNOWN_PART, "");
}
}
} else {
throw new UriParserSemanticException("The type cast is not compatible.",
UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, type.getName());
}
} else if (tokenizer.next(TokenKind.ODataIdentifier)) {
addSelectPath(tokenizer, (EdmStructuredType) property.getType(), resource);
} else if (tokenizer.next(TokenKind.SLASH)) {
throw new UriParserSyntaxException("Illegal $select expression.",
UriParserSyntaxException.MessageKeys.SYNTAX);
} else {
throw new UriParserSemanticException("Unknown part after '/'.",
UriParserSemanticException.MessageKeys.UNKNOWN_PART, "");
}
}
}
}
private void requireNext(UriTokenizer tokenizer, final TokenKind kind) throws UriParserSyntaxException {
if (!tokenizer.next(kind)) {
throw new UriParserSyntaxException("Illegal $select expression.",
UriParserSyntaxException.MessageKeys.SYNTAX);
}
}
}

View File

@ -18,11 +18,11 @@
*/
package org.apache.olingo.server.core.uri.parser;
import java.util.Stack;
import java.util.ArrayDeque;
import java.util.Deque;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.server.core.uri.UriInfoImpl;
import org.apache.olingo.server.core.uri.parser.UriParseTreeVisitor.TypeInformation;
import org.apache.olingo.server.core.uri.queryoption.ExpandItemImpl;
import org.apache.olingo.server.core.uri.queryoption.SelectItemImpl;
@ -33,9 +33,9 @@ import org.apache.olingo.server.core.uri.queryoption.SelectItemImpl;
public class UriContext {
public static class LambdaVariables {
public boolean isCollection;
public String name;
public EdmType type;
public boolean isCollection;
}
/**
@ -43,11 +43,14 @@ public class UriContext {
* As lambda functions can be nested there may be more than one allowed lambda variables at a time while parsing a
* $filter or $orderby expressions.
*/
public Stack<LambdaVariables> allowedLambdaVariables;
public Deque<LambdaVariables> allowedLambdaVariables;
/**
* Used to stack type information for nested $expand, $filter query options and other cases.
*/
public Stack<TypeInformation> contextTypes;
public Deque<EdmType> contextTypes;
/** Whether the context types are collections. */
public boolean isCollection;
// CHECKSTYLE:OFF (Maven checkstyle)
/**
@ -106,8 +109,8 @@ public class UriContext {
contextExpandItemPath = null;
contextReadingFunctionParameters = false;
contextSelectItem = null;
contextTypes = new Stack<UriParseTreeVisitor.TypeInformation>();
allowedLambdaVariables = new Stack<UriContext.LambdaVariables>();
contextTypes = new ArrayDeque<EdmType>();
allowedLambdaVariables = new ArrayDeque<UriContext.LambdaVariables>();
}
}

View File

@ -25,53 +25,42 @@ import java.util.LinkedList;
import java.util.List;
import org.apache.olingo.commons.core.Decoder;
import org.apache.olingo.server.api.uri.queryoption.QueryOption;
import org.apache.olingo.server.core.uri.queryoption.CustomQueryOptionImpl;
public class UriDecoder {
public static RawUri decodeUri(final String path, final String query, final String fragment,
final int skipSegments) throws UriParserSyntaxException {
RawUri rawUri = new RawUri();
rawUri.path = path;
rawUri.queryOptionString = query;
rawUri.fragment = fragment;
rawUri.pathSegmentList = splitPath(path, skipSegments);
rawUri.queryOptionList = splitOptions(query);
decode(rawUri);
return rawUri;
/** Splits the path string at '/' characters and percent-decodes the resulting path segments. */
protected static List<String> splitAndDecodePath(final String path) throws UriParserSyntaxException {
List<String> pathSegmentsDecoded = new ArrayList<String>();
for (final String segment : splitSkipEmpty(path, '/')) {
pathSegmentsDecoded.add(decode(segment));
}
return pathSegmentsDecoded;
}
private static void decode(final RawUri rawUri) throws UriParserSyntaxException {
rawUri.pathSegmentListDecoded = new ArrayList<String>();
for (String segment : rawUri.pathSegmentList) {
rawUri.pathSegmentListDecoded.add(decode(segment));
}
rawUri.queryOptionListDecoded = new ArrayList<RawUri.QueryOption>();
for (RawUri.QueryOption optionPair : rawUri.queryOptionList) {
rawUri.queryOptionListDecoded.add(new RawUri.QueryOption(
decode(optionPair.name),
decode(optionPair.value)));
}
}
private static List<RawUri.QueryOption> splitOptions(final String queryOptionString) {
if (queryOptionString == null) {
/**
* Splits the query-option string at '&' characters, the resulting parts at '=' characters,
* and separately percent-decodes names and values of the resulting name-value pairs.
*/
protected static List<QueryOption> splitAndDecodeOptions(final String queryOptionString)
throws UriParserSyntaxException {
if (queryOptionString == null || queryOptionString.isEmpty()) {
return Collections.emptyList();
}
List<RawUri.QueryOption> queryOptionList = new ArrayList<RawUri.QueryOption>();
for (String option : splitSkipEmpty(queryOptionString, '&')) {
List<QueryOption> queryOptions = new ArrayList<QueryOption>();
for (final String option : splitSkipEmpty(queryOptionString, '&')) {
final List<String> pair = splitFirst(option, '=');
queryOptionList.add(new RawUri.QueryOption(pair.get(0), pair.get(1)));
queryOptions.add(new CustomQueryOptionImpl()
.setName(decode(pair.get(0)))
.setText(decode(pair.get(1))));
}
return queryOptionList;
return queryOptions;
}
private static List<String> splitFirst(final String input, final char c) {
int pos = input.indexOf(c, 0);
int pos = input.indexOf(c);
if (pos >= 0) {
return Arrays.asList(input.substring(0, pos), input.substring(pos + 1));
} else {
@ -79,21 +68,14 @@ public class UriDecoder {
}
}
private static List<String> splitPath(final String path, final int skipSegments) {
List<String> list = splitSkipEmpty(path, '/');
return skipSegments > 0 ? list.subList(skipSegments, list.size()) : list;
}
/**
* Split the input string at given character and drop all empty elements.
*
* Splits the input string at the given character and drops all empty elements.
* @param input string to split
* @param c character at which to split
* @return list of elements (can be empty)
*/
static List<String> splitSkipEmpty(final String input, final char c) {
if(input.isEmpty() || input.length() == 1 && input.charAt(0) == c) {
private static List<String> splitSkipEmpty(final String input, final char c) {
if (input.isEmpty() || input.length() == 1 && input.charAt(0) == c) {
return Collections.emptyList();
}
@ -103,20 +85,20 @@ public class UriDecoder {
int end;
while ((end = input.indexOf(c, start)) >= 0) {
if(start != end) {
if (start != end) {
list.add(input.substring(start, end));
}
start = end + 1;
}
if(input.charAt(input.length()-1) != c) {
if (input.charAt(input.length() - 1) != c) {
list.add(input.substring(start));
}
return list;
}
public static String decode(final String encoded) throws UriParserSyntaxException {
private static String decode(final String encoded) throws UriParserSyntaxException {
try {
return Decoder.decode(encoded);
} catch (final IllegalArgumentException e) {

View File

@ -82,9 +82,7 @@ import org.apache.olingo.server.core.uri.UriResourceStartingTypeFilterImpl;
import org.apache.olingo.server.core.uri.UriResourceTypedImpl;
import org.apache.olingo.server.core.uri.UriResourceValueImpl;
import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
import org.apache.olingo.server.core.uri.antlr.UriLexer;
import org.apache.olingo.server.core.uri.antlr.UriParserBaseVisitor;
import org.apache.olingo.server.core.uri.antlr.UriParserParser;
import org.apache.olingo.server.core.uri.antlr.*;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.AllEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.AllExprContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltAddContext;
@ -106,7 +104,6 @@ import org.apache.olingo.server.core.uri.antlr.UriParserParser.CeilingMethodCall
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ConcatMethodCallExprContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ConstSegmentContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ContainsMethodCallExprContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.CrossjoinEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.DateLiteralContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.DateMethodCallExprContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.DatetimeoffsetLiteralContext;
@ -151,7 +148,6 @@ import org.apache.olingo.server.core.uri.antlr.UriParserParser.NamespaceContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.NaninfinityLiteralContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.NowMethodCallExprContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.NullruleLiteralContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.OdataIdentifierContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByItemContext;
@ -226,20 +222,6 @@ import org.apache.olingo.server.core.uri.queryoption.expression.UnaryImpl;
*/
public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
public class TypeInformation {
boolean isCollection;
EdmType type;
TypeInformation(final EdmType type, final boolean isCollection) {
this.type = type;
this.isCollection = isCollection;
}
public TypeInformation() {}
}
public UriContext context = null;
public Edm edm;
@ -277,36 +259,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
return null;
}
TypeInformation getTypeInformation(final UriResource lastResourcePart) {
TypeInformation typeInformation = new TypeInformation();
if (lastResourcePart instanceof UriResourceWithKeysImpl) {
UriResourceWithKeysImpl lastPartWithKeys = (UriResourceWithKeysImpl) lastResourcePart;
if (lastPartWithKeys.getTypeFilterOnEntry() != null) {
typeInformation.type = lastPartWithKeys.getTypeFilterOnEntry();
} else if (lastPartWithKeys.getTypeFilterOnCollection() != null) {
typeInformation.type = lastPartWithKeys.getTypeFilterOnCollection();
} else {
typeInformation.type = lastPartWithKeys.getType();
}
typeInformation.isCollection = lastPartWithKeys.isCollection();
} else if (lastResourcePart instanceof UriResourceTypedImpl) {
UriResourceTypedImpl lastPartTyped = (UriResourceTypedImpl) lastResourcePart;
if (lastPartTyped.getTypeFilter() != null) {
typeInformation.type = lastPartTyped.getTypeFilter();
} else {
typeInformation.type = lastPartTyped.getType();
}
typeInformation.isCollection = lastPartTyped.isCollection();
}
return typeInformation;
}
public UriResourceTypedImpl readResourcePathSegment(final PathSegmentContext ctx) {
final boolean checkFirst =
@ -318,10 +270,10 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
boolean searchInContainer = true;
// validate if context type and according property is available
// otherwise search in container for first element
if (checkFirst && ctx.vNS == null && !context.contextTypes.empty()) {
TypeInformation source = context.contextTypes.peek();
if (source.type instanceof EdmStructuredType) {
EdmStructuredType str = (EdmStructuredType) source.type;
if (checkFirst && ctx.vNS == null && !context.contextTypes.isEmpty()) {
EdmType sourceType = context.contextTypes.peek();
if (sourceType instanceof EdmStructuredType) {
EdmStructuredType str = (EdmStructuredType) sourceType;
EdmElement property = str.getProperty(odi);
if (property != null) {
searchInContainer = false;
@ -418,11 +370,12 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
}
}
final TypeInformation source;
EdmType sourceType;
boolean sourceIsCollection = false;
final UriResource lastResourcePart = context.contextUriInfo.getLastResourcePart();
if (lastResourcePart == null) {
if (context.contextTypes.empty()) {
if (context.contextTypes.isEmpty()) {
if (checkFirst && ctx.vNS == null) {
throw wrap(new UriParserSemanticException(
"Cannot find EntitySet, Singleton, ActionImport or FunctionImport with name '" + odi + "'.",
@ -432,15 +385,15 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
"Resource part '" + odi + "' can only applied on typed resource parts",
UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS, odi));
}
source = context.contextTypes.peek();
sourceType = context.contextTypes.peek();
sourceIsCollection = context.isCollection;
} else if (lastResourcePart instanceof UriResourcePartTyped) {
sourceType = Parser.getTypeInformation((UriResourcePartTyped) lastResourcePart);
sourceIsCollection = ((UriResourcePartTyped) lastResourcePart).isCollection();
} else {
source = getTypeInformation(lastResourcePart);
if (source.type == null) {
throw wrap(new UriParserSemanticException(
"Resource part '" + odi + "' can only be applied on typed resource parts.",
UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS, odi));
}
throw wrap(new UriParserSemanticException(
"Resource part '" + odi + "' can only be applied on typed resource parts.",
UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS, odi));
}
if (ctx.vNS == null) { // without namespace
@ -456,7 +409,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
return null;
}
if (!(source.type instanceof EdmStructuredType)) {
if (!(sourceType instanceof EdmStructuredType)) {
throw wrap(new UriParserSemanticException(
"Cannot parse '" + odi + "'; previous path segment is not a structural type.",
UriParserSemanticException.MessageKeys.RESOURCE_PART_MUST_BE_PRECEDED_BY_STRUCTURAL_TYPE, odi));
@ -465,12 +418,12 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
if ((ctx.depth() <= 2 // path evaluation for the resource path
|| lastResourcePart instanceof UriResourceTypedImpl
|| lastResourcePart instanceof UriResourceNavigationPropertyImpl)
&& source.isCollection) {
&& sourceIsCollection) {
throw wrap(new UriParserSemanticException("Property '" + odi + "' is not allowed after collection.",
UriParserSemanticException.MessageKeys.PROPERTY_AFTER_COLLECTION, odi));
}
EdmStructuredType structType = (EdmStructuredType) source.type;
EdmStructuredType structType = (EdmStructuredType) sourceType;
EdmElement property = structType.getProperty(odi);
if (property == null) {
@ -520,12 +473,12 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
FullQualifiedName fullFilterName = getFullNameFromContext(ctx.vNS, odi);
// EdmType lastType = getLastType(lastTyped);
if (source.type instanceof EdmEntityType) {
if (sourceType instanceof EdmEntityType) {
EdmEntityType filterEntityType = edm.getEntityType(fullFilterName);
if (filterEntityType != null) {
// is entity type cast
if (!(filterEntityType.compatibleTo(source.type))) {
if (!(filterEntityType.compatibleTo(sourceType))) {
throw wrap(new UriParserSemanticException(
"Entity typefilter not compatible to previous path segment: " + fullFilterName.toString(),
UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, fullFilterName.toString()));
@ -535,8 +488,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
// this may be the case if a member expression within a filter starts with a typeCast
UriResourceStartingTypeFilterImpl uriResource = new UriResourceStartingTypeFilterImpl()
.setType(filterEntityType)
.setCollection(source.isCollection);
if (source.isCollection) {
.setCollection(sourceIsCollection);
if (sourceIsCollection) {
uriResource.setCollectionTypeFilter(filterEntityType);
} else {
uriResource.setEntryTypeFilter(filterEntityType);
@ -590,18 +543,18 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
}
}
} else if (source.type instanceof EdmComplexType) {
} else if (sourceType instanceof EdmComplexType) {
EdmComplexType filterComplexType = edm.getComplexType(fullFilterName);
if (filterComplexType != null) {
// is complex type cast
if (!(filterComplexType.compatibleTo(source.type))) {
if (!(filterComplexType.compatibleTo(sourceType))) {
throw wrap(new UriParserSemanticException(
"Complex typefilter '" + getName(source.type) + "'not compatible type of previous path segment '"
"Complex typefilter '" + getName(sourceType) + "'not compatible type of previous path segment '"
+ getName(filterComplexType) + "'",
UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, getName(source.type)));
UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, getName(sourceType)));
}
// is simple complex type cast
@ -609,9 +562,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
// this may be the case if a member expression within a filter starts with a typeCast
UriResourceStartingTypeFilterImpl uriResource = new UriResourceStartingTypeFilterImpl()
.setType(filterComplexType)
.setCollection(source.isCollection);
.setCollection(sourceIsCollection);
if (source.isCollection) {
if (sourceIsCollection) {
uriResource.setCollectionTypeFilter(filterComplexType);
} else {
uriResource.setEntryTypeFilter(filterComplexType);
@ -666,10 +619,10 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
}
}
FullQualifiedName fullBindingTypeName = new FullQualifiedName(source.type.getNamespace(), source.type.getName());
FullQualifiedName fullBindingTypeName = sourceType.getFullQualifiedName();
// check for action
EdmAction action = edm.getBoundAction(fullFilterName, fullBindingTypeName, source.isCollection);
EdmAction action = edm.getBoundAction(fullFilterName, fullBindingTypeName, sourceIsCollection);
if (action != null) {
UriResourceActionImpl pathInfoAction = new UriResourceActionImpl();
pathInfoAction.setAction(action);
@ -694,7 +647,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
names.add(item.getName());
}
EdmFunction function = edm.getBoundFunction(fullFilterName, fullBindingTypeName, source.isCollection, names);
EdmFunction function = edm.getBoundFunction(fullFilterName, fullBindingTypeName, sourceIsCollection, names);
if (function != null) {
UriResourceFunctionImpl pathInfoFunction = new UriResourceFunctionImpl()
@ -767,7 +720,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
UriContext.LambdaVariables var = new UriContext.LambdaVariables();
var.name = ctx.vLV.getText();
var.type = getTypeInformation(obj).type;
var.type = Parser.getTypeInformation((UriResourcePartTyped) obj);
var.isCollection = false;
all.setLamdaVariable(ctx.vLV.getText());
@ -907,11 +860,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
context.contextUriInfo.setEntityTypeCast(type);
// contextUriInfo = uriInfo;
context.contextTypes.push(new TypeInformation(context.contextUriInfo.getEntityTypeCast(), true));
context.contextTypes.push(context.contextUriInfo.getEntityTypeCast());
context.isCollection = true; // TODO: check!
// @SuppressWarnings("unchecked")
// List<QueryOptionImpl> list = (List<QueryOptionImpl>) ctx.vEO.accept(this);
// uriInfo.setQueryOptions(list);
return null;
}
@ -998,7 +949,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
UriContext.LambdaVariables var = new UriContext.LambdaVariables();
var.name = ctx.vLV.getText();
var.type = getTypeInformation(lastResourcePart).type;
var.type = Parser.getTypeInformation((UriResourcePartTyped) lastResourcePart);
var.isCollection = false;
any.setLamdaVariable(ctx.vLV.getText());
@ -1146,33 +1097,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
.addParameter((ExpressionImpl) ctx.vE2.accept(this));
}
@Override
public Object visitCrossjoinEOF(final CrossjoinEOFContext ctx) {
UriInfoImpl crossJoin = new UriInfoImpl().setKind(UriInfoKind.crossjoin);
for (OdataIdentifierContext obj : ctx.vlODI) {
String odi = obj.getText();
crossJoin.addEntitySetName(odi);
EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(odi);
if (edmEntitySet == null) {
throw wrap(new UriParserSemanticException("Expected EntityTypeName",
UriParserSemanticException.MessageKeys.UNKNOWN_PART, odi));
}
EdmEntityType type = edmEntitySet.getEntityType();
if (type == null) {
throw wrap(new UriParserSemanticException("Expected EntityTypeName",
UriParserSemanticException.MessageKeys.UNKNOWN_ENTITY_TYPE, odi));
}
// contextUriInfo = uriInfo;
context.contextTypes.push(new TypeInformation(type, true));
}
context.contextUriInfo = crossJoin;
return null;
}
@Override
public Object visitDateMethodCallExpr(final DateMethodCallExprContext ctx) {
return new MethodImpl()
@ -1372,23 +1296,24 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
if (context.contextExpandItemPath == null) {
// use the type of the last resource path segement
UriResourceTypedImpl lastSegment = (UriResourceTypedImpl) context.contextUriInfo.getLastResourcePart();
targetType = getTypeInformation(lastSegment).type;
targetType = Parser.getTypeInformation(lastSegment);
isColl = lastSegment.isCollection();
} else {
if (context.contextExpandItemPath.getResourcePath() == null) {
// use the type of the last resource path segement
UriResourceTypedImpl lastSegment = (UriResourceTypedImpl) context.contextUriInfo.getLastResourcePart();
targetType = getTypeInformation(lastSegment).type;
targetType = Parser.getTypeInformation(lastSegment);
isColl = lastSegment.isCollection();
} else {
// use the type of the last ''expand'' path segement
UriInfoImpl info = (UriInfoImpl) context.contextExpandItemPath.getResourcePath();
targetType = getTypeInformation(info.getLastResourcePart()).type;
targetType = Parser.getTypeInformation((UriResourcePartTyped) info.getLastResourcePart());
isColl = ((UriResourcePartTyped) info.getLastResourcePart()).isCollection();
}
}
context.contextTypes.push(new TypeInformation(targetType, isColl));
context.contextTypes.push(targetType);
context.isCollection = isColl;
if (ctx.vC != null) {
UriInfoImpl resourcePath = (UriInfoImpl) context.contextExpandItemPath.getResourcePath();
@ -1546,12 +1471,11 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
throw wrap(new UriParserSemanticException("Expression '" + ctx.getText() + "' is not allowed as key value.",
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, ctx.getText()));
}
TypeInformation lastTypeInfo = context.contextTypes.peek();
if (ctx.vIt != null || ctx.vIts != null) {
UriResourceItImpl pathInfoIT = new UriResourceItImpl();
pathInfoIT.setType(lastTypeInfo.type);
pathInfoIT.setCollection(lastTypeInfo.isCollection);
pathInfoIT.setType(context.contextTypes.peek());
pathInfoIT.setCollection(context.isCollection);
uriInfoImplpath.addResourcePart(pathInfoIT);
}
@ -2101,7 +2025,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
UriResourceRootImpl pathInfoRoot = new UriResourceRootImpl();
pathInfoRoot.setCollection(lastType.isCollection());
pathInfoRoot.setType(getTypeInformation(lastType).type);
pathInfoRoot.setType(Parser.getTypeInformation(lastType));
UriInfoImpl uriInfoImplpath = new UriInfoImpl().setKind(UriInfoKind.resource);
uriInfoImplpath.addResourcePart(pathInfoRoot);
@ -2194,12 +2118,12 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
EdmType prevType = null;
if (context.contextSelectItem.getResourcePath() == null) {
prevType = context.contextTypes.peek().type;
prevType = context.contextTypes.peek();
} else {
UriInfoImpl uriInfo = (UriInfoImpl) context.contextSelectItem.getResourcePath();
UriResource last = uriInfo.getLastResourcePart();
prevType = getTypeInformation(last).type;
prevType = Parser.getTypeInformation((UriResourcePartTyped) last);
if (prevType == null) {
throw wrap(new UriParserSemanticException("prev segment not typed",
UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "select"));
@ -2278,7 +2202,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
// contextSelectItem.addQualifiedThing(fullName);
if (context.contextSelectItem.getResourcePath() == null) {
EdmType prevType = context.contextTypes.peek().type;
EdmType prevType = context.contextTypes.peek();
// check for complex type cast
if (prevType instanceof EdmComplexType) {
@ -2331,7 +2255,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
throw wrap(new UriParserSemanticException("prev segment typed",
UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "select"));
}
EdmType prevType = getTypeInformation(last).type;
EdmType prevType = Parser.getTypeInformation((UriResourcePartTyped) last);
if (prevType instanceof EdmComplexType) {
EdmComplexType ct = edm.getComplexType(fullName);
@ -2367,7 +2291,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
EdmType prevType = null;
if (context.contextSelectItem.getResourcePath() == null) {
prevType = context.contextTypes.peek().type;
prevType = context.contextTypes.peek();
} else {
UriInfoImpl uriInfo = (UriInfoImpl) context.contextSelectItem.getResourcePath();
UriResource last = uriInfo.getLastResourcePart();
@ -2375,7 +2299,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
throw wrap(new UriParserSemanticException("prev segment typed",
UriParserSemanticException.MessageKeys.PREVIOUS_PART_TYPED));
}
prevType = getTypeInformation(last).type;
prevType = Parser.getTypeInformation((UriResourcePartTyped) last);
}
final FullQualifiedName finalTypeName = prevType.getFullQualifiedName();

View File

@ -39,7 +39,11 @@ public class UriTokenizer {
CLOSE,
COMMA,
SEMI,
DOT,
SLASH,
EQ,
STAR,
PLUS,
NULL,
// variable-value tokens (convention: mixed case)
@ -63,18 +67,18 @@ public class UriTokenizer {
jsonArrayOrObject
}
private final String pathSegment;
private final String parseString;
private int startIndex = 0;
private int index = 0;
public UriTokenizer(final String pathSegment) {
this.pathSegment = pathSegment == null ? "" : pathSegment;
public UriTokenizer(final String parseString) {
this.parseString = parseString == null ? "" : parseString;
}
/** Returns the string value corresponding to the last successful {@link #next(TokenKind)} call. */
public String getText() {
return pathSegment.substring(startIndex, index);
return parseString.substring(startIndex, index);
}
/**
@ -119,14 +123,26 @@ public class UriTokenizer {
case SEMI:
found = nextCharacter(';');
break;
case DOT:
found = nextCharacter('.');
break;
case SLASH:
found = nextCharacter('/');
break;
case EQ:
found = nextCharacter('=');
break;
case STAR:
found = nextCharacter('*');
break;
case PLUS:
found = nextCharacter('+');
break;
case NULL:
found = nextConstant("null");
break;
case EOF:
found = index >= pathSegment.length();
found = index >= parseString.length();
break;
// Identifiers
@ -192,8 +208,12 @@ public class UriTokenizer {
return found;
}
/**
* Moves past the given string constant if found; otherwise leaves the index unchanged.
* @return whether the constant has been found at the current index
*/
private boolean nextConstant(final String constant) {
if (pathSegment.startsWith(constant, index)) {
if (parseString.startsWith(constant, index)) {
index += constant.length();
return true;
} else {
@ -201,10 +221,14 @@ public class UriTokenizer {
}
}
/**
* Moves past the given string constant, ignoring case, if found; otherwise leaves the index unchanged.
* @return whether the constant has been found at the current index
*/
private boolean nextConstantIgnoreCase(final String constant) {
final int length = constant.length();
if (index + length <= pathSegment.length()
&& constant.equalsIgnoreCase(pathSegment.substring(index, index + length))) {
if (index + length <= parseString.length()
&& constant.equalsIgnoreCase(parseString.substring(index, index + length))) {
index += length;
return true;
} else {
@ -217,7 +241,7 @@ public class UriTokenizer {
* @return whether the given character has been found at the current index
*/
private boolean nextCharacter(final char character) {
if (index < pathSegment.length() && pathSegment.charAt(index) == character) {
if (index < parseString.length() && parseString.charAt(index) == character) {
index++;
return true;
} else {
@ -231,8 +255,8 @@ public class UriTokenizer {
* @return whether the given character has been found at the current index
*/
private boolean nextCharacterRange(final char from, final char to) {
if (index < pathSegment.length()) {
final char code = pathSegment.charAt(index);
if (index < parseString.length()) {
final char code = parseString.charAt(index);
if (code >= from && code <= to) {
index++;
return true;
@ -276,16 +300,20 @@ public class UriTokenizer {
return nextCharacter('+') || nextCharacter('-');
}
/**
* Moves past an OData identifier if found; otherwise leaves the index unchanged.
* @return whether an OData identifier has been found at the current index
*/
private boolean nextODataIdentifier() {
int count = 0;
if (index < pathSegment.length()) {
int code = pathSegment.codePointAt(index);
if (index < parseString.length()) {
int code = parseString.codePointAt(index);
if (Character.isUnicodeIdentifierStart(code) || code == '_') {
count++;
// Unicode characters outside of the Basic Multilingual Plane are represented as two Java characters.
index += Character.isSupplementaryCodePoint(code) ? 2 : 1;
while (index < pathSegment.length() && count < 128) {
code = pathSegment.codePointAt(index);
while (index < parseString.length() && count < 128) {
code = parseString.codePointAt(index);
if (Character.isUnicodeIdentifierPart(code) && !Character.isISOControl(code)) {
count++;
// Unicode characters outside of the Basic Multilingual Plane are represented as two Java characters.
@ -299,16 +327,30 @@ public class UriTokenizer {
return count > 0;
}
/**
* Moves past a qualified name if found; otherwise leaves the index unchanged.
* @return whether a qualified name has been found at the current index
*/
private boolean nextQualifiedName() {
int count = 0;
do {
final int lastGoodIndex = index;
if (!nextODataIdentifier()) {
return false;
}
int count = 1;
while (nextCharacter('.')) {
if (nextODataIdentifier()) {
count++;
} else {
return false;
index--;
break;
}
} while (nextCharacter('.'));
return count >= 2;
}
if (count >= 2) {
return true;
} else {
index = lastGoodIndex;
return false;
}
}
private boolean nextParameterAliasName() {
@ -323,12 +365,12 @@ public class UriTokenizer {
if (!nextCharacter('\'')) {
return false;
}
while (index < pathSegment.length()) {
if (pathSegment.charAt(index) == '\'') {
while (index < parseString.length()) {
if (parseString.charAt(index) == '\'') {
// If a single quote is followed by another single quote,
// it represents one single quote within the string literal,
// otherwise it marks the end of the string literal.
if (index + 1 < pathSegment.length() && pathSegment.charAt(index + 1) == '\'') {
if (index + 1 < parseString.length() && parseString.charAt(index + 1) == '\'') {
index++;
} else {
break;
@ -339,7 +381,13 @@ public class UriTokenizer {
return nextCharacter('\'');
}
/**
* Moves past an integer value if found; otherwise leaves the index unchanged.
* @param signed whether a sign character ('+' or '-') at the beginning is allowed
* @return whether an integer value has been found at the current index
*/
private boolean nextIntegerValue(final boolean signed) {
final int lastGoodIndex = index;
if (signed) {
nextSign();
}
@ -347,33 +395,53 @@ public class UriTokenizer {
while (nextDigit()) {
hasDigits = true;
}
return hasDigits;
}
/** Finds and returns only decimal-number tokens with a fractional part.
* Whole numbers must be found with {@link #nextIntegerValue()}.
*/
private boolean nextDecimalValue() {
return nextIntegerValue(true) && nextCharacter('.') && nextIntegerValue(false);
if (hasDigits) {
return true;
} else {
index = lastGoodIndex;
return false;
}
}
/**
* Finds and returns only floating-point-number tokens with an exponential part
* and the special three constants "NaN", "-INF", and "INF".
* Whole numbers must be found with {@link #nextIntegerValue()}.
* Decimal numbers must be found with {@link #nextDecimalValue()}.
* Moves past a decimal value with a fractional part if found; otherwise leaves the index unchanged.
* Whole numbers must be found with {@link #nextIntegerValue()}.
*/
private boolean nextDecimalValue() {
final int lastGoodIndex = index;
if (nextIntegerValue(true) && nextCharacter('.') && nextIntegerValue(false)) {
return true;
} else {
index = lastGoodIndex;
return false;
}
}
/**
* Moves past a floating-point-number value with an exponential part
* or one of the special constants "NaN", "-INF", and "INF"
* if found; otherwise leaves the index unchanged.
* Whole numbers must be found with {@link #nextIntegerValue()}.
* Decimal numbers must be found with {@link #nextDecimalValue()}.
*/
private boolean nextDoubleValue() {
if (nextConstant("NaN") || nextConstant("-INF") || nextConstant("INF")) {
return true;
} else {
final int lastGoodIndex = index;
if (!nextIntegerValue(true)) {
return false;
}
if (nextCharacter('.') && !nextIntegerValue(false)) {
index = lastGoodIndex;
return false;
}
if ((nextCharacter('E') || nextCharacter('e')) && nextIntegerValue(true)) {
return true;
} else {
index = lastGoodIndex;
return false;
}
return (nextCharacter('E') || nextCharacter('e')) && nextIntegerValue(true);
}
}
@ -533,7 +601,12 @@ public class UriTokenizer {
return false;
}
/**
* Moves past a JSON string if found; otherwise leaves the index unchanged.
* @return whether a JSON string has been found at the current index
*/
private boolean nextJsonString() {
final int lastGoodIndex = index;
if (nextCharacter('"')) {
do {
if (nextCharacter('\\')) {
@ -541,6 +614,7 @@ public class UriTokenizer {
|| nextCharacter('n') || nextCharacter('f') || nextCharacter('r')
|| nextCharacter('"') || nextCharacter('/') || nextCharacter('\\')
|| nextCharacter('u') && nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit())) {
index = lastGoodIndex;
return false;
}
} else if (nextCharacter('"')) {
@ -548,16 +622,17 @@ public class UriTokenizer {
} else {
index++;
}
} while (index < pathSegment.length());
} while (index < parseString.length());
index = lastGoodIndex;
return false;
}
index = lastGoodIndex;
return false;
}
private boolean nextJsonValue() {
return nextConstant("null") || nextConstant("true") || nextConstant("false")
// If a double or decimal number is not found, the index must be reset; the internal methods don't do that.
|| next(TokenKind.PrimitiveDoubleValue) || next(TokenKind.PrimitiveDecimalValue) || nextIntegerValue(true)
|| nextDoubleValue() || nextDecimalValue() || nextIntegerValue(true)
|| nextJsonString()
|| nextJsonArrayOrObject();
}
@ -566,25 +641,42 @@ public class UriTokenizer {
return nextJsonString() && nextCharacter(':') && nextJsonValue();
}
/**
* Moves past a JSON array or object if found; otherwise leaves the index unchanged.
* @return whether a JSON array or object has been found at the current index
*/
private boolean nextJsonArrayOrObject() {
final int lastGoodIndex = index;
if (nextCharacter('[')) {
if (nextJsonValue()) {
while (nextCharacter(',')) {
if (!nextJsonValue()) {
index = lastGoodIndex;
return false;
}
}
}
return nextCharacter(']');
if (nextCharacter(']')) {
return true;
} else {
index = lastGoodIndex;
return false;
}
} else if (nextCharacter('{')) {
if (nextJsonMember()) {
while (nextCharacter(',')) {
if (!nextJsonMember()) {
index = lastGoodIndex;
return false;
}
}
}
return nextCharacter('}');
if (nextCharacter('}')) {
return true;
} else {
index = lastGoodIndex;
return false;
}
} else {
return false;
}

View File

@ -20,24 +20,22 @@ package org.apache.olingo.server.core.uri;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collections;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.edmx.EdmxReference;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriInfoKind;
import org.apache.olingo.server.api.uri.UriResourceAction;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
import org.apache.olingo.server.api.uri.queryoption.QueryOption;
import org.apache.olingo.server.core.uri.UriInfoImpl;
import org.apache.olingo.server.core.uri.UriResourceActionImpl;
import org.apache.olingo.server.core.uri.UriResourceEntitySetImpl;
import org.apache.olingo.server.core.uri.queryoption.AliasQueryOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.CustomQueryOptionImpl;
@ -52,15 +50,11 @@ 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.TopOptionImpl;
import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
import org.apache.olingo.server.tecsvc.provider.EntityTypeProvider;
import org.junit.Test;
import org.mockito.Mockito;
public class UriInfoImplTest {
private static final Edm edm = OData.newInstance().createServiceMetadata(
new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
@Test
public void kind() {
final UriInfo uriInfo = new UriInfoImpl().setKind(UriInfoKind.all);
@ -184,9 +178,7 @@ public class UriInfoImplTest {
@Test
public void entityTypeCast() {
final EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETKeyNav);
assertNotNull(entityType);
final EdmEntityType entityType = Mockito.mock(EdmEntityType.class);
final UriInfo uriInfo = new UriInfoImpl()
.setEntityTypeCast(entityType);
assertEquals(entityType, uriInfo.getEntityTypeCast());

View File

@ -0,0 +1,94 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.uri.parser;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.List;
import org.apache.olingo.server.api.uri.queryoption.QueryOption;
import org.junit.Test;
public class UriDecoderTest {
@Test
public void split() throws Exception {
assertTrue(UriDecoder.splitAndDecodePath("").isEmpty());
assertTrue(UriDecoder.splitAndDecodePath("/").isEmpty());
assertEquals(Arrays.asList("a"), UriDecoder.splitAndDecodePath("a"));
assertEquals(Arrays.asList("a"), UriDecoder.splitAndDecodePath("a/"));
assertEquals(Arrays.asList("a"), UriDecoder.splitAndDecodePath("/a"));
assertEquals(Arrays.asList("a", "a"), UriDecoder.splitAndDecodePath("a/a"));
assertEquals(Arrays.asList("a", "a"), UriDecoder.splitAndDecodePath("/a/a"));
}
@Test
public void path() throws Exception {
assertEquals(Arrays.asList("a", "entitySet('/')", "bcd"),
UriDecoder.splitAndDecodePath("a/entitySet('%2F')/b%63d"));
}
@Test
public void options() throws Exception {
assertTrue(UriDecoder.splitAndDecodeOptions("").isEmpty());
checkOption("a", "a", "");
checkOption("a=b", "a", "b");
checkOption("=", "", "");
checkOption("=b", "", "b");
checkOption("a&c", "a", "");
checkOption("a&c", "c", "");
checkOption("a=b&c", "a", "b");
checkOption("a=b&c", "c", "");
checkOption("a=b&c=d", "a", "b");
checkOption("a=b&c=d", "c", "d");
checkOption("=&=", "", "");
assertEquals(2, UriDecoder.splitAndDecodeOptions("=&=").size());
checkOption("=&c=d", "", "");
checkOption("=&c=d", "c", "d");
checkOption("a%62c=d%65f", "abc", "def");
checkOption("a='%26%3D'", "a", "'&='");
}
@Test(expected = UriParserSyntaxException.class)
public void wrongPercentEncoding() throws Exception {
UriDecoder.splitAndDecodePath("%wrong");
}
private void checkOption(final String query, final String name, final String value)
throws UriParserSyntaxException {
final List<QueryOption> options = UriDecoder.splitAndDecodeOptions(query);
for (final QueryOption option : options) {
if (option.getName().equals(name)) {
assertEquals(value, option.getText());
return;
}
}
fail("Option " + name + " not found!");
}
}

View File

@ -51,7 +51,7 @@ public class UriTokenizerTest {
@Test
public void sequence() {
final UriTokenizer tokenizer = new UriTokenizer("(A=1,B=2);");
final UriTokenizer tokenizer = new UriTokenizer("(A=1,B=2);.*/+");
assertTrue(tokenizer.next(TokenKind.OPEN));
assertFalse(tokenizer.next(TokenKind.OPEN));
assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
@ -68,6 +68,10 @@ public class UriTokenizerTest {
assertFalse(tokenizer.next(TokenKind.EOF));
assertTrue(tokenizer.next(TokenKind.CLOSE));
assertTrue(tokenizer.next(TokenKind.SEMI));
assertTrue(tokenizer.next(TokenKind.DOT));
assertTrue(tokenizer.next(TokenKind.STAR));
assertTrue(tokenizer.next(TokenKind.SLASH));
assertTrue(tokenizer.next(TokenKind.PLUS));
assertTrue(tokenizer.next(TokenKind.EOF));
}
@ -100,8 +104,10 @@ public class UriTokenizerTest {
public void qualifiedName() {
assertTrue(new UriTokenizer("namespace.name").next(TokenKind.QualifiedName));
final UriTokenizer tokenizer = new UriTokenizer("multi.part.namespace.name");
final UriTokenizer tokenizer = new UriTokenizer("multi.part.namespace.name.1");
assertTrue(tokenizer.next(TokenKind.QualifiedName));
assertTrue(tokenizer.next(TokenKind.DOT));
assertTrue(tokenizer.next(TokenKind.PrimitiveIntegerValue));
assertTrue(tokenizer.next(TokenKind.EOF));
assertFalse(new UriTokenizer("name").next(TokenKind.QualifiedName));
@ -334,6 +340,7 @@ public class UriTokenizerTest {
assertFalse(new UriTokenizer("[,1]").next(TokenKind.jsonArrayOrObject));
assertFalse(new UriTokenizer("[1,,2]").next(TokenKind.jsonArrayOrObject));
assertFalse(new UriTokenizer("[1,x]").next(TokenKind.jsonArrayOrObject));
assertFalse(new UriTokenizer("[+\"x\"]").next(TokenKind.jsonArrayOrObject));
assertFalse(new UriTokenizer("{\"name\":1,}").next(TokenKind.jsonArrayOrObject));
assertFalse(new UriTokenizer("{,\"name\":1}").next(TokenKind.jsonArrayOrObject));
assertFalse(new UriTokenizer("{\"name\":1,,\"name2\":2}").next(TokenKind.jsonArrayOrObject));
@ -350,6 +357,7 @@ public class UriTokenizerTest {
assertFalse(new UriTokenizer("[\"\\u1\"]").next(TokenKind.jsonArrayOrObject));
assertFalse(new UriTokenizer("[\"\\u12x\"]").next(TokenKind.jsonArrayOrObject));
assertFalse(new UriTokenizer("[\"\\u123x\"]").next(TokenKind.jsonArrayOrObject));
wrongToken(TokenKind.jsonArrayOrObject, "[{\"name\":+123.456},null]", '\\');
}
private void wrongToken(final TokenKind kind, final String value, final char disturbCharacter) {
@ -358,6 +366,7 @@ public class UriTokenizerTest {
final UriTokenizer tokenizer = new UriTokenizer(value + disturbCharacter);
assertTrue(tokenizer.next(kind));
assertEquals(value, tokenizer.getText());
assertFalse(tokenizer.next(TokenKind.EOF));
// Place the disturbing character at every position in the value string
// and check that this leads to a failed token recognition.

View File

@ -40,18 +40,19 @@ import org.apache.olingo.server.api.uri.UriResourceKind;
import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
import org.apache.olingo.server.core.uri.parser.UriParserException;
import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
import org.apache.olingo.server.core.uri.parser.UriParserSemanticException.MessageKeys;
import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
import org.apache.olingo.server.core.uri.parser.search.SearchParserException;
import org.apache.olingo.server.core.uri.testutil.FilterValidator;
import org.apache.olingo.server.core.uri.testutil.TestUriValidator;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
import org.apache.olingo.server.tecsvc.provider.ActionProvider;
import org.apache.olingo.server.tecsvc.provider.ComplexTypeProvider;
import org.apache.olingo.server.tecsvc.provider.ContainerProvider;
import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
import org.apache.olingo.server.tecsvc.provider.EntityTypeProvider;
import org.apache.olingo.server.tecsvc.provider.EnumTypeProvider;
import org.apache.olingo.server.tecsvc.provider.FunctionProvider;
import org.apache.olingo.server.tecsvc.provider.PropertyProvider;
import org.apache.olingo.server.tecsvc.provider.TypeDefinitionProvider;
import org.junit.Ignore;
@ -2731,17 +2732,6 @@ public class TestFullResourcePath {
.isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
.isType(EntityTypeProvider.nameETKeyNav);
testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')", "$select=olingo.odata.test1.ETBaseTwoKeyNav"
+ "/PropertyInt16")
.isKind(UriInfoKind.resource).goPath()
.first()
.isKeyPredicate(0, "PropertyInt16", "1")
.isKeyPredicate(1, "PropertyString", "'2'")
.isSelectStartType(0, EntityTypeProvider.nameETBaseTwoKeyNav)
.goSelectItem(0)
.first()
.isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
testUri.run("ESKeyNav", "$expand=NavPropertyETKeyNavOne($select=PropertyInt16)")
.isKind(UriInfoKind.resource)
.goPath().first()
@ -2763,17 +2753,6 @@ public class TestFullResourcePath {
.goUpExpandValidator()
.isSelectText("PropertyCompNav/PropertyInt16");
testUri.run("ESMixEnumDefCollComp",
"$select=PropertyEnumString,PropertyDefString,CollPropertyEnumString,CollPropertyDefString")
.isKind(UriInfoKind.resource)
.goSelectItemPath(0).isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
.goUpUriValidator()
.goSelectItemPath(1).isPrimitiveProperty("PropertyDefString", TypeDefinitionProvider.nameTDString, false)
.goUpUriValidator()
.goSelectItemPath(2).isPrimitiveProperty("CollPropertyEnumString", EnumTypeProvider.nameENString, true)
.goUpUriValidator()
.goSelectItemPath(3).isPrimitiveProperty("CollPropertyDefString", TypeDefinitionProvider.nameTDString, true);
testUri.runEx("ESKeyNav", "$expand=undefined")
.isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
testUri.runEx("ESTwoKeyNav", "$expand=PropertyCompNav/undefined")
@ -2814,6 +2793,134 @@ public class TestFullResourcePath {
.isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
}
@Test
public void select() throws Exception {
testUri.run("ESTwoKeyNav", "$select=*")
.isSelectItemStar(0);
testUri.run("ESTwoKeyNav", "$select=olingo.odata.test1.*")
.isSelectItemAllOp(0, new FullQualifiedName("olingo.odata.test1", "*"));
testUri.run("ESTwoKeyNav", "$select=Namespace1_Alias.*")
.isSelectItemAllOp(0, new FullQualifiedName("Namespace1_Alias", "*"));
testUri.run("ESTwoKeyNav", "$select=PropertyString")
.goSelectItemPath(0).isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
testUri.run("ESTwoKeyNav", "$select=PropertyComp")
.goSelectItemPath(0).isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false);
testUri.run("ESAllPrim", "$select=PropertyTimeOfDay,PropertyDate,NavPropertyETTwoPrimOne")
.isKind(UriInfoKind.resource)
.goSelectItemPath(0).first().isPrimitiveProperty("PropertyTimeOfDay", PropertyProvider.nameTimeOfDay, false)
.goUpUriValidator()
.goSelectItemPath(1).first().isPrimitiveProperty("PropertyDate", PropertyProvider.nameDate, false)
.goUpUriValidator()
.goSelectItemPath(2).first().isNavProperty("NavPropertyETTwoPrimOne", EntityTypeProvider.nameETTwoPrim, false);
testUri.run("ESMixEnumDefCollComp",
"$select=PropertyEnumString,PropertyDefString,CollPropertyEnumString,CollPropertyDefString")
.isKind(UriInfoKind.resource)
.goSelectItemPath(0).isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
.goUpUriValidator()
.goSelectItemPath(1).isPrimitiveProperty("PropertyDefString", TypeDefinitionProvider.nameTDString, false)
.goUpUriValidator()
.goSelectItemPath(2).isPrimitiveProperty("CollPropertyEnumString", EnumTypeProvider.nameENString, true)
.goUpUriValidator()
.goSelectItemPath(3).isPrimitiveProperty("CollPropertyDefString", TypeDefinitionProvider.nameTDString, true);
testUri.run("ESTwoKeyNav", "$select=PropertyComp/PropertyInt16")
.goSelectItemPath(0)
.first()
.isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
.n()
.isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
testUri.run("ESTwoKeyNav", "$select=PropertyComp/PropertyComp")
.goSelectItemPath(0)
.first()
.isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
.n()
.isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTAllPrim, false);
testUri.run("ESTwoKeyNav", "$select=olingo.odata.test1.ETBaseTwoKeyNav")
.isSelectStartType(0, EntityTypeProvider.nameETBaseTwoKeyNav);
testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')",
"$select=olingo.odata.test1.ETBaseTwoKeyNav/PropertyInt16")
.isKind(UriInfoKind.resource).goPath()
.first()
.isKeyPredicate(0, "PropertyInt16", "1")
.isKeyPredicate(1, "PropertyString", "'2'")
.isSelectStartType(0, EntityTypeProvider.nameETBaseTwoKeyNav)
.goSelectItem(0)
.first()
.isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='1')/PropertyCompNav",
"$select=olingo.odata.test1.CTTwoBasePrimCompNav")
.isSelectStartType(0, ComplexTypeProvider.nameCTTwoBasePrimCompNav);
testUri.run("ESTwoKeyNav", "$select=PropertyCompNav/olingo.odata.test1.CTTwoBasePrimCompNav")
.goSelectItemPath(0)
.first()
.isComplexProperty("PropertyCompNav", ComplexTypeProvider.nameCTBasePrimCompNav, false)
.isTypeFilter(ComplexTypeProvider.nameCTTwoBasePrimCompNav);
testUri.run("ESTwoKeyNav", "$select=PropertyCompNav/Namespace1_Alias.CTTwoBasePrimCompNav/PropertyInt16")
.goSelectItemPath(0)
.first()
.isComplexProperty("PropertyCompNav", ComplexTypeProvider.nameCTBasePrimCompNav, false)
.isTypeFilter(ComplexTypeProvider.nameCTTwoBasePrimCompNav)
.n()
.isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
testUri.run("ESAllPrim", "$select=olingo.odata.test1.BAESAllPrimRTETAllPrim")
.goSelectItemPath(0)
.first()
.isAction(ActionProvider.nameBAESAllPrimRTETAllPrim.getName());
testUri.run("ESTwoKeyNav", "$select=Namespace1_Alias.BFCESTwoKeyNavRTString")
.goSelectItemPath(0)
.first()
.isFunction(FunctionProvider.nameBFCESTwoKeyNavRTString.getName());
testUri.run("ESTwoKeyNav", "$select=olingo.odata.test1.BFCESTwoKeyNavRTStringParam(ParameterComp)")
.goSelectItemPath(0)
.first()
.isFunction(FunctionProvider.nameBFCESTwoKeyNavRTStringParam.getName());
testUri.runEx("ESMixPrimCollComp", "$select=wrong")
.isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
testUri.runEx("ESMixPrimCollComp", "$select=PropertyComp/wrong")
.isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
testUri.runEx("ESMixPrimCollComp", "$select=PropertyComp///PropertyInt16")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
testUri.runEx("ESMixPrimCollComp", "$select=/PropertyInt16")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
testUri.runEx("ESMixPrimCollComp", "$select=PropertyInt16+")
.isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
testUri.runEx("ESTwoKeyNav", "$select=olingo.odata.test1.1")
.isExSemantic(MessageKeys.UNKNOWN_PART);
testUri.runEx("ESTwoKeyNav", "$select=olingo.odata.test1.ETKeyNav")
.isExSemantic(MessageKeys.INCOMPATIBLE_TYPE_FILTER);
testUri.runEx("ESTwoKeyNav", "$select=PropertyCompNav/olingo.odata.test1.CTTwoPrim")
.isExSemantic(MessageKeys.INCOMPATIBLE_TYPE_FILTER);
testUri.runEx("ESTwoKeyNav", "$select=PropertyCompNav/olingo.odata.test1.CTwrong")
.isExSemantic(MessageKeys.UNKNOWN_TYPE);
testUri.runEx("ESTwoKeyNav", "$select=PropertyCompNav/.")
.isExSemantic(MessageKeys.UNKNOWN_PART);
testUri.runEx("ESTwoKeyNav", "$select=PropertyCompNav/olingo.odata.test1.CTTwoBasePrimCompNav/.")
.isExSemantic(MessageKeys.UNKNOWN_PART);
testUri.runEx("AIRT", "$select=wrong")
.isExSemantic(MessageKeys.ONLY_FOR_TYPED_PARTS);
testUri.runEx("AIRT", "$select=olingo.odata.test1.BAESAllPrimRT")
.isExSemantic(MessageKeys.ONLY_FOR_TYPED_PARTS);
testUri.runEx("ESTwoKeyNav", "$select=olingo.odata.test1.BFwrong")
.isExSemantic(MessageKeys.UNKNOWN_PART);
testUri.runEx("ESTwoKeyNav", "$select=olingo.odata.test1.BFCESTwoKeyNavRTStringParam()")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
testUri.runEx("ESTwoKeyNav", "$select=Namespace1_Alias.BFCESTwoKeyNavRTStringParam(ParameterComp,...)")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
}
@Test
public void runTop() throws Exception {
// top
@ -5950,7 +6057,7 @@ public class TestFullResourcePath {
testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
+ "(ParameterComp={\"PropertyInt16\":1,\"PropertyString\":\"Test\"})")
.isExSemantic(UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE);
.isExSemantic(MessageKeys.INVALID_KEY_VALUE);
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=null)")
.isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
@ -5964,7 +6071,7 @@ public class TestFullResourcePath {
testUri.run("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test='null'");
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test,UnknownParam=1)", "@test='null'")
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND);
.isExSemantic(MessageKeys.FUNCTION_NOT_FOUND);
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test='null'");
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test=null");
@ -5975,7 +6082,7 @@ public class TestFullResourcePath {
.isExSyntax(UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS);
testUri.runEx("ESAllPrim", "$filter=FINRTInt16() eq 0")
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED);
.isExSemantic(MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED);
testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"")

View File

@ -22,13 +22,11 @@ import java.util.Arrays;
import java.util.Collections;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.edmx.EdmxReference;
import org.apache.olingo.server.api.uri.UriInfoKind;
import org.apache.olingo.server.api.uri.UriResourceKind;
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
import org.apache.olingo.server.core.uri.testutil.FilterValidator;
import org.apache.olingo.server.core.uri.testutil.ResourceValidator;
@ -1112,64 +1110,6 @@ public class TestUriParserImpl {
.isMethod(MethodKind.GEOINTERSECTS, 2);
}
@Test
public void testSelect() throws Exception {
testUri.run("ESTwoKeyNav", "$select=*")
.isSelectItemStar(0);
testUri.run("ESTwoKeyNav", "$select=olingo.odata.test1.*")
.isSelectItemAllOp(0, new FullQualifiedName("olingo.odata.test1", "*"));
testUri.run("ESTwoKeyNav", "$select=PropertyString")
.goSelectItemPath(0).isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
testUri.run("ESTwoKeyNav", "$select=PropertyComp")
.goSelectItemPath(0).isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false);
testUri.run("ESTwoKeyNav", "$select=PropertyComp/PropertyInt16")
.goSelectItemPath(0)
.first()
.isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
.n()
.isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
testUri.run("ESTwoKeyNav", "$select=PropertyComp/PropertyComp")
.goSelectItemPath(0)
.first()
.isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
.n()
.isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTAllPrim, false);
testUri.run("ESTwoKeyNav", "$select=olingo.odata.test1.ETBaseTwoKeyNav")
.isSelectStartType(0, EntityTypeProvider.nameETBaseTwoKeyNav);
testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='1')/PropertyCompNav",
"$select=olingo.odata.test1.CTTwoBasePrimCompNav")
.isSelectStartType(0, ComplexTypeProvider.nameCTTwoBasePrimCompNav);
testUri.run("ESTwoKeyNav", "$select=PropertyCompNav/olingo.odata.test1.CTTwoBasePrimCompNav")
.goSelectItemPath(0)
.first()
.isComplexProperty("PropertyCompNav", ComplexTypeProvider.nameCTBasePrimCompNav, false)
.n()
.isTypeFilterOnCollection(ComplexTypeProvider.nameCTTwoBasePrimCompNav);
testUri.run("ESAllPrim", "$select=PropertyTimeOfDay,PropertyDate,PropertyTimeOfDay")
.isKind(UriInfoKind.resource)
.goSelectItemPath(0).first().isPrimitiveProperty("PropertyTimeOfDay", PropertyProvider.nameTimeOfDay, false)
.goUpUriValidator()
.goSelectItemPath(1).first().isPrimitiveProperty("PropertyDate", PropertyProvider.nameDate, false);
testUri.runEx("ESMixPrimCollComp", "$select=wrong")
.isExSemantic(UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
testUri.runEx("ESMixPrimCollComp", "$select=PropertyComp/wrong")
.isExSemantic(UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
testUri.runEx("ESMixPrimCollComp", "$select=PropertyComp///PropertyInt16")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
testUri.runEx("ESMixPrimCollComp", "$select=/PropertyInt16")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
}
private final String encode(final String uriPart) {
return uriPart.replaceAll(":", "%3A");
}

View File

@ -1,150 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.uri.parser;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
public class RawUriTest {
private RawUri runRawParser(final String path, final String query, final int skipSegments)
throws UriParserSyntaxException {
return UriDecoder.decodeUri(path, query, null, skipSegments);
}
@Test
public void testOption() throws Exception {
RawUri rawUri;
rawUri = runRawParser("", "", 0);
checkOptionCount(rawUri, 0);
rawUri = runRawParser("", "a", 0);
checkOption(rawUri, 0, "a", "");
rawUri = runRawParser("", "a=b", 0);
checkOption(rawUri, 0, "a", "b");
rawUri = runRawParser("", "=", 0);
checkOption(rawUri, 0, "", "");
rawUri = runRawParser("", "=b", 0);
checkOption(rawUri, 0, "", "b");
rawUri = runRawParser("", "a&c", 0);
checkOption(rawUri, 0, "a", "");
checkOption(rawUri, 1, "c", "");
rawUri = runRawParser("", "a=b&c", 0);
checkOption(rawUri, 0, "a", "b");
checkOption(rawUri, 1, "c", "");
rawUri = runRawParser("", "a=b&c=d", 0);
checkOption(rawUri, 0, "a", "b");
checkOption(rawUri, 1, "c", "d");
rawUri = runRawParser("", "=&=", 0);
checkOption(rawUri, 0, "", "");
checkOption(rawUri, 1, "", "");
rawUri = runRawParser("", "=&c=d", 0);
checkOption(rawUri, 0, "", "");
checkOption(rawUri, 1, "c", "d");
}
private void checkOption(final RawUri rawUri, final int index, final String name, final String value) {
RawUri.QueryOption option = rawUri.queryOptionListDecoded.get(index);
assertEquals(name, option.name);
assertEquals(value, option.value);
}
private void checkOptionCount(final RawUri rawUri, final int count) {
assertEquals(count, rawUri.queryOptionListDecoded.size());
}
@Test
public void testPath() throws Exception {
RawUri rawUri;
rawUri = runRawParser("", null, 0);
checkPath(rawUri, "", Collections.<String> emptyList());
rawUri = runRawParser("/", null, 0);
checkPath(rawUri, "/", Collections.<String> emptyList());
rawUri = runRawParser("/entitySet", null, 0);
checkPath(rawUri, "/entitySet", Arrays.asList("entitySet"));
rawUri = runRawParser("//entitySet", null, 0);
checkPath(rawUri, "//entitySet", Arrays.asList("entitySet"));
rawUri = runRawParser("entitySet", null, 0);
checkPath(rawUri, "entitySet", Arrays.asList("entitySet"));
rawUri = runRawParser("/nonServiceSegment/entitySet", null, 0);
checkPath(rawUri, "/nonServiceSegment/entitySet", Arrays.asList("nonServiceSegment", "entitySet"));
rawUri = runRawParser("/nonServiceSegment/entitySet", null, 1);
checkPath(rawUri, "/nonServiceSegment/entitySet", Arrays.asList("entitySet"));
rawUri = runRawParser("nonServiceSegment/entitySet", null, 0);
checkPath(rawUri, "nonServiceSegment/entitySet", Arrays.asList("nonServiceSegment", "entitySet"));
rawUri = runRawParser("nonServiceSegment/entitySet", null, 1);
checkPath(rawUri, "nonServiceSegment/entitySet", Arrays.asList("entitySet"));
rawUri = runRawParser("non//Service/Segment///entitySet/", null, 3);
checkPath(rawUri, "non//Service/Segment///entitySet/", Arrays.asList("entitySet"));
rawUri = runRawParser("/a", "abc=xx+yz", 0);
checkPath(rawUri, "/a", Arrays.asList("a"));
}
@Test
public void testSplit() {
assertTrue(UriDecoder.splitSkipEmpty("", '/').isEmpty());
assertTrue(UriDecoder.splitSkipEmpty("/", '/').isEmpty());
assertEquals(Arrays.asList("a"), UriDecoder.splitSkipEmpty("a", '/'));
assertEquals(Arrays.asList("a"), UriDecoder.splitSkipEmpty("a/", '/'));
assertEquals(Arrays.asList("a"), UriDecoder.splitSkipEmpty("/a", '/'));
assertEquals(Arrays.asList("a", "a"), UriDecoder.splitSkipEmpty("a/a", '/'));
assertEquals(Arrays.asList("a", "a"), UriDecoder.splitSkipEmpty("/a/a", '/'));
}
private void checkPath(final RawUri rawUri, final String path, final List<String> list) {
assertEquals(path, rawUri.path);
assertEquals(list.size(), rawUri.pathSegmentListDecoded.size());
for (int i = 0; i < list.size(); i++) {
assertEquals(list.get(i), rawUri.pathSegmentListDecoded.get(i));
}
}
@Test(expected = UriParserSyntaxException.class)
public void wrongPercentEncoding() throws Exception {
runRawParser("%wrong", null, 0);
}
}

View File

@ -1,59 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.uri.testutil;
import org.antlr.v4.runtime.DefaultErrorStrategy;
import org.antlr.v4.runtime.DiagnosticErrorListener;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.core.uri.antlr.UriParserParser;
import org.apache.olingo.server.core.uri.parser.Parser;
public class ParserWithLogging extends Parser {
TestErrorLogger errorCollector1;
TestErrorLogger errorCollector2;
public ParserWithLogging(final Edm edm, final OData odata) {
super(edm, odata);
errorCollector1 = new TestErrorLogger("Stage 1", 1);
errorCollector2 = new TestErrorLogger("Stage 2", 1);
}
@Override
protected void addStage2ErrorStategy(final UriParserParser parser) {
// Don't throw an at first syntax error, so the error listener will be called
parser.setErrorHandler(new DefaultErrorStrategy());
}
@Override
protected void addStage1ErrorListener(final UriParserParser parser) {
// Log error to console
parser.removeErrorListeners();
parser.addErrorListener(errorCollector1);
parser.addErrorListener(new DiagnosticErrorListener());
}
@Override
protected void addStage2ErrorListener(final UriParserParser parser) {
// Log error to console
parser.removeErrorListeners();
parser.addErrorListener(errorCollector2);
parser.addErrorListener(new DiagnosticErrorListener());
}
}

View File

@ -52,6 +52,7 @@ import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.SelectItem;
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
import org.apache.olingo.server.core.uri.parser.Parser;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
import org.apache.olingo.server.core.uri.validator.UriValidator;
@ -85,7 +86,7 @@ public class ResourceValidator implements TestValidator {
// --- Execution ---
public ResourceValidator run(final String path) {
ParserWithLogging testParser = new ParserWithLogging(edm, odata);
Parser testParser = new Parser(edm, odata);
UriInfo uriInfoTmp = null;
uriPathInfo = null;

View File

@ -1,105 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.uri.testutil;
import java.util.BitSet;
import java.util.Collections;
import java.util.List;
import org.antlr.v4.runtime.ANTLRErrorListener;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import org.antlr.v4.runtime.atn.ATNConfigSet;
import org.antlr.v4.runtime.dfa.DFA;
import org.apache.olingo.server.core.uri.antlr.UriLexer;
class TestErrorLogger implements ANTLRErrorListener {
private String prefix;
private int logLevel = 0;
public TestErrorLogger(final String prefix, final int logLevel) {
this.prefix = prefix;
this.logLevel = logLevel;
}
@Override
public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol, final int line,
final int charPositionInLine,
final String msg, final RecognitionException e) {
if (logLevel > 0) {
System.out.println("\n" + prefix + " -- SyntaxError");
trace(recognizer, offendingSymbol, line, charPositionInLine, msg, e);
}
}
@Override
public void reportAmbiguity(final Parser recognizer, final DFA dfa, final int startIndex, final int stopIndex,
final boolean exact,
final BitSet ambigAlts, final ATNConfigSet configs) {
// Test
}
@Override
public void reportAttemptingFullContext(final Parser recognizer, final DFA dfa, final int startIndex,
final int stopIndex,
final BitSet conflictingAlts, final ATNConfigSet configs) {
// Test
}
@Override
public void reportContextSensitivity(final Parser recognizer, final DFA dfa, final int startIndex,
final int stopIndex, final int prediction,
final ATNConfigSet configs) {
// Test
}
private void printStack(final Recognizer<?, ?> recognizer) {
List<String> stack = ((Parser) recognizer).getRuleInvocationStack();
Collections.reverse(stack);
System.out.println(" rule stack: " + stack);
}
public void trace(final Recognizer<?, ?> recognizer, final Object offendingSymbol,
final int line, final int charPositionInLine, final String msg, final RecognitionException e) {
System.out.println("Error message: " + msg);
printStack(recognizer);
System.out.println(" line/char :" + line + " / " + charPositionInLine);
System.out.println(" sym :" + offendingSymbol);
if (e != null && e.getOffendingToken() != null) {
String lexerTokenName = "";
try {
lexerTokenName = UriLexer.VOCABULARY.getDisplayName(e.getOffendingToken().getType());
} catch (ArrayIndexOutOfBoundsException es) {
lexerTokenName = "token error";
}
System.out.println(" tokenname:" + lexerTokenName);
}
}
}

View File

@ -29,35 +29,18 @@ import org.apache.olingo.server.core.uri.antlr.UriLexer;
public class TokenValidator {
private String input = null;
private List<? extends Token> tokens = null;
private Token curToken = null;
private Exception curException = null;
private int startMode;
private int logLevel = 0;
// --- Setup ---
public TokenValidator log(final int logLevel) {
this.logLevel = logLevel;
return this;
}
// --- Execution ---
public TokenValidator run(final String uri) {
input = uri;
tokens = parseInput(uri);
if (logLevel > 0) {
showTokens();
}
first();
exFirst();
logLevel = 0;
return this;
}
@ -87,31 +70,6 @@ public class TokenValidator {
return this;
}
public TokenValidator exLast() {
// curException = exceptions.get(exceptions.size() - 1);
return this;
}
// navigate within the exception list
public TokenValidator exFirst() {
try {
// curException = exceptions.get(0);
} catch (IndexOutOfBoundsException ex) {
curException = null;
}
return this;
}
public TokenValidator exAt(final int index) {
try {
// curException = exceptions.get(index);
} catch (IndexOutOfBoundsException ex) {
curException = null;
}
return this;
}
// --- Validation ---
public TokenValidator isText(final String expected) {
@ -162,32 +120,8 @@ public class TokenValidator {
private List<? extends Token> parseInput(final String input) {
ANTLRInputStream inputStream = new ANTLRInputStream(input);
UriLexer lexer = new UriLexerWithTrace(inputStream, logLevel, startMode);
// lexer.addErrorListener(new ErrorCollector(this));
UriLexer lexer = new UriLexer(inputStream);
lexer.mode(startMode);
return lexer.getAllTokens();
}
public TokenValidator showTokens() {
boolean first = true;
System.out.println("input: " + input);
String nL = "\n";
String out = "[" + nL;
for (Token token : tokens) {
if (!first) {
out += ",";
first = false;
}
int index = token.getType();
if (index != -1) {
out += "\"" + token.getText() + "\"" + " " + UriLexer.VOCABULARY.getDisplayName(index) + nL;
} else {
out += "\"" + token.getText() + "\"" + " " + index + nL;
}
}
out += ']';
System.out.println("tokens: " + out);
return this;
}
}

View File

@ -1,85 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.uri.testutil;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.Token;
import org.apache.olingo.server.core.uri.antlr.UriLexer;
public class UriLexerWithTrace extends UriLexer {
int logLevel = 0;
public UriLexerWithTrace(final ANTLRInputStream antlrInputStream, final int logLevel) {
super(antlrInputStream);
this.logLevel = logLevel;
}
public UriLexerWithTrace(final ANTLRInputStream antlrInputStream, final int logLevel, final int mode) {
super(antlrInputStream);
super.mode(mode);
this.logLevel = logLevel;
}
@Override
public void emit(final Token token) {
if (logLevel > 1) {
String out = String.format("%1$-" + 20 + "s", token.getText());
int tokenType = token.getType();
if (tokenType == -1) {
out += "-1/EOF";
} else {
out += UriLexer.VOCABULARY.getDisplayName(tokenType);
}
System.out.println("Lexer.emit(...):" + out);
}
super.emit(token);
}
@Override
public void pushMode(final int m) {
String out = UriLexer.modeNames[_mode] + "-->";
super.pushMode(m);
out += UriLexer.modeNames[_mode];
if (logLevel > 1) {
System.out.println(out + " ");
}
}
@Override
public int popMode() {
String out = UriLexer.modeNames[_mode] + "-->";
int m = super.popMode();
out += UriLexer.modeNames[_mode];
if (logLevel > 1) {
System.out.println(out + " ");
}
return m;
}
}