You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2015/03/06 10:05:44 UTC

olingo-odata4 git commit: [OLINGO-557] better server dispatching for functions

Repository: olingo-odata4
Updated Branches:
  refs/heads/master a3789c7cc -> 33c1f02c0


[OLINGO-557] better server dispatching for functions

Change-Id: I4581fb226870672d2b2ff10617a97a40dd9543e3

Signed-off-by: Christian Amend <ch...@apache.org>


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

Branch: refs/heads/master
Commit: 33c1f02c071fc981b552d0095b9d7070d72a6b99
Parents: a3789c7
Author: Klaus Straubinger <kl...@sap.com>
Authored: Fri Mar 6 09:56:31 2015 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Fri Mar 6 10:00:38 2015 +0100

----------------------------------------------------------------------
 .../apache/olingo/server/core/ODataHandler.java | 450 ++++++++++---------
 .../olingo/server/core/ODataHandlerTest.java    | 141 ++++--
 2 files changed, 324 insertions(+), 267 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/33c1f02c/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
index e057696..c8928b5 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
@@ -28,6 +28,8 @@ import org.apache.olingo.commons.api.edm.EdmFunction;
 import org.apache.olingo.commons.api.edm.EdmFunctionImport;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
 import org.apache.olingo.commons.api.edm.EdmReturnType;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
 import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.format.ODataFormat;
@@ -144,69 +146,69 @@ public class ODataHandler {
   }
 
   private void processInternal(final ODataRequest request, final ODataResponse response)
-          throws ODataHandlerException, UriParserException, UriValidationException, ContentNegotiatorException,
-          ODataApplicationException, SerializerException, DeserializerException {
+      throws ODataHandlerException, UriParserException, UriValidationException, ContentNegotiatorException,
+      ODataApplicationException, SerializerException, DeserializerException {
     validateODataVersion(request, response);
 
     uriInfo = new Parser().parseUri(request.getRawODataPath(), request.getRawQueryPath(), null,
-            serviceMetadata.getEdm());
+        serviceMetadata.getEdm());
 
     final HttpMethod method = request.getMethod();
     new UriValidator().validate(uriInfo, method);
 
     switch (uriInfo.getKind()) {
-      case metadata:
-        if (method == HttpMethod.GET) {
-          final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                  request, customContentTypeSupport, RepresentationType.METADATA);
-          selectProcessor(MetadataProcessor.class)
-                  .readMetadata(request, response, uriInfo, requestedContentType);
-        } else {
-          throw new ODataHandlerException("HttpMethod " + method + " not allowed for metadata document",
-                  ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
-        }
-        break;
-
-      case service:
-        if (method == HttpMethod.GET) {
-          if ("".equals(request.getRawODataPath())) {
-            selectProcessor(RedirectProcessor.class).redirect(request, response);
-          } else {
-            final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                    request, customContentTypeSupport, RepresentationType.SERVICE);
-
-            selectProcessor(ServiceDocumentProcessor.class)
-                    .readServiceDocument(request, response, uriInfo, requestedContentType);
-          }
+    case metadata:
+      if (method == HttpMethod.GET) {
+        final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
+            request, customContentTypeSupport, RepresentationType.METADATA);
+        selectProcessor(MetadataProcessor.class)
+            .readMetadata(request, response, uriInfo, requestedContentType);
+      } else {
+        throw new ODataHandlerException("HttpMethod " + method + " not allowed for metadata document",
+            ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+      }
+      break;
+
+    case service:
+      if (method == HttpMethod.GET) {
+        if ("".equals(request.getRawODataPath())) {
+          selectProcessor(RedirectProcessor.class).redirect(request, response);
         } else {
-          throw new ODataHandlerException("HttpMethod " + method + " not allowed for service document",
-                  ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+          final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
+              request, customContentTypeSupport, RepresentationType.SERVICE);
+
+          selectProcessor(ServiceDocumentProcessor.class)
+              .readServiceDocument(request, response, uriInfo, requestedContentType);
         }
-        break;
+      } else {
+        throw new ODataHandlerException("HttpMethod " + method + " not allowed for service document",
+            ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+      }
+      break;
 
-      case resource:
-        handleResourceDispatching(request, response);
-        break;
+    case resource:
+      handleResourceDispatching(request, response);
+      break;
 
-      case batch:
-        if (method == HttpMethod.POST) {
-          final BatchProcessor bp = selectProcessor(BatchProcessor.class);
-          final BatchHandler handler = new BatchHandler(this, bp);
-          handler.process(request, response, true);
-        } else {
-          throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
-                  ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
-        }
-        break;
+    case batch:
+      if (method == HttpMethod.POST) {
+        final BatchProcessor bp = selectProcessor(BatchProcessor.class);
+        final BatchHandler handler = new BatchHandler(this, bp);
+        handler.process(request, response, true);
+      } else {
+        throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
+            ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+      }
+      break;
 
-      default:
-        throw new ODataHandlerException("not implemented",
-                ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
+    default:
+      throw new ODataHandlerException("not implemented",
+          ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
     }
   }
 
   public void handleException(final ODataRequest request, final ODataResponse response,
-                              final ODataServerError serverError) {
+      final ODataServerError serverError) {
 
     ErrorProcessor exceptionProcessor;
     try {
@@ -218,8 +220,8 @@ public class ODataHandler {
     ContentType requestedContentType;
     try {
       requestedContentType = ContentNegotiator.doContentNegotiation(
-              uriInfo == null ? null : uriInfo.getFormatOption(), request, customContentTypeSupport,
-              RepresentationType.ERROR);
+          uriInfo == null ? null : uriInfo.getFormatOption(), request, customContentTypeSupport,
+          RepresentationType.ERROR);
     } catch (final ContentNegotiatorException e) {
       requestedContentType = ODataFormat.JSON.getContentType(ODataServiceVersion.V40);
     }
@@ -227,262 +229,263 @@ public class ODataHandler {
   }
 
   private void handleResourceDispatching(final ODataRequest request, final ODataResponse response)
-          throws ODataHandlerException, ContentNegotiatorException, ODataApplicationException,
-          SerializerException, DeserializerException {
+      throws ODataHandlerException, ContentNegotiatorException, ODataApplicationException,
+      SerializerException, DeserializerException {
 
     final int lastPathSegmentIndex = uriInfo.getUriResourceParts().size() - 1;
     final UriResource lastPathSegment = uriInfo.getUriResourceParts().get(lastPathSegmentIndex);
 
     switch (lastPathSegment.getKind()) {
-      case action:
-        handleActionDispatching(request, response, (UriResourceAction) lastPathSegment);
-        break;
-
-      case function:
-        handleFunctionDispatching(request, response, (UriResourceFunction) lastPathSegment);
-        break;
-
-      case entitySet:
-      case navigationProperty:
-        handleEntityDispatching(request, response, (UriResourcePartTyped) lastPathSegment);
-        break;
-
-      case count:
-        handleCountDispatching(request, response, lastPathSegmentIndex);
-        break;
-
-      case primitiveProperty:
-        handlePrimitivePropertyDispatching(request, response, false,
-                ((UriResourceProperty) lastPathSegment).isCollection());
-        break;
-
-      case complexProperty:
-        handleComplexPropertyDispatching(request, response, false,
-                ((UriResourceProperty) lastPathSegment).isCollection());
-        break;
-
-      case value:
-        handleValueDispatching(request, response, lastPathSegmentIndex);
-        break;
-
-      case ref:
-        handleReferenceDispatching(request, response, lastPathSegmentIndex);
-        break;
-
-      default:
-        throw new ODataHandlerException("not implemented",
-                ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
+    case action:
+      handleActionDispatching(request, response, (UriResourceAction) lastPathSegment);
+      break;
+
+    case function:
+      handleFunctionDispatching(request, response, (UriResourceFunction) lastPathSegment);
+      break;
+
+    case entitySet:
+    case navigationProperty:
+      handleEntityDispatching(request, response, (UriResourcePartTyped) lastPathSegment);
+      break;
+
+    case count:
+      handleCountDispatching(request, response, lastPathSegmentIndex);
+      break;
+
+    case primitiveProperty:
+      handlePrimitivePropertyDispatching(request, response, false,
+          ((UriResourceProperty) lastPathSegment).isCollection());
+      break;
+
+    case complexProperty:
+      handleComplexPropertyDispatching(request, response, false,
+          ((UriResourceProperty) lastPathSegment).isCollection());
+      break;
+
+    case value:
+      handleValueDispatching(request, response, lastPathSegmentIndex);
+      break;
+
+    case ref:
+      handleReferenceDispatching(request, response, lastPathSegmentIndex);
+      break;
+
+    default:
+      throw new ODataHandlerException("not implemented",
+          ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
     }
   }
 
   private void handleFunctionDispatching(final ODataRequest request, final ODataResponse response,
-                                         final UriResourceFunction uriResourceFunction)
-          throws ODataHandlerException, SerializerException, ContentNegotiatorException,
-          ODataApplicationException, DeserializerException {
+      final UriResourceFunction uriResourceFunction)
+      throws ODataHandlerException, SerializerException, ContentNegotiatorException,
+      ODataApplicationException, DeserializerException {
     final HttpMethod method = request.getMethod();
-    if(method != HttpMethod.GET) {
+    if (method != HttpMethod.GET) {
       throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
-              ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+          ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
     }
 
     EdmFunctionImport functionImport = uriResourceFunction.getFunctionImport();
     // could be null for bound functions
-    if(functionImport == null) {
+    if (functionImport == null) {
       throw new ODataHandlerException("Bound functions are not implemented yet",
-              ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
+          ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
     }
 
     List<EdmFunction> unboundFunctions = functionImport.getUnboundFunctions();
-    if(unboundFunctions == null || unboundFunctions.isEmpty()) {
+    if (unboundFunctions == null || unboundFunctions.isEmpty()) {
       throw new ODataHandlerException("No unbound function defined for function import",
-              ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
+          ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
     }
     EdmReturnType returnType = unboundFunctions.get(0).getReturnType();
     handleOperationDispatching(request, response, false, returnType);
   }
 
   private void handleActionDispatching(final ODataRequest request, final ODataResponse response,
-                                       final UriResourceAction uriResourceAction)
-          throws ODataHandlerException, SerializerException, ContentNegotiatorException,
-          ODataApplicationException, DeserializerException {
+      final UriResourceAction uriResourceAction)
+      throws ODataHandlerException, SerializerException, ContentNegotiatorException,
+      ODataApplicationException, DeserializerException {
 
     final HttpMethod method = request.getMethod();
-    if(request.getMethod() != HttpMethod.POST) {
+    if (request.getMethod() != HttpMethod.POST) {
       throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
-              ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+          ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
     }
 
     EdmActionImport actionImport = uriResourceAction.getActionImport();
     // could be null for bound actions
-    if(actionImport == null) {
+    if (actionImport == null) {
       throw new ODataHandlerException("Bound actions are not implemented yet",
-              ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
+          ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
     }
 
     EdmAction unboundActions = actionImport.getUnboundAction();
-    if(unboundActions == null) {
+    if (unboundActions == null) {
       throw new ODataHandlerException("No unbound function defined for function import",
-              ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
+          ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
     }
     EdmReturnType returnType = unboundActions.getReturnType();
     handleOperationDispatching(request, response, true, returnType);
   }
 
-
   private void handleOperationDispatching(final ODataRequest request, final ODataResponse response,
-                                          final boolean isAction, final EdmReturnType edmReturnTypeKind)
-          throws ODataHandlerException, SerializerException, ContentNegotiatorException,
-          ODataApplicationException, DeserializerException {
+      final boolean isAction, final EdmReturnType edmReturnTypeKind)
+      throws ODataHandlerException, SerializerException, ContentNegotiatorException,
+      ODataApplicationException, DeserializerException {
 
     switch (edmReturnTypeKind.getType().getKind()) {
-      case ENTITY:
-        handleEntityDispatching(request, response, edmReturnTypeKind.isCollection(), false, isAction);
-        break;
-      case PRIMITIVE:
-        handlePrimitivePropertyDispatching(request, response, isAction, edmReturnTypeKind.isCollection());
-        break;
-      case COMPLEX:
-        handleComplexPropertyDispatching(request, response, isAction, edmReturnTypeKind.isCollection());
-        break;
-      default:
-        throw new ODataHandlerException("not implemented",
-                ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
+    case ENTITY:
+      handleEntityDispatching(request, response, edmReturnTypeKind.isCollection(), false, isAction);
+      break;
+    case PRIMITIVE:
+      handlePrimitivePropertyDispatching(request, response, isAction, edmReturnTypeKind.isCollection());
+      break;
+    case COMPLEX:
+      handleComplexPropertyDispatching(request, response, isAction, edmReturnTypeKind.isCollection());
+      break;
+    default:
+      throw new ODataHandlerException("not implemented",
+          ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
     }
   }
 
-
   private void handleReferenceDispatching(final ODataRequest request, final ODataResponse response,
-                                          final int lastPathSegmentIndex)
-          throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException,
-          DeserializerException {
+      final int lastPathSegmentIndex)
+      throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException,
+      DeserializerException {
     final HttpMethod method = request.getMethod();
     if (((UriResourcePartTyped) uriInfo.getUriResourceParts().get(lastPathSegmentIndex - 1)).isCollection()) {
       if (method == HttpMethod.GET) {
         final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                request, customContentTypeSupport, RepresentationType.COLLECTION_REFERENCE);
+            request, customContentTypeSupport, RepresentationType.COLLECTION_REFERENCE);
         selectProcessor(ReferenceCollectionProcessor.class)
-                .readReferenceCollection(request, response, uriInfo, responseFormat);
+            .readReferenceCollection(request, response, uriInfo, responseFormat);
       } else if (method == HttpMethod.POST) {
         final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
         checkContentTypeSupport(requestFormat, RepresentationType.REFERENCE);
         selectProcessor(ReferenceProcessor.class)
-                .createReference(request, response, uriInfo, requestFormat);
+            .createReference(request, response, uriInfo, requestFormat);
       } else {
         throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
-                ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+            ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
       }
     } else {
       if (method == HttpMethod.GET) {
         final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                request, customContentTypeSupport, RepresentationType.REFERENCE);
+            request, customContentTypeSupport, RepresentationType.REFERENCE);
         selectProcessor(ReferenceProcessor.class).readReference(request, response, uriInfo, responseFormat);
       } else if (method == HttpMethod.PUT || method == HttpMethod.PATCH) {
         final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
         checkContentTypeSupport(requestFormat, RepresentationType.REFERENCE);
         selectProcessor(ReferenceProcessor.class)
-                .updateReference(request, response, uriInfo, requestFormat);
+            .updateReference(request, response, uriInfo, requestFormat);
       } else if (method == HttpMethod.DELETE) {
         selectProcessor(ReferenceProcessor.class)
-                .deleteReference(request, response, uriInfo);
+            .deleteReference(request, response, uriInfo);
       } else {
         throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
-                ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+            ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
       }
     }
   }
 
   private void handleValueDispatching(final ODataRequest request, final ODataResponse response,
-                                      final int lastPathSegmentIndex)
-          throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException,
-          DeserializerException {
+      final int lastPathSegmentIndex)
+      throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException,
+      DeserializerException {
     final HttpMethod method = request.getMethod();
     final UriResource resource = uriInfo.getUriResourceParts().get(lastPathSegmentIndex - 1);
-    if (resource instanceof UriResourceProperty) {
+    if (resource instanceof UriResourceProperty
+        || resource instanceof UriResourceFunction
+        && ((UriResourceFunction) resource).getType().getKind() == EdmTypeKind.PRIMITIVE) {
+      final EdmType type = resource instanceof UriResourceProperty ?
+          ((UriResourceProperty) resource).getType() : ((UriResourceFunction) resource).getType();
       final RepresentationType valueRepresentationType =
-              ((UriResourceProperty) resource).getType() ==
-                      EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary) ?
-                      RepresentationType.BINARY : RepresentationType.VALUE;
+          type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary) ?
+              RepresentationType.BINARY : RepresentationType.VALUE;
       if (method == HttpMethod.GET) {
         final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                request, customContentTypeSupport, valueRepresentationType);
+            request, customContentTypeSupport, valueRepresentationType);
 
         selectProcessor(PrimitiveValueProcessor.class)
-                .readPrimitiveValue(request, response, uriInfo, requestedContentType);
-      } else if (method == HttpMethod.PUT) {
+            .readPrimitiveValue(request, response, uriInfo, requestedContentType);
+      } else if (method == HttpMethod.PUT && resource instanceof UriResourceProperty) {
         final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
         checkContentTypeSupport(requestFormat, valueRepresentationType);
         final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                request, customContentTypeSupport, valueRepresentationType);
+            request, customContentTypeSupport, valueRepresentationType);
         selectProcessor(PrimitiveValueProcessor.class)
-                .updatePrimitive(request, response, uriInfo, requestFormat, responseFormat);
-      } else if (method == HttpMethod.DELETE) {
+            .updatePrimitive(request, response, uriInfo, requestFormat, responseFormat);
+      } else if (method == HttpMethod.DELETE && resource instanceof UriResourceProperty) {
         selectProcessor(PrimitiveValueProcessor.class).deletePrimitive(request, response, uriInfo);
       } else {
         throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
-                ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+            ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
       }
     } else {
       if (method == HttpMethod.GET) {
         final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                request, customContentTypeSupport, RepresentationType.MEDIA);
+            request, customContentTypeSupport, RepresentationType.MEDIA);
         selectProcessor(MediaEntityProcessor.class)
-                .readMediaEntity(request, response, uriInfo, requestedContentType);
-      } else if (method == HttpMethod.PUT) {
+            .readMediaEntity(request, response, uriInfo, requestedContentType);
+      } else if (method == HttpMethod.PUT && resource instanceof UriResourceEntitySet) {
         final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
         final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                request, customContentTypeSupport, RepresentationType.ENTITY);
+            request, customContentTypeSupport, RepresentationType.ENTITY);
         selectProcessor(MediaEntityProcessor.class)
-                .updateMediaEntity(request, response, uriInfo, requestFormat, responseFormat);
-      } else if (method == HttpMethod.DELETE) {
+            .updateMediaEntity(request, response, uriInfo, requestFormat, responseFormat);
+      } else if (method == HttpMethod.DELETE && resource instanceof UriResourceEntitySet) {
         selectProcessor(MediaEntityProcessor.class).deleteEntity(request, response, uriInfo);
       } else {
         throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
-                ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+            ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
       }
     }
   }
 
   private void handleComplexPropertyDispatching(final ODataRequest request, final ODataResponse response,
-                                                final boolean isAction, final boolean isCollection)
-          throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException,
-          DeserializerException {
+      final boolean isAction, final boolean isCollection)
+      throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException,
+      DeserializerException {
 
     final HttpMethod method = request.getMethod();
     final RepresentationType complexRepresentationType = isCollection ?
-            RepresentationType.COLLECTION_COMPLEX : RepresentationType.COMPLEX;
+        RepresentationType.COLLECTION_COMPLEX : RepresentationType.COMPLEX;
     if (method == HttpMethod.GET) {
       final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-              request, customContentTypeSupport, complexRepresentationType);
+          request, customContentTypeSupport, complexRepresentationType);
       if (complexRepresentationType == RepresentationType.COMPLEX) {
         selectProcessor(ComplexProcessor.class)
-                .readComplex(request, response, uriInfo, requestedContentType);
+            .readComplex(request, response, uriInfo, requestedContentType);
       } else {
         selectProcessor(ComplexCollectionProcessor.class)
-                .readComplexCollection(request, response, uriInfo, requestedContentType);
+            .readComplexCollection(request, response, uriInfo, requestedContentType);
       }
     } else if (method == HttpMethod.PUT || method == HttpMethod.PATCH) {
       final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
       checkContentTypeSupport(requestFormat, complexRepresentationType);
       final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-              request, customContentTypeSupport, complexRepresentationType);
+          request, customContentTypeSupport, complexRepresentationType);
       if (complexRepresentationType == RepresentationType.COMPLEX) {
         selectProcessor(ComplexProcessor.class)
-                .updateComplex(request, response, uriInfo, requestFormat, responseFormat);
+            .updateComplex(request, response, uriInfo, requestFormat, responseFormat);
       } else {
         selectProcessor(ComplexCollectionProcessor.class)
-                .updateComplexCollection(request, response, uriInfo, requestFormat, responseFormat);
+            .updateComplexCollection(request, response, uriInfo, requestFormat, responseFormat);
       }
     } else if (method == HttpMethod.POST && isAction) {
       final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
       checkContentTypeSupport(requestFormat, complexRepresentationType);
       final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-              request, customContentTypeSupport, complexRepresentationType);
+          request, customContentTypeSupport, complexRepresentationType);
       if (complexRepresentationType == RepresentationType.COMPLEX) {
         selectProcessor(ActionComplexProcessor.class)
-                .processActionComplex(request, response, uriInfo, requestFormat, responseFormat);
+            .processActionComplex(request, response, uriInfo, requestFormat, responseFormat);
       } else {
         selectProcessor(ActionComplexCollectionProcessor.class)
-                .processActionComplexCollection(request, response, uriInfo, requestFormat, responseFormat);
+            .processActionComplexCollection(request, response, uriInfo, requestFormat, responseFormat);
       }
     } else if (method == HttpMethod.DELETE) {
       if (complexRepresentationType == RepresentationType.COMPLEX) {
@@ -492,38 +495,38 @@ public class ODataHandler {
       }
     } else {
       throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
-              ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+          ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
     }
   }
 
   private void handlePrimitivePropertyDispatching(final ODataRequest request, final ODataResponse response,
-                                                  boolean isAction, final boolean isCollection)
-          throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException,
-          DeserializerException {
+      boolean isAction, final boolean isCollection)
+      throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException,
+      DeserializerException {
 
     final HttpMethod method = request.getMethod();
     final RepresentationType representationType = isCollection ?
-            RepresentationType.COLLECTION_PRIMITIVE : RepresentationType.PRIMITIVE;
+        RepresentationType.COLLECTION_PRIMITIVE : RepresentationType.PRIMITIVE;
     if (method == HttpMethod.GET) {
       final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-              request, customContentTypeSupport, representationType);
+          request, customContentTypeSupport, representationType);
       if (representationType == RepresentationType.PRIMITIVE) {
         selectProcessor(PrimitiveProcessor.class).readPrimitive(request, response, uriInfo, requestedContentType);
       } else {
         selectProcessor(PrimitiveCollectionProcessor.class)
-                .readPrimitiveCollection(request, response, uriInfo, requestedContentType);
+            .readPrimitiveCollection(request, response, uriInfo, requestedContentType);
       }
     } else if (method == HttpMethod.PUT || method == HttpMethod.PATCH) {
       final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
       checkContentTypeSupport(requestFormat, representationType);
       final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-              request, customContentTypeSupport, representationType);
+          request, customContentTypeSupport, representationType);
       if (representationType == RepresentationType.PRIMITIVE) {
         selectProcessor(PrimitiveProcessor.class)
-                .updatePrimitive(request, response, uriInfo, requestFormat, responseFormat);
+            .updatePrimitive(request, response, uriInfo, requestFormat, responseFormat);
       } else {
         selectProcessor(PrimitiveCollectionProcessor.class)
-                .updatePrimitiveCollection(request, response, uriInfo, requestFormat, responseFormat);
+            .updatePrimitiveCollection(request, response, uriInfo, requestFormat, responseFormat);
       }
     } else if (method == HttpMethod.DELETE) {
       if (representationType == RepresentationType.PRIMITIVE) {
@@ -535,143 +538,148 @@ public class ODataHandler {
       final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
       checkContentTypeSupport(requestFormat, representationType);
       final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-              request, customContentTypeSupport, representationType);
+          request, customContentTypeSupport, representationType);
       if (representationType == RepresentationType.PRIMITIVE) {
         selectProcessor(ActionPrimitiveProcessor.class)
-                .processActionPrimitive(request, response, uriInfo, requestFormat, responseFormat);
+            .processActionPrimitive(request, response, uriInfo, requestFormat, responseFormat);
       } else {
         selectProcessor(ActionPrimitiveCollectionProcessor.class)
-                .processActionPrimitiveCollection(request, response, uriInfo, requestFormat, responseFormat);
+            .processActionPrimitiveCollection(request, response, uriInfo, requestFormat, responseFormat);
       }
     } else {
       throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
-              ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+          ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
     }
   }
 
   private void handleCountDispatching(final ODataRequest request, final ODataResponse response,
-                                      final int lastPathSegmentIndex)
-          throws ODataApplicationException, SerializerException, ODataHandlerException {
+      final int lastPathSegmentIndex)
+      throws ODataApplicationException, SerializerException, ODataHandlerException {
 
     final HttpMethod method = request.getMethod();
     if (method == HttpMethod.GET) {
       final UriResource resource = uriInfo.getUriResourceParts().get(lastPathSegmentIndex - 1);
-      if (resource instanceof UriResourceEntitySet || resource instanceof UriResourceNavigation) {
+      if (resource instanceof UriResourceEntitySet
+          || resource instanceof UriResourceNavigation
+          || resource instanceof UriResourceFunction
+          && ((UriResourceFunction) resource).getType().getKind() == EdmTypeKind.ENTITY) {
         selectProcessor(CountEntityCollectionProcessor.class)
-                .countEntityCollection(request, response, uriInfo);
-      } else if (resource instanceof UriResourcePrimitiveProperty) {
+            .countEntityCollection(request, response, uriInfo);
+      } else if (resource instanceof UriResourcePrimitiveProperty
+          || resource instanceof UriResourceFunction
+          && ((UriResourceFunction) resource).getType().getKind() == EdmTypeKind.PRIMITIVE) {
         selectProcessor(CountPrimitiveCollectionProcessor.class)
-                .countPrimitiveCollection(request, response, uriInfo);
+            .countPrimitiveCollection(request, response, uriInfo);
       } else {
         selectProcessor(CountComplexCollectionProcessor.class)
-                .countComplexCollection(request, response, uriInfo);
+            .countComplexCollection(request, response, uriInfo);
       }
     } else {
       throw new ODataHandlerException("HTTP method " + method + " is not allowed for count.",
-              ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+          ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
     }
   }
 
   private void handleEntityDispatching(final ODataRequest request, final ODataResponse response,
-                                       final UriResourcePartTyped uriResourcePart)
-          throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException,
-          DeserializerException {
+      final UriResourcePartTyped uriResourcePart)
+      throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException,
+      DeserializerException {
     handleEntityDispatching(request, response, uriResourcePart.isCollection(), isMedia(uriResourcePart), false);
   }
 
   private void handleEntityDispatching(final ODataRequest request, final ODataResponse response,
-                                       final boolean isCollection, final boolean isMedia, boolean isAction)
-          throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException,
-          DeserializerException {
+      final boolean isCollection, final boolean isMedia, boolean isAction)
+      throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException,
+      DeserializerException {
 
     final HttpMethod method = request.getMethod();
     if (isCollection) {
       if (method == HttpMethod.GET) {
         final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                request, customContentTypeSupport, RepresentationType.COLLECTION_ENTITY);
+            request, customContentTypeSupport, RepresentationType.COLLECTION_ENTITY);
 
         selectProcessor(EntityCollectionProcessor.class)
-                .readEntityCollection(request, response, uriInfo, requestedContentType);
+            .readEntityCollection(request, response, uriInfo, requestedContentType);
       } else if (method == HttpMethod.POST) {
-          final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
+        final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
         if (isMedia) {
           final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                  request, customContentTypeSupport, RepresentationType.ENTITY);
+              request, customContentTypeSupport, RepresentationType.ENTITY);
           selectProcessor(MediaEntityProcessor.class)
-                  .createMediaEntity(request, response, uriInfo, requestFormat, responseFormat);
-        } else if(isAction) {
+              .createMediaEntity(request, response, uriInfo, requestFormat, responseFormat);
+        } else if (isAction) {
           checkContentTypeSupport(requestFormat, RepresentationType.ENTITY);
           final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                  request, customContentTypeSupport, RepresentationType.ENTITY);
+              request, customContentTypeSupport, RepresentationType.ENTITY);
           selectProcessor(ActionEntityCollectionProcessor.class)
