olingo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From chri...@apache.org
Subject [2/2] olingo-odata4 git commit: [OLINGO-834] $select parser in Java + clean-up
Date Thu, 10 Dec 2015 14:50:25 GMT
[OLINGO-834] $select parser in Java + clean-up

Signed-off-by: Christian Amend <christian.amend@sap.com>


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/ea625e81
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/ea625e81
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/ea625e81

Branch: refs/heads/OLINGO-834_RefactorUriParsing
Commit: ea625e81779085670027fbafce677f7b58cd25c3
Parents: 7bc932a
Author: Klaus Straubinger <klaus.straubinger@sap.com>
Authored: Thu Dec 10 14:56:58 2015 +0100
Committer: Christian Amend <christian.amend@sap.com>
Committed: Thu Dec 10 15:42:05 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/ea625e81/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/ea625e81/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/ea625e81/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/ea625e81/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/ea625e81/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/ea625e81/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/ea625e81/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();


Mime
View raw message