[OLINGO-834] $select parser in Java + clean-up Signed-off-by: Christian Amend <[email protected]>
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/d7e23bf8 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/d7e23bf8 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/d7e23bf8 Branch: refs/heads/OLINGO-834_Filter_Parser Commit: d7e23bf89a61df8fdbe53728f201a2686c7f79fc Parents: ef19c9b Author: Klaus Straubinger <[email protected]> Authored: Thu Dec 10 14:56:58 2015 +0100 Committer: Christian Amend <[email protected]> Committed: Thu Dec 10 15:51:45 2015 +0100 ---------------------------------------------------------------------- .../uri/parser/CheckFullContextListener.java | 60 --- .../olingo/server/core/uri/parser/Parser.java | 507 ++++++++++--------- .../olingo/server/core/uri/parser/RawUri.java | 46 -- .../server/core/uri/parser/SelectParser.java | 241 +++++++++ .../server/core/uri/parser/UriContext.java | 17 +- .../server/core/uri/parser/UriDecoder.java | 74 +-- .../core/uri/parser/UriParseTreeVisitor.java | 176 ++----- .../server/core/uri/parser/UriTokenizer.java | 166 ++++-- .../olingo/server/core/uri/UriInfoImplTest.java | 204 ++++++++ .../server/core/uri/parser/UriDecoderTest.java | 94 ++++ .../core/uri/parser/UriTokenizerTest.java | 13 +- .../olingo/server/core/uri/UriInfoImplTest.java | 212 -------- .../core/uri/antlr/TestFullResourcePath.java | 159 +++++- .../core/uri/antlr/TestUriParserImpl.java | 60 --- .../server/core/uri/parser/RawUriTest.java | 150 ------ .../core/uri/testutil/ParserWithLogging.java | 59 --- .../core/uri/testutil/ResourceValidator.java | 3 +- .../core/uri/testutil/TestErrorLogger.java | 105 ---- .../core/uri/testutil/TokenValidator.java | 70 +-- .../core/uri/testutil/UriLexerWithTrace.java | 85 ---- 20 files changed, 1164 insertions(+), 1337 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/CheckFullContextListener.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/CheckFullContextListener.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/CheckFullContextListener.java deleted file mode 100644 index 86efdca..0000000 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/CheckFullContextListener.java +++ /dev/null @@ -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"); - } - -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java index 5caaaeb..0b53e69 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java @@ -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 - - // first, read the decoded path segments - final String firstSegment = uri.pathSegmentListDecoded.isEmpty() ? "" : uri.pathSegmentListDecoded.get(0); - - if (firstSegment.isEmpty()) { - ensureLastSegment(firstSegment, 0, uri.pathSegmentListDecoded.size()); - 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("$metadata")) { - ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size()); - context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.metadata); - context.contextUriInfo.setFragment(uri.fragment); - - } else if (firstSegment.equals("$all")) { - ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size()); - context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.all); - - } 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); - } + final List<String> pathSegmentsDecoded = UriDecoder.splitAndDecodePath(path); + final int numberOfSegments = pathSegmentsDecoded.size(); - } 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)); - } + // first, read the decoded path segments + final String firstSegment = numberOfSegments == 0 ? "" : pathSegmentsDecoded.get(0); + + if (firstSegment.isEmpty()) { + ensureLastSegment(firstSegment, 0, numberOfSegments); + context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.service); + } else if (firstSegment.equals("$batch")) { + ensureLastSegment(firstSegment, 1, numberOfSegments); + context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.batch); + + } 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, 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.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 = 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)); } - context.contextUriInfo.addResourcePart(segment); + 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); + 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 - for (final RawUri.QueryOption option : uri.queryOptionListDecoded) { - if (option.name.startsWith("$")) { - SystemQueryOption systemOption = null; - if (option.name.equals(SystemQueryOptionKind.FILTER.toString())) { + // 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(option.value, ParserEntryRules.FilterExpression); + (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 (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 (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 (option.name.equals(SystemQueryOptionKind.EXPAND.toString())) { + } else if (optionName.equals(SystemQueryOptionKind.EXPAND.toString())) { + try { ExpandItemsEOFContext ctxExpandItems = - (ExpandItemsEOFContext) parseRule(option.value, ParserEntryRules.ExpandItems); + (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 (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 (optionName.equals(SystemQueryOptionKind.ID.toString())) { + IdOptionImpl idOption = new IdOptionImpl(); + idOption.setText(optionValue); + idOption.setValue(optionValue); + 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 (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 (option.name.equals(SystemQueryOptionKind.ORDERBY.toString())) { + } else if (optionName.equals(SystemQueryOptionKind.ORDERBY.toString())) { + try { OrderByEOFContext ctxOrderByExpression = - (OrderByEOFContext) parseRule(option.value, ParserEntryRules.Orderby); + (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 (option.name.equals(SystemQueryOptionKind.SEARCH.toString())) { - systemOption = new SearchParser().parse(option.value); + } 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 (option.name.equals(SystemQueryOptionKind.SELECT.toString())) { - SelectEOFContext ctxSelectEOF = - (SelectEOFContext) parseRule(option.value, ParserEntryRules.Select); - systemOption = (SelectOptionImpl) uriParseTreeVisitor.visitSelectEOF(ctxSelectEOF); + } 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 (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 if (optionName.equals(SystemQueryOptionKind.SKIPTOKEN.toString())) { + SkipTokenOptionImpl skipTokenOption = new SkipTokenOptionImpl(); + skipTokenOption.setText(optionValue); + skipTokenOption.setValue(optionValue); + systemOption = skipTokenOption; - } else { - throw new UriParserSyntaxException("Unknown system query option!", - UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION, option.name); - } + } else if (optionName.equals(SystemQueryOptionKind.TOP.toString())) { + TopOptionImpl topOption = new TopOptionImpl(); + topOption.setText(optionValue); 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); + 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 (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 { + } 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 { + 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 (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(option.value, ParserEntryRules.FilterExpression); + (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(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); } - + context.contextUriInfo.addAlias((AliasQueryOption) new AliasQueryOptionImpl() + .setAliasValue(expression) + .setName(optionName) + .setText(NULL.equals(optionValue) ? null : optionValue)); } else { - context.contextUriInfo.addCustomQueryOption((CustomQueryOption) - new CustomQueryOptionImpl() - .setName(option.name) - .setText(option.value)); + throw new UriParserSyntaxException("Alias already specified! Name: " + optionName, + UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS, optionName); } - } - return context.contextUriInfo; - } catch (ParseCancellationException e) { - throw e.getCause() instanceof UriParserException ? - (UriParserException) e.getCause() : - new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX); + } else { + context.contextUriInfo.addCustomQueryOption((CustomQueryOption) option); + } } + + 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()); - } - } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/RawUri.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/RawUri.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/RawUri.java deleted file mode 100644 index 42e0a0f..0000000 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/RawUri.java +++ /dev/null @@ -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; - } - - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java new file mode 100644 index 0000000..3d933d2 --- /dev/null +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java @@ -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); + } + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java index b6b6fda..c0db85b 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java @@ -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>(); } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriDecoder.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriDecoder.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriDecoder.java index 4649ac5..4dd7e1c 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriDecoder.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriDecoder.java @@ -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; - } - - 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))); + /** 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 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) { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java index 8740d66..c58327b 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java @@ -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()); @@ -1147,33 +1098,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> { } @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() .setMethod(MethodKind.DATE) @@ -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();