-                  .processActionEntityCollection(request, response, uriInfo, requestFormat, responseFormat);
+              .processActionEntityCollection(request, response, uriInfo, requestFormat, responseFormat);
         } else {
           checkContentTypeSupport(requestFormat, RepresentationType.ENTITY);
           final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                  request, customContentTypeSupport, RepresentationType.ENTITY);
+              request, customContentTypeSupport, RepresentationType.ENTITY);
           selectProcessor(EntityProcessor.class)
-                  .createEntity(request, response, uriInfo, requestFormat, responseFormat);
+              .createEntity(request, response, uriInfo, requestFormat, responseFormat);
         }
       } else {
         throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
-                ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+            ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
       }
     } else {
       if (method == HttpMethod.GET) {
         final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                request, customContentTypeSupport, RepresentationType.ENTITY);
+            request, customContentTypeSupport, RepresentationType.ENTITY);
 
         selectProcessor(EntityProcessor.class).readEntity(request, response, uriInfo, requestedContentType);
       } else if (method == HttpMethod.PUT || method == HttpMethod.PATCH) {
         final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
         checkContentTypeSupport(requestFormat, RepresentationType.ENTITY);
         final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                request, customContentTypeSupport, RepresentationType.ENTITY);
+            request, customContentTypeSupport, RepresentationType.ENTITY);
         selectProcessor(EntityProcessor.class).updateEntity(request, response, uriInfo, requestFormat, responseFormat);
       } else if (method == HttpMethod.POST && isAction) {
         final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
         checkContentTypeSupport(requestFormat, RepresentationType.ENTITY);
         final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-                request, customContentTypeSupport, RepresentationType.ENTITY);
