Repository: olingo-odata4 Updated Branches: refs/heads/OLINGO-888 [created] 7f5c1aa8d
[OLINGO-888] Start with singleton dispatching Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/7f5c1aa8 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/7f5c1aa8 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/7f5c1aa8 Branch: refs/heads/OLINGO-888 Commit: 7f5c1aa8de48590ef8954762620067490630631c Parents: feb94ed Author: Christian Amend <[email protected]> Authored: Thu Feb 25 15:47:40 2016 +0100 Committer: Christian Amend <[email protected]> Committed: Thu Feb 25 15:47:40 2016 +0100 ---------------------------------------------------------------------- .../olingo/server/core/ODataDispatcher.java | 212 +++++++++++-------- .../olingo/server/core/ODataHandlerTest.java | 42 ++++ 2 files changed, 166 insertions(+), 88 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7f5c1aa8/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java index ceacd10..b62282d 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java @@ -68,6 +68,7 @@ import org.apache.olingo.server.api.uri.UriResourceNavigation; import org.apache.olingo.server.api.uri.UriResourcePartTyped; import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty; import org.apache.olingo.server.api.uri.UriResourceProperty; +import org.apache.olingo.server.api.uri.UriResourceSingleton; import org.apache.olingo.server.core.batchhandler.BatchHandler; import org.apache.olingo.server.core.etag.PreconditionsValidator; @@ -145,6 +146,9 @@ public class ODataDispatcher { ((UriResourcePartTyped) lastPathSegment).isCollection(), isEntityOrNavigationMedia(lastPathSegment)); break; + case singleton: + handleSingleEntityDispatching(request, response, isSingletonMedia(lastPathSegment), true); + case count: checkMethod(request.getMethod(), HttpMethod.GET); handleCountDispatching(request, response, lastPathSegmentIndex); @@ -303,60 +307,73 @@ public class ODataDispatcher { private void handleValueDispatching(final ODataRequest request, final ODataResponse response, final int lastPathSegmentIndex) throws ODataApplicationException, ODataLibraryException { - //The URI Parser already checked if $value is allowed here so we only have to dispatch to the correct processor - final HttpMethod method = request.getMethod(); + // The URI Parser already checked if $value is allowed here so we only have to dispatch to the correct processor final UriResource resource = uriInfo.getUriResourceParts().get(lastPathSegmentIndex - 1); 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 = - type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary) ? - RepresentationType.BINARY : RepresentationType.VALUE; - if (method == HttpMethod.GET) { - final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, handler.getCustomContentTypeSupport(), valueRepresentationType); - - handler.selectProcessor(PrimitiveValueProcessor.class) - .readPrimitiveValue(request, response, uriInfo, requestedContentType); - } else if (method == HttpMethod.PUT && resource instanceof UriResourceProperty) { - validatePreconditions(request, false); - final ContentType requestFormat = getSupportedContentType(request.getHeader(HttpHeader.CONTENT_TYPE), - valueRepresentationType, true); - final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, handler.getCustomContentTypeSupport(), valueRepresentationType); - handler.selectProcessor(PrimitiveValueProcessor.class) - .updatePrimitiveValue(request, response, uriInfo, requestFormat, responseFormat); - } else if (method == HttpMethod.DELETE && resource instanceof UriResourceProperty) { - validatePreconditions(request, false); - handler.selectProcessor(PrimitiveValueProcessor.class) - .deletePrimitiveValue(request, response, uriInfo); - } else { - throwMethodNotAllowed(method); - } + handlePrimitiveValueDispatching(request, response, resource); } else { - if (method == HttpMethod.GET) { - //This can be a GET on an EntitySet, Navigation or Function - final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, handler.getCustomContentTypeSupport(), RepresentationType.MEDIA); - handler.selectProcessor(MediaEntityProcessor.class) - .readMediaEntity(request, response, uriInfo, requestedContentType); - //PUT and DELETE can only be called on EntitySets or Navigation properties which are media resources - } else if (method == HttpMethod.PUT && isEntityOrNavigationMedia(resource)) { - validatePreconditions(request, true); - final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); - final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY); - handler.selectProcessor(MediaEntityProcessor.class) - .updateMediaEntity(request, response, uriInfo, requestFormat, responseFormat); - } else if (method == HttpMethod.DELETE && isEntityOrNavigationMedia(resource)) { - validatePreconditions(request, true); - handler.selectProcessor(MediaEntityProcessor.class) - .deleteMediaEntity(request, response, uriInfo); - } else { - throwMethodNotAllowed(method); - } + handleMediaValueDispatching(request, response, resource); + } + } + + private void handleMediaValueDispatching(final ODataRequest request, final ODataResponse response, + final UriResource resource) throws ContentNegotiatorException, ODataApplicationException, ODataLibraryException, + ODataHandlerException, PreconditionException { + final HttpMethod method = request.getMethod(); + if (method == HttpMethod.GET) { + // This can be a GET on an EntitySet, Navigation or Function + final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, handler.getCustomContentTypeSupport(), RepresentationType.MEDIA); + handler.selectProcessor(MediaEntityProcessor.class) + .readMediaEntity(request, response, uriInfo, requestedContentType); + // PUT and DELETE can only be called on EntitySets or Navigation properties which are media resources + } else if (method == HttpMethod.PUT && (isEntityOrNavigationMedia(resource) || isSingletonMedia(resource))) { + validatePreconditions(request, true); + final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); + final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY); + handler.selectProcessor(MediaEntityProcessor.class) + .updateMediaEntity(request, response, uriInfo, requestFormat, responseFormat); + } else if (method == HttpMethod.DELETE && isEntityOrNavigationMedia(resource)) { + validatePreconditions(request, true); + handler.selectProcessor(MediaEntityProcessor.class) + .deleteMediaEntity(request, response, uriInfo); + } else { + throwMethodNotAllowed(method); + } + } + + private void handlePrimitiveValueDispatching(final ODataRequest request, final ODataResponse response, + final UriResource resource) throws ContentNegotiatorException, ODataApplicationException, ODataLibraryException, + ODataHandlerException, PreconditionException { + final HttpMethod method = request.getMethod(); + final EdmType type = resource instanceof UriResourceProperty ? + ((UriResourceProperty) resource).getType() : ((UriResourceFunction) resource).getType(); + final RepresentationType valueRepresentationType = + type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary) ? + RepresentationType.BINARY : RepresentationType.VALUE; + if (method == HttpMethod.GET) { + final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, handler.getCustomContentTypeSupport(), valueRepresentationType); + + handler.selectProcessor(PrimitiveValueProcessor.class) + .readPrimitiveValue(request, response, uriInfo, requestedContentType); + } else if (method == HttpMethod.PUT && resource instanceof UriResourceProperty) { + validatePreconditions(request, false); + final ContentType requestFormat = getSupportedContentType(request.getHeader(HttpHeader.CONTENT_TYPE), + valueRepresentationType, true); + final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, handler.getCustomContentTypeSupport(), valueRepresentationType); + handler.selectProcessor(PrimitiveValueProcessor.class) + .updatePrimitiveValue(request, response, uriInfo, requestFormat, responseFormat); + } else if (method == HttpMethod.DELETE && resource instanceof UriResourceProperty) { + validatePreconditions(request, false); + handler.selectProcessor(PrimitiveValueProcessor.class) + .deletePrimitiveValue(request, response, uriInfo); + } else { + throwMethodNotAllowed(method); } } @@ -466,50 +483,64 @@ public class ODataDispatcher { private void handleEntityDispatching(final ODataRequest request, final ODataResponse response, final boolean isCollection, final boolean isMedia) throws ODataApplicationException, ODataLibraryException { - final HttpMethod method = request.getMethod(); if (isCollection) { - if (method == HttpMethod.GET) { - final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, handler.getCustomContentTypeSupport(), RepresentationType.COLLECTION_ENTITY); - handler.selectProcessor(EntityCollectionProcessor.class) - .readEntityCollection(request, response, uriInfo, requestedContentType); - } else if (method == HttpMethod.POST) { - final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY); - if (isMedia) { - final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); - handler.selectProcessor(MediaEntityProcessor.class) - .createMediaEntity(request, response, uriInfo, requestFormat, responseFormat); - } else { - final ContentType requestFormat = getSupportedContentType(request.getHeader(HttpHeader.CONTENT_TYPE), - RepresentationType.ENTITY, true); - handler.selectProcessor(EntityProcessor.class) - .createEntity(request, response, uriInfo, requestFormat, responseFormat); - } - } else { - throwMethodNotAllowed(method); - } + handleEntityCollectionDispatching(request, response, isMedia); } else { - if (method == HttpMethod.GET) { - final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY); - handler.selectProcessor(EntityProcessor.class) - .readEntity(request, response, uriInfo, requestedContentType); - } else if (method == HttpMethod.PUT || method == HttpMethod.PATCH) { - validatePreconditions(request, false); + handleSingleEntityDispatching(request, response, isMedia, false); + } + } + + private void handleEntityCollectionDispatching(final ODataRequest request, final ODataResponse response, + final boolean isMedia + ) throws ContentNegotiatorException, ODataApplicationException, ODataLibraryException, + ODataHandlerException { + final HttpMethod method = request.getMethod(); + if (method == HttpMethod.GET) { + final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, handler.getCustomContentTypeSupport(), RepresentationType.COLLECTION_ENTITY); + handler.selectProcessor(EntityCollectionProcessor.class) + .readEntityCollection(request, response, uriInfo, requestedContentType); + } else if (method == HttpMethod.POST) { + final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY); + if (isMedia) { + final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); + handler.selectProcessor(MediaEntityProcessor.class) + .createMediaEntity(request, response, uriInfo, requestFormat, responseFormat); + } else { final ContentType requestFormat = getSupportedContentType(request.getHeader(HttpHeader.CONTENT_TYPE), RepresentationType.ENTITY, true); - final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY); handler.selectProcessor(EntityProcessor.class) - .updateEntity(request, response, uriInfo, requestFormat, responseFormat); - } else if (method == HttpMethod.DELETE) { - validatePreconditions(request, false); - handler.selectProcessor(isMedia ? MediaEntityProcessor.class : EntityProcessor.class) - .deleteEntity(request, response, uriInfo); - } else { - throwMethodNotAllowed(method); + .createEntity(request, response, uriInfo, requestFormat, responseFormat); } + } else { + throwMethodNotAllowed(method); + } + } + + private void handleSingleEntityDispatching(final ODataRequest request, final ODataResponse response, + final boolean isMedia, final boolean isSingleton) throws ContentNegotiatorException, ODataApplicationException, + ODataLibraryException, ODataHandlerException, PreconditionException { + final HttpMethod method = request.getMethod(); + if (method == HttpMethod.GET) { + final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY); + handler.selectProcessor(EntityProcessor.class) + .readEntity(request, response, uriInfo, requestedContentType); + } else if (method == HttpMethod.PUT || method == HttpMethod.PATCH) { + validatePreconditions(request, false); + final ContentType requestFormat = getSupportedContentType(request.getHeader(HttpHeader.CONTENT_TYPE), + RepresentationType.ENTITY, true); + final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY); + handler.selectProcessor(EntityProcessor.class) + .updateEntity(request, response, uriInfo, requestFormat, responseFormat); + } else if (method == HttpMethod.DELETE && !isSingleton) { + validatePreconditions(request, false); + handler.selectProcessor(isMedia ? MediaEntityProcessor.class : EntityProcessor.class) + .deleteEntity(request, response, uriInfo); + } else { + throwMethodNotAllowed(method); } } @@ -558,8 +589,13 @@ public class ODataDispatcher { return contentType; } + private boolean isSingletonMedia(final UriResource pathSegment) { + return pathSegment instanceof UriResourceSingleton + && ((UriResourceSingleton) pathSegment).getEntityType().hasStream(); + } + private boolean isEntityOrNavigationMedia(final UriResource pathSegment) { - //This method MUST NOT check if the resource is of type function since these are handled differently + // This method MUST NOT check if the resource is of type function since these are handled differently return pathSegment instanceof UriResourceEntitySet && ((UriResourceEntitySet) pathSegment).getEntityType().hasStream() || pathSegment instanceof UriResourceNavigation http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7f5c1aa8/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 a228e40..b973cba 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 @@ -471,6 +471,48 @@ public class ODataHandlerTest { dispatchMethodNotAllowed(HttpMethod.POST, uri, processor); } + + @Test + public void dispatchSingleton() throws Exception { + final String uri = "SI"; + final EntityProcessor processor = mock(EntityProcessor.class); + + dispatch(HttpMethod.GET, uri, processor); + verify(processor).readEntity( + any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class)); + + 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.PUT, uri, processor); + verify(processor, times(2)).updateEntity( + any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class), + any(ContentType.class)); + + dispatchMethodNotAllowed(HttpMethod.POST, uri, processor); + dispatchMethodNotAllowed(HttpMethod.DELETE, uri, processor); + } + + @Test + public void dispatchSingletonMedia() throws Exception { + final String uri = "SIMedia/$value"; + final MediaEntityProcessor processor = mock(MediaEntityProcessor.class); + + dispatch(HttpMethod.GET, uri, processor); + verify(processor).readMediaEntity( + any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class)); + + dispatch(HttpMethod.PUT, uri, processor); + verify(processor).updateMediaEntity( + any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class), + any(ContentType.class)); + + dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor); + dispatchMethodNotAllowed(HttpMethod.POST, uri, processor); + dispatchMethodNotAllowed(HttpMethod.DELETE, uri, processor); + } @Test public void dispatchMedia() throws Exception {