+            request, customContentTypeSupport, RepresentationType.ENTITY);
         selectProcessor(ActionEntityProcessor.class).processActionEntity(
-                request, response, uriInfo, requestFormat, responseFormat);
+            request, response, uriInfo, requestFormat, responseFormat);
       } else if (method == HttpMethod.DELETE) {
         selectProcessor(isMedia ? MediaEntityProcessor.class : EntityProcessor.class)
-                .deleteEntity(request, response, uriInfo);
+            .deleteEntity(request, response, uriInfo);
       } else {
         throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
-                ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
+            ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
       }
     }
   }
 
   private void checkContentTypeSupport(ContentType requestFormat, RepresentationType representationType)
-          throws ODataHandlerException, ContentNegotiatorException {
+      throws ODataHandlerException, ContentNegotiatorException {
     if (!ContentNegotiator.isSupported(requestFormat, customContentTypeSupport, representationType)) {
       final String contentTypeString = requestFormat.toContentTypeString();
       throw new ODataHandlerException("ContentType " + contentTypeString + " is not supported.",
-              ODataHandlerException.MessageKeys.UNSUPPORTED_CONTENT_TYPE, contentTypeString);
+          ODataHandlerException.MessageKeys.UNSUPPORTED_CONTENT_TYPE, contentTypeString);
     }
   }
 
   private void validateODataVersion(final ODataRequest request, final ODataResponse response)
-          throws ODataHandlerException {
+      throws ODataHandlerException {
     final String maxVersion = request.getHeader(HttpHeader.ODATA_MAX_VERSION);
     response.setHeader(HttpHeader.ODATA_VERSION, ODataServiceVersion.V40.toString());
 
     if (maxVersion != null) {
       if (ODataServiceVersion.isBiggerThan(ODataServiceVersion.V40.toString(), maxVersion)) {
         throw new ODataHandlerException("ODataVersion not supported: " + maxVersion,
-                ODataHandlerException.MessageKeys.ODATA_VERSION_NOT_SUPPORTED, maxVersion);
+            ODataHandlerException.MessageKeys.ODATA_VERSION_NOT_SUPPORTED, maxVersion);
       }
     }
   }
 
   private boolean isMedia(final UriResource pathSegment) {
     return pathSegment instanceof UriResourceEntitySet
-            && ((UriResourceEntitySet) pathSegment).getEntityType().hasStream()
-            || pathSegment instanceof UriResourceNavigation
-            && ((EdmEntityType) ((UriResourceNavigation) pathSegment).getType()).hasStream();
+        && ((UriResourceEntitySet) pathSegment).getEntityType().hasStream()
+        || pathSegment instanceof UriResourceNavigation
+        && ((EdmEntityType) ((UriResourceNavigation) pathSegment).getType()).hasStream();
   }
 
   private <T extends Processor> T selectProcessor(final Class<T> cls) throws ODataHandlerException {
@@ -682,7 +690,7 @@ public class ODataHandler {
       }
     }
     throw new ODataHandlerException("Processor: " + cls.getSimpleName() + " not registered.",
-            ODataHandlerException.MessageKeys.PROCESSOR_NOT_IMPLEMENTED, cls.getSimpleName());
+        ODataHandlerException.MessageKeys.PROCESSOR_NOT_IMPLEMENTED, cls.getSimpleName());
   }
 
   public void register(final Processor processor) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/33c1f02c/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java
index 5870439..39cfb63 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java
@@ -97,8 +97,8 @@ public class ODataHandlerTest {
         any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
 
     dispatchMethodNotAllowed(HttpMethod.POST, "/", processor);
-    dispatchMethodNotAllowed(HttpMethod.PUT, "/", processor);
     dispatchMethodNotAllowed(HttpMethod.PATCH, "/", processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, "/", processor);
     dispatchMethodNotAllowed(HttpMethod.DELETE, "/", processor);
   }
 
@@ -135,8 +135,8 @@ public class ODataHandlerTest {
         any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
 
     dispatchMethodNotAllowed(HttpMethod.POST, "$metadata", processor);
-    dispatchMethodNotAllowed(HttpMethod.PUT, "$metadata", processor);
     dispatchMethodNotAllowed(HttpMethod.PATCH, "$metadata", processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, "$metadata", processor);
     dispatchMethodNotAllowed(HttpMethod.DELETE, "$metadata", processor);
   }
 
@@ -296,88 +296,138 @@ public class ODataHandlerTest {
     EntityProcessor entityProcessor = mock(EntityProcessor.class);
     dispatch(HttpMethod.GET, "FICRTETKeyNav()", entityProcessor);
     verify(entityProcessor).readEntity(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
 
     EntityCollectionProcessor entityCollectionProcessor = mock(EntityCollectionProcessor.class);
     dispatch(HttpMethod.GET, "FICRTCollESTwoKeyNavParam(ParameterInt16=123)", entityCollectionProcessor);
     verify(entityCollectionProcessor).readEntityCollection(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+
+    final String entityCountUri = "FICRTCollESTwoKeyNavParam(ParameterInt16=123)/$count";
+    final CountEntityCollectionProcessor entityCountProcessor = mock(CountEntityCollectionProcessor.class);
+    dispatch(HttpMethod.GET, entityCountUri, entityCountProcessor);
+    verify(entityCountProcessor).countEntityCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class));
+    dispatchMethodNotAllowed(HttpMethod.POST, entityCountUri, entityCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, entityCountUri, entityCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, entityCountUri, entityCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, entityCountUri, entityCountProcessor);
 
     PrimitiveProcessor primitiveProcessor = mock(PrimitiveProcessor.class);
     dispatch(HttpMethod.GET, "FICRTString()", primitiveProcessor);
     verify(primitiveProcessor).readPrimitive(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+
+    final String valueUri = "FINRTInt16()/$value";
+    final PrimitiveValueProcessor primitiveValueProcessor = mock(PrimitiveValueProcessor.class);
+    dispatch(HttpMethod.GET, valueUri, primitiveValueProcessor);
+    verify(primitiveValueProcessor).readPrimitiveValue(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+    dispatchMethodNotAllowed(HttpMethod.POST, valueUri, primitiveValueProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, valueUri, primitiveValueProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, valueUri, primitiveValueProcessor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, valueUri, primitiveValueProcessor);
 
+    final String primitiveCollectionUri = "FICRTCollString()";
     PrimitiveCollectionProcessor primitiveCollectionProcessor = mock(PrimitiveCollectionProcessor.class);
-    dispatch(HttpMethod.GET, "FICRTCollString()", primitiveCollectionProcessor);
+    dispatch(HttpMethod.GET, primitiveCollectionUri, primitiveCollectionProcessor);
     verify(primitiveCollectionProcessor).readPrimitiveCollection(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+    dispatchMethodNotAllowed(HttpMethod.POST, primitiveCollectionUri, primitiveCollectionProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, primitiveCollectionUri, primitiveCollectionProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, primitiveCollectionUri, primitiveCollectionProcessor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, primitiveCollectionUri, primitiveCollectionProcessor);
+
+    final String primitiveCountUri = "FICRTCollString()/$count";
+    final CountPrimitiveCollectionProcessor primitiveCountProcessor = mock(CountPrimitiveCollectionProcessor.class);
+    dispatch(HttpMethod.GET, primitiveCountUri, primitiveCountProcessor);
+    verify(primitiveCountProcessor).countPrimitiveCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class));
+    dispatchMethodNotAllowed(HttpMethod.POST, primitiveCountUri, primitiveCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, primitiveCountUri, primitiveCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, primitiveCountUri, primitiveCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, primitiveCountUri, primitiveCountProcessor);
 
     ComplexProcessor complexProcessor = mock(ComplexProcessor.class);
     dispatch(HttpMethod.GET, "FICRTCTTwoPrim()", complexProcessor);
     verify(complexProcessor).readComplex(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
 
     ComplexCollectionProcessor complexCollectionProcessor = mock(ComplexCollectionProcessor.class);
     dispatch(HttpMethod.GET, "FICRTCollCTTwoPrim()", complexCollectionProcessor);
     verify(complexCollectionProcessor).readComplexCollection(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
 
-    dispatchMethodNotAllowed(HttpMethod.POST, "FICRTCollString()", mock(Processor.class));
-    dispatchMethodNotAllowed(HttpMethod.PUT, "FICRTCollString()", mock(Processor.class));
-    dispatchMethodNotAllowed(HttpMethod.DELETE, "FICRTCollString()", mock(Processor.class));
+    final String complexCountUri = "FICRTCollCTTwoPrim()/$count";
+    final CountComplexCollectionProcessor complexCountProcessor = mock(CountComplexCollectionProcessor.class);
+    dispatch(HttpMethod.GET, complexCountUri, complexCountProcessor);
+    verify(complexCountProcessor).countComplexCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class));
+    dispatchMethodNotAllowed(HttpMethod.POST, complexCountUri, complexCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, complexCountUri, complexCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, complexCountUri, complexCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, complexCountUri, complexCountProcessor);
+
+    final String mediaUri = "FICRTESMedia()/$value";
+    final MediaEntityProcessor mediaProcessor = mock(MediaEntityProcessor.class);
+    dispatch(HttpMethod.GET, mediaUri, mediaProcessor);
+    verify(mediaProcessor).readMediaEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+    dispatchMethodNotAllowed(HttpMethod.POST, mediaUri, mediaProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, mediaUri, mediaProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, mediaUri, mediaProcessor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, mediaUri, mediaProcessor);
   }
 
-
   @Test
   public void dispatchAction() throws Exception {
     ActionPrimitiveProcessor primitiveProcessor = mock(ActionPrimitiveProcessor.class);
     dispatch(HttpMethod.POST, ContainerProvider.AIRT_STRING, primitiveProcessor);
     verify(primitiveProcessor).processActionPrimitive(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
-            any(ContentType.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
 
     ActionPrimitiveCollectionProcessor primitiveCollectionProcessor = mock(ActionPrimitiveCollectionProcessor.class);
     dispatch(HttpMethod.POST, ContainerProvider.AIRT_COLL_STRING_TWO_PARAM, primitiveCollectionProcessor);
     verify(primitiveCollectionProcessor).processActionPrimitiveCollection(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
-            any(ContentType.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
 
     ActionComplexProcessor complexProcessor = mock(ActionComplexProcessor.class);
     dispatch(HttpMethod.POST, ContainerProvider.AIRTCT_TWO_PRIM_PARAM, complexProcessor);
     verify(complexProcessor).processActionComplex(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
-            any(ContentType.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
 
     ActionComplexCollectionProcessor complexCollectionProcessor = mock(ActionComplexCollectionProcessor.class);
     dispatch(HttpMethod.POST, ContainerProvider.AIRT_COLL_CT_TWO_PRIM_PARAM, complexCollectionProcessor);
     verify(complexCollectionProcessor).processActionComplexCollection(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
-            any(ContentType.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
 
     ActionEntityProcessor entityProcessor = mock(ActionEntityProcessor.class);
     dispatch(HttpMethod.POST, ContainerProvider.AIRTET_TWO_KEY_TWO_PRIM_PARAM, entityProcessor);
     verify(entityProcessor).processActionEntity(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
-            any(ContentType.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
 
     ActionEntityCollectionProcessor entityCollectionProcessor = mock(ActionEntityCollectionProcessor.class);
     dispatch(HttpMethod.POST, ContainerProvider.AIRT_COLL_ET_KEY_NAV_PARAM, entityCollectionProcessor);
     verify(entityCollectionProcessor).processActionEntityCollection(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
-            any(ContentType.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
 
     ActionEntityProcessor entityProcessorEs = mock(ActionEntityProcessor.class);
     dispatch(HttpMethod.POST, ContainerProvider.AIRTES_ALL_PRIM_PARAM, entityProcessorEs);
     verify(entityProcessorEs).processActionEntity(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
-            any(ContentType.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
 
     ActionEntityCollectionProcessor entityCollectionProcessorEs = mock(ActionEntityCollectionProcessor.class);
     dispatch(HttpMethod.POST, ContainerProvider.AIRT_COLL_ES_ALL_PRIM_PARAM, entityCollectionProcessorEs);
     verify(entityCollectionProcessorEs).processActionEntityCollection(
-            any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
-            any(ContentType.class), any(ContentType.class));
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
 
     dispatchMethodNotAllowed(HttpMethod.GET, "AIRTString", mock(Processor.class));
   }
@@ -391,12 +441,12 @@ public class ODataHandlerTest {
     verify(processor).readEntity(
         any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
 
-    dispatch(HttpMethod.PUT, uri, processor);
+    dispatch(HttpMethod.PATCH, uri, processor);
     verify(processor).updateEntity(
         any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
         any(ContentType.class));
 
-    dispatch(HttpMethod.PATCH, uri, processor);
+    dispatch(HttpMethod.PUT, uri, processor);
     verify(processor, times(2)).updateEntity(
         any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
         any(ContentType.class));
@@ -452,12 +502,12 @@ public class ODataHandlerTest {
     verify(processor).readPrimitive(
         any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
 
-    dispatch(HttpMethod.PUT, uri, processor);
+    dispatch(HttpMethod.PATCH, uri, processor);
     verify(processor).updatePrimitive(
         any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
         any(ContentType.class));
 
-    dispatch(HttpMethod.PATCH, uri, processor);
+    dispatch(HttpMethod.PUT, uri, processor);
     verify(processor, times(2)).updatePrimitive(
         any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
         any(ContentType.class));
@@ -519,8 +569,8 @@ public class ODataHandlerTest {
     verify(processor).countPrimitiveCollection(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class));
 
     dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
-    dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor);
     dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor);
     dispatchMethodNotAllowed(HttpMethod.DELETE, uri, processor);
   }
 
@@ -533,12 +583,12 @@ public class ODataHandlerTest {
     verify(processor).readComplex(
         any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
 
-    dispatch(HttpMethod.PUT, uri, processor);
+    dispatch(HttpMethod.PATCH, uri, processor);
     verify(processor).updateComplex(
         any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
         any(ContentType.class));
 
-    dispatch(HttpMethod.PATCH, uri, processor);
+    dispatch(HttpMethod.PUT, uri, processor);
     verify(processor, times(2)).updateComplex(
         any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
         any(ContentType.class));
@@ -578,8 +628,8 @@ public class ODataHandlerTest {
     verify(processor).countComplexCollection(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class));
 
     dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
-    dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor);
     dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor);
     dispatchMethodNotAllowed(HttpMethod.DELETE, uri, processor);
   }
 
@@ -592,11 +642,11 @@ public class ODataHandlerTest {
     verify(processor).readReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
         any(ContentType.class));
 
-    dispatch(HttpMethod.PUT, uri, processor);
+    dispatch(HttpMethod.PATCH, uri, processor);
     verify(processor).updateReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
         any(ContentType.class));
 
-    dispatch(HttpMethod.PATCH, uri, processor);
+    dispatch(HttpMethod.PUT, uri, processor);
     verify(processor, times(2)).updateReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
         any(ContentType.class));
 
@@ -619,8 +669,8 @@ public class ODataHandlerTest {
     verify(processor).readReferenceCollection(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
         any(ContentType.class));
 
-    dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor);
     dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor);
     dispatchMethodNotAllowed(HttpMethod.DELETE, uri, processor);
   }
 
@@ -631,23 +681,22 @@ public class ODataHandlerTest {
     dispatch(HttpMethod.POST, "ESAllPrim", "", HttpHeader.CONTENT_TYPE, "some/unsupported", errorProcessor);
     verifyZeroInteractions(processor);
     verify(errorProcessor).processError(any(ODataRequest.class), any(ODataResponse.class), any(ODataServerError.class),
-            any(ContentType.class));
+        any(ContentType.class));
   }
 
   private ODataResponse dispatch(final HttpMethod method, final String path, final String query,
       final String headerName, final String headerValue, final Processor processor) {
     Map<String, List<String>> headers = null;
-    if(headerName != null) {
+    if (headerName != null) {
       headers = Collections.singletonMap(headerName, Collections.singletonList(headerValue));
     }
     List<Processor> processors = null;
-    if(processor != null) {
+    if (processor != null) {
       processors = Collections.singletonList(processor);
     }
     return dispatch(method, path, query, headers, processors);
   }
 
-
   private ODataResponse dispatch(final HttpMethod method, final String path, final String query,
       final Map<String, List<String>> headers, final List<Processor> processors) {
     ODataRequest request = new ODataRequest();
@@ -666,9 +715,9 @@ public class ODataHandlerTest {
       }
     }
 
-    if(request.getHeaders(HttpHeader.CONTENT_TYPE) == null) {
+    if (request.getHeaders(HttpHeader.CONTENT_TYPE) == null) {
       request.addHeader(HttpHeader.CONTENT_TYPE, Collections.singletonList(
-              ODataFormat.JSON.getContentType(ODataServiceVersion.V40).toContentTypeString()));
+          ODataFormat.JSON.getContentType(ODataServiceVersion.V40).toContentTypeString()));
     }
 
     final OData odata = OData.newInstance();