From 6b0d6d2544fb1c6fb9f85a4e05e7bebfaf3f4847 Mon Sep 17 00:00:00 2001 From: Michael Bolz Date: Thu, 8 Jan 2015 14:22:19 +0100 Subject: [PATCH] [OLINGO-507] Split 'handleResourceDispatching' into several smaller methods --- .../olingo/fit/tecsvc/client/BasicITCase.java | 41 ++ .../olingo/server/core/ContentNegotiator.java | 13 + .../core/ContentNegotiatorException.java | 1 + .../olingo/server/core/ODataHandler.java | 585 ++++++++++-------- .../server/core/ODataHandlerException.java | 3 +- .../server-core-exceptions-i18n.properties | 1 + 6 files changed, 375 insertions(+), 269 deletions(-) diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java index 023729c93..f6a5520a1 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java @@ -34,11 +34,14 @@ import java.util.List; import org.apache.olingo.client.api.CommonODataClient; import org.apache.olingo.client.api.communication.ODataClientErrorException; +import org.apache.olingo.client.api.communication.ODataServerErrorException; +import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest; import org.apache.olingo.client.api.communication.request.retrieve.EdmMetadataRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataServiceDocumentRequest; import org.apache.olingo.client.api.communication.request.retrieve.XMLMetadataRequest; +import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse; import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; import org.apache.olingo.client.api.edm.xml.XMLMetadata; import org.apache.olingo.client.api.edm.xml.v4.Reference; @@ -52,9 +55,11 @@ import org.apache.olingo.commons.api.domain.v4.ODataEntitySet; import org.apache.olingo.commons.api.domain.v4.ODataProperty; import org.apache.olingo.commons.api.domain.v4.ODataValue; import org.apache.olingo.commons.api.edm.Edm; +import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.api.http.HttpStatusCode; +import org.apache.olingo.commons.core.domain.v4.ODataEntityImpl; import org.apache.olingo.fit.AbstractBaseTestITCase; import org.apache.olingo.fit.tecsvc.TecSvcConst; import org.junit.Test; @@ -188,6 +193,42 @@ public class BasicITCase extends AbstractBaseTestITCase { assertEquals(30112, iterator.next().asPrimitive().toValue()); } + /** + * Actual an create request for an entity will lead to an "501 - Not Implemented" response + * and hence to an ODataServerErrorException + */ + @Test(expected = ODataServerErrorException.class) + public void createEntity() throws IOException { + final ODataEntityRequest request = getClient().getRetrieveRequestFactory() + .getEntityRequest(getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESCollAllPrim").appendKeySegment(1).build()); + assertNotNull(request); + + final ODataRetrieveResponse response = request.execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + assertThat(response.getContentType(), containsString(ContentType.APPLICATION_JSON.toContentTypeString())); + + final ODataEntity entity = response.getBody(); + assertNotNull(entity); + + final ODataEntityCreateRequest createRequest = getClient().getCUDRequestFactory() + .getEntityCreateRequest(getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESCollAllPrim").build(), entity); + assertNotNull(createRequest); + ODataEntityCreateResponse createResponse = createRequest.execute(); + + final ODataEntity createdEntity = createResponse.getBody(); + assertNotNull(createdEntity); + final ODataProperty property = createdEntity.getProperty("CollPropertyInt16"); + assertNotNull(property); + assertNotNull(property.getCollectionValue()); + assertEquals(3, property.getCollectionValue().size()); + Iterator iterator = property.getCollectionValue().iterator(); + assertEquals(1000, iterator.next().asPrimitive().toValue()); + assertEquals(2000, iterator.next().asPrimitive().toValue()); + assertEquals(30112, iterator.next().asPrimitive().toValue()); + } + @Override protected CommonODataClient getClient() { ODataClient odata = ODataClientFactory.getV4(); diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java index e84c9c915..f0e3d2de3 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java @@ -151,4 +151,17 @@ public class ContentNegotiator { throw new ContentNegotiatorException("unsupported content type: " + contentType, ContentNegotiatorException.MessageKeys.UNSUPPORTED_CONTENT_TYPE, contentType.toContentTypeString()); } + + public static boolean isSupported(final ContentType contentType, + final CustomContentTypeSupport customContentTypeSupport, + final RepresentationType representationType) throws ContentNegotiatorException { + + for (final ContentType supportedContentType : + getSupportedContentTypes(customContentTypeSupport, representationType)) { + if (AcceptType.fromContentType(supportedContentType).get(0).matches(contentType)) { + return true; + } + } + return false; + } } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiatorException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiatorException.java index efd597d19..e2ee86663 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiatorException.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiatorException.java @@ -30,6 +30,7 @@ public class ContentNegotiatorException extends ODataTranslatedException { UNSUPPORTED_CONTENT_TYPES, /** parameter: content type */ UNSUPPORTED_CONTENT_TYPE, + /** no parameter */ NO_CONTENT_TYPE_SUPPORTED, /** parameter: format string */ UNSUPPORTED_FORMAT_OPTION; 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 56293a502..c36704393 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 @@ -22,7 +22,6 @@ import java.util.LinkedList; import java.util.List; import org.apache.olingo.commons.api.edm.EdmEntityType; -import org.apache.olingo.commons.api.edm.EdmPrimitiveType; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; import org.apache.olingo.commons.api.format.ContentType; @@ -136,64 +135,70 @@ 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 { + case metadata: + if (method == HttpMethod.GET) { final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, RepresentationType.SERVICE); - - selectProcessor(ServiceDocumentProcessor.class) - .readServiceDocument(request, response, uriInfo, requestedContentType); + 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()); } - } 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 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); + 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); + } + } 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 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); } } - public void handleException(ODataRequest request, ODataResponse response, ODataServerError serverError) { + public void handleException(final ODataRequest request, final ODataResponse response, + final ODataServerError serverError) { + ErrorProcessor exceptionProcessor; try { exceptionProcessor = selectProcessor(ErrorProcessor.class); @@ -204,8 +209,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); } @@ -213,274 +218,318 @@ 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 HttpMethod method = request.getMethod(); final int lastPathSegmentIndex = uriInfo.getUriResourceParts().size() - 1; final UriResource lastPathSegment = uriInfo.getUriResourceParts().get(lastPathSegmentIndex); switch (lastPathSegment.getKind()) { - case entitySet: - case navigationProperty: - if (((UriResourcePartTyped) lastPathSegment).isCollection()) { - if (method == HttpMethod.GET) { - final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, RepresentationType.COLLECTION_ENTITY); + case entitySet: + case navigationProperty: + handleEntityDispatching(request, response, method, (UriResourcePartTyped) lastPathSegment); + break; - selectProcessor(EntityCollectionProcessor.class) - .readEntityCollection(request, response, uriInfo, requestedContentType); - } else if (method == HttpMethod.POST) { - if (isMedia(lastPathSegment)) { - final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); - final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, RepresentationType.ENTITY); - selectProcessor(MediaEntityProcessor.class) - .createMediaEntity(request, response, uriInfo, requestFormat, responseFormat); - } else { - final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); - ContentNegotiator.checkSupport(requestFormat, customContentTypeSupport, RepresentationType.ENTITY); - final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, RepresentationType.ENTITY); - selectProcessor(EntityProcessor.class) - .createEntity(request, response, uriInfo, requestFormat, responseFormat); - } - } else { - throw new ODataHandlerException("HTTP method " + method + " is not allowed.", - ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString()); - } - } else { - if (method == HttpMethod.GET) { - final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, RepresentationType.ENTITY); + case count: + handleCountDispatching(request, response, method, lastPathSegmentIndex); + break; - 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)); - ContentNegotiator.checkSupport(requestFormat, customContentTypeSupport, RepresentationType.ENTITY); - final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, RepresentationType.ENTITY); - selectProcessor(EntityProcessor.class) - .updateEntity(request, response, uriInfo, requestFormat, responseFormat); - } else if (method == HttpMethod.DELETE) { - selectProcessor(isMedia(lastPathSegment) ? MediaEntityProcessor.class : EntityProcessor.class) - .deleteEntity(request, response, uriInfo); - } else { - throw new ODataHandlerException("HTTP method " + method + " is not allowed.", - ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString()); - } - } - break; + case primitiveProperty: + handlePrimitivePropertyDispatching(request, response, method, (UriResourceProperty) lastPathSegment); + break; - case count: + case complexProperty: + handleComplexPropertyDispatching(request, response, method, (UriResourceProperty) lastPathSegment); + break; + + case value: + handleValueDispatching(request, response, method, lastPathSegmentIndex); + break; + + case ref: + handleReferenceDispatching(request, response, method, lastPathSegmentIndex); + break; + + default: + throw new ODataHandlerException("not implemented", + ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED); + } + } + + private void handleReferenceDispatching(final ODataRequest request, final ODataResponse response, + final HttpMethod method, final int lastPathSegmentIndex) + throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException, + DeserializerException { + if (((UriResourcePartTyped) uriInfo.getUriResourceParts().get(lastPathSegmentIndex - 1)).isCollection()) { if (method == HttpMethod.GET) { - final UriResource resource = uriInfo.getUriResourceParts().get(lastPathSegmentIndex - 1); - if (resource instanceof UriResourceEntitySet || resource instanceof UriResourceNavigation) { - selectProcessor(CountEntityCollectionProcessor.class) - .countEntityCollection(request, response, uriInfo); - } else if (resource instanceof UriResourcePrimitiveProperty) { - selectProcessor(CountPrimitiveCollectionProcessor.class) - .countPrimitiveCollection(request, response, uriInfo); - } else { - selectProcessor(CountComplexCollectionProcessor.class) - .countComplexCollection(request, response, uriInfo); - } - } else { - throw new ODataHandlerException("HTTP method " + method + " is not allowed for count.", - ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString()); - } - break; - - case primitiveProperty: - final UriResourceProperty propertyResource = (UriResourceProperty) lastPathSegment; - final RepresentationType representationType = propertyResource.isCollection() ? - RepresentationType.COLLECTION_PRIMITIVE : RepresentationType.PRIMITIVE; - if (method == HttpMethod.GET) { - final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, representationType); - if (representationType == RepresentationType.PRIMITIVE) { - selectProcessor(PrimitiveProcessor.class) - .readPrimitive(request, response, uriInfo, requestedContentType); - } else { - selectProcessor(PrimitiveCollectionProcessor.class) - .readPrimitiveCollection(request, response, uriInfo, requestedContentType); - } - } else if (method == HttpMethod.PUT || method == HttpMethod.PATCH) { - final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); - ContentNegotiator.checkSupport(requestFormat, customContentTypeSupport, representationType); final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, representationType); - if (representationType == RepresentationType.PRIMITIVE) { - selectProcessor(PrimitiveProcessor.class) - .updatePrimitive(request, response, uriInfo, requestFormat, responseFormat); - } else { - selectProcessor(PrimitiveCollectionProcessor.class) - .updatePrimitiveCollection(request, response, uriInfo, requestFormat, responseFormat); - } - } else if (method == HttpMethod.DELETE) { - if (representationType == RepresentationType.PRIMITIVE) { - selectProcessor(PrimitiveProcessor.class) - .deletePrimitive(request, response, uriInfo); - } else { - selectProcessor(PrimitiveCollectionProcessor.class) - .deletePrimitiveCollection(request, response, uriInfo); - } + request, customContentTypeSupport, RepresentationType.COLLECTION_REFERENCE); + selectProcessor(ReferenceCollectionProcessor.class) + .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); } 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()); } - break; - - case complexProperty: - final UriResourceProperty complexPropertyResource = (UriResourceProperty) lastPathSegment; - final RepresentationType complexRepresentationType = complexPropertyResource.isCollection() ? - RepresentationType.COLLECTION_COMPLEX : RepresentationType.COMPLEX; + } else { if (method == HttpMethod.GET) { - final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, complexRepresentationType); - if (complexRepresentationType == RepresentationType.COMPLEX) { - selectProcessor(ComplexProcessor.class) - .readComplex(request, response, uriInfo, requestedContentType); - } else { - selectProcessor(ComplexCollectionProcessor.class) - .readComplexCollection(request, response, uriInfo, requestedContentType); - } + final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + 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)); - ContentNegotiator.checkSupport(requestFormat, customContentTypeSupport, complexRepresentationType); - final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, complexRepresentationType); - if (complexRepresentationType == RepresentationType.COMPLEX) { - selectProcessor(ComplexProcessor.class) - .updateComplex(request, response, uriInfo, requestFormat, responseFormat); - } else { - selectProcessor(ComplexCollectionProcessor.class) - .updateComplexCollection(request, response, uriInfo, requestFormat, responseFormat); - } + checkContentTypeSupport(requestFormat, RepresentationType.REFERENCE); + selectProcessor(ReferenceProcessor.class) + .updateReference(request, response, uriInfo, requestFormat); } else if (method == HttpMethod.DELETE) { - if (complexRepresentationType == RepresentationType.COMPLEX) { - selectProcessor(ComplexProcessor.class) - .deleteComplex(request, response, uriInfo); - } else { - selectProcessor(ComplexCollectionProcessor.class) - .deleteComplexCollection(request, response, uriInfo); - } + selectProcessor(ReferenceProcessor.class) + .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()); } - break; + } + } - case value: - final UriResource resource = uriInfo.getUriResourceParts().get(lastPathSegmentIndex - 1); - if (resource instanceof UriResourceProperty) { - final RepresentationType valueRepresentationType = - (EdmPrimitiveType) ((UriResourceProperty) resource).getType() == - EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary) ? - RepresentationType.BINARY : RepresentationType.VALUE; - if (method == HttpMethod.GET) { - final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, valueRepresentationType); + private void handleValueDispatching(final ODataRequest request, final ODataResponse response, + final HttpMethod method, final int lastPathSegmentIndex) + throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException, + DeserializerException { + final UriResource resource = uriInfo.getUriResourceParts().get(lastPathSegmentIndex - 1); + if (resource instanceof UriResourceProperty) { + final RepresentationType valueRepresentationType = + ((UriResourceProperty) resource).getType() == + EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary) ? + RepresentationType.BINARY : RepresentationType.VALUE; + if (method == HttpMethod.GET) { + final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, customContentTypeSupport, valueRepresentationType); - selectProcessor(PrimitiveValueProcessor.class) - .readPrimitiveValue(request, response, uriInfo, requestedContentType); - } else if (method == HttpMethod.PUT) { - final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); - ContentNegotiator.checkSupport(requestFormat, customContentTypeSupport, valueRepresentationType); - final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, valueRepresentationType); - selectProcessor(PrimitiveValueProcessor.class) - .updatePrimitive(request, response, uriInfo, requestFormat, responseFormat); - } else if (method == HttpMethod.DELETE) { - 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()); - } + selectProcessor(PrimitiveValueProcessor.class) + .readPrimitiveValue(request, response, uriInfo, requestedContentType); + } else if (method == HttpMethod.PUT) { + final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); + checkContentTypeSupport(requestFormat, valueRepresentationType); + final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, customContentTypeSupport, valueRepresentationType); + selectProcessor(PrimitiveValueProcessor.class) + .updatePrimitive(request, response, uriInfo, requestFormat, responseFormat); + } else if (method == HttpMethod.DELETE) { + selectProcessor(PrimitiveValueProcessor.class).deletePrimitive(request, response, uriInfo); } else { - if (method == HttpMethod.GET) { - final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, RepresentationType.MEDIA); - selectProcessor(MediaEntityProcessor.class) - .readMediaEntity(request, response, uriInfo, requestedContentType); - } else if (method == HttpMethod.PUT) { + throw new ODataHandlerException("HTTP method " + method + " is not allowed.", + ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString()); + } + } else { + if (method == HttpMethod.GET) { + final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, customContentTypeSupport, RepresentationType.MEDIA); + selectProcessor(MediaEntityProcessor.class) + .readMediaEntity(request, response, uriInfo, requestedContentType); + } else if (method == HttpMethod.PUT) { + final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); + final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, customContentTypeSupport, RepresentationType.ENTITY); + selectProcessor(MediaEntityProcessor.class) + .updateMediaEntity(request, response, uriInfo, requestFormat, responseFormat); + } else if (method == HttpMethod.DELETE) { + 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()); + } + } + } + + private void handleComplexPropertyDispatching(final ODataRequest request, final ODataResponse response, + final HttpMethod method, + final UriResourceProperty complexPropertyResource) + throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException, + DeserializerException { + + final RepresentationType complexRepresentationType = complexPropertyResource.isCollection() ? + RepresentationType.COLLECTION_COMPLEX : RepresentationType.COMPLEX; + if (method == HttpMethod.GET) { + final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, customContentTypeSupport, complexRepresentationType); + if (complexRepresentationType == RepresentationType.COMPLEX) { + selectProcessor(ComplexProcessor.class) + .readComplex(request, response, uriInfo, requestedContentType); + } else { + selectProcessor(ComplexCollectionProcessor.class) + .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); + if (complexRepresentationType == RepresentationType.COMPLEX) { + selectProcessor(ComplexProcessor.class) + .updateComplex(request, response, uriInfo, requestFormat, responseFormat); + } else { + selectProcessor(ComplexCollectionProcessor.class) + .updateComplexCollection(request, response, uriInfo, requestFormat, responseFormat); + } + } else if (method == HttpMethod.DELETE) { + if (complexRepresentationType == RepresentationType.COMPLEX) { + selectProcessor(ComplexProcessor.class).deleteComplex(request, response, uriInfo); + } else { + selectProcessor(ComplexCollectionProcessor.class).deleteComplexCollection(request, response, uriInfo); + } + } else { + throw new ODataHandlerException("HTTP method " + method + " is not allowed.", + ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString()); + } + } + + private void handlePrimitivePropertyDispatching(final ODataRequest request, final ODataResponse response, + final HttpMethod method, final UriResourceProperty propertyResource) + throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException, + DeserializerException { + final RepresentationType representationType = propertyResource.isCollection() ? + RepresentationType.COLLECTION_PRIMITIVE : RepresentationType.PRIMITIVE; + if (method == HttpMethod.GET) { + final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, customContentTypeSupport, representationType); + if (representationType == RepresentationType.PRIMITIVE) { + selectProcessor(PrimitiveProcessor.class).readPrimitive(request, response, uriInfo, requestedContentType); + } else { + selectProcessor(PrimitiveCollectionProcessor.class) + .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); + if (representationType == RepresentationType.PRIMITIVE) { + selectProcessor(PrimitiveProcessor.class) + .updatePrimitive(request, response, uriInfo, requestFormat, responseFormat); + } else { + selectProcessor(PrimitiveCollectionProcessor.class) + .updatePrimitiveCollection(request, response, uriInfo, requestFormat, responseFormat); + } + } else if (method == HttpMethod.DELETE) { + if (representationType == RepresentationType.PRIMITIVE) { + selectProcessor(PrimitiveProcessor.class).deletePrimitive(request, response, uriInfo); + } else { + selectProcessor(PrimitiveCollectionProcessor.class).deletePrimitiveCollection(request, response, uriInfo); + } + } else { + throw new ODataHandlerException("HTTP method " + method + " is not allowed.", + ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString()); + } + } + + private void handleCountDispatching(final ODataRequest request, final ODataResponse response, + final HttpMethod method, final int lastPathSegmentIndex) + throws ODataApplicationException, SerializerException, ODataHandlerException { + + if (method == HttpMethod.GET) { + final UriResource resource = uriInfo.getUriResourceParts().get(lastPathSegmentIndex - 1); + if (resource instanceof UriResourceEntitySet || resource instanceof UriResourceNavigation) { + selectProcessor(CountEntityCollectionProcessor.class) + .countEntityCollection(request, response, uriInfo); + } else if (resource instanceof UriResourcePrimitiveProperty) { + selectProcessor(CountPrimitiveCollectionProcessor.class) + .countPrimitiveCollection(request, response, uriInfo); + } else { + selectProcessor(CountComplexCollectionProcessor.class) + .countComplexCollection(request, response, uriInfo); + } + } else { + throw new ODataHandlerException("HTTP method " + method + " is not allowed for count.", + ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString()); + } + } + + private void handleEntityDispatching(final ODataRequest request, final ODataResponse response, + final HttpMethod method, + final UriResourcePartTyped uriResourcePart) + throws ContentNegotiatorException, ODataApplicationException, SerializerException, ODataHandlerException, + DeserializerException { + + if (uriResourcePart.isCollection()) { + if (method == HttpMethod.GET) { + final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, customContentTypeSupport, RepresentationType.COLLECTION_ENTITY); + + selectProcessor(EntityCollectionProcessor.class) + .readEntityCollection(request, response, uriInfo, requestedContentType); + } else if (method == HttpMethod.POST) { + if (isMedia(uriResourcePart)) { final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request, customContentTypeSupport, RepresentationType.ENTITY); selectProcessor(MediaEntityProcessor.class) - .updateMediaEntity(request, response, uriInfo, requestFormat, responseFormat); - } else if (method == HttpMethod.DELETE) { - selectProcessor(MediaEntityProcessor.class) - .deleteEntity(request, response, uriInfo); + .createMediaEntity(request, response, uriInfo, requestFormat, responseFormat); } else { - throw new ODataHandlerException("HTTP method " + method + " is not allowed.", - ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString()); - } - } - break; - - case ref: - if (((UriResourcePartTyped) uriInfo.getUriResourceParts().get(lastPathSegmentIndex - 1)).isCollection()) { - if (method == HttpMethod.GET) { - final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - request, customContentTypeSupport, RepresentationType.COLLECTION_REFERENCE); - selectProcessor(ReferenceCollectionProcessor.class) - .readReferenceCollection(request, response, uriInfo, responseFormat); - } else if (method == HttpMethod.POST) { final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE)); - ContentNegotiator.checkSupport(requestFormat, customContentTypeSupport, RepresentationType.REFERENCE); - selectProcessor(ReferenceProcessor.class) - .createReference(request, response, uriInfo, requestFormat); - } else { - throw new ODataHandlerException("HTTP method " + method + " is not allowed.", - ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString()); + checkContentTypeSupport(requestFormat, RepresentationType.ENTITY); + final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, customContentTypeSupport, RepresentationType.ENTITY); + selectProcessor(EntityProcessor.class) + .createEntity(request, response, uriInfo, requestFormat, responseFormat); } } else { - if (method == HttpMethod.GET) { - final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), - 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)); - ContentNegotiator.checkSupport(requestFormat, customContentTypeSupport, RepresentationType.REFERENCE); - selectProcessor(ReferenceProcessor.class) - .updateReference(request, response, uriInfo, requestFormat); - } else if (method == HttpMethod.DELETE) { - selectProcessor(ReferenceProcessor.class) - .deleteReference(request, response, uriInfo); - } else { - throw new ODataHandlerException("HTTP method " + method + " is not allowed.", - ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString()); - } + throw new ODataHandlerException("HTTP method " + method + " is not allowed.", + ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString()); } - break; + } else { + if (method == HttpMethod.GET) { + final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), + request, customContentTypeSupport, RepresentationType.ENTITY); - default: - throw new ODataHandlerException("not implemented", - ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED); + 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); + selectProcessor(EntityProcessor.class).updateEntity(request, response, uriInfo, requestFormat, responseFormat); + } else if (method == HttpMethod.DELETE) { + selectProcessor(isMedia(uriResourcePart) ? MediaEntityProcessor.class : EntityProcessor.class) + .deleteEntity(request, response, uriInfo); + } else { + throw new ODataHandlerException("HTTP method " + method + " is not allowed.", + ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString()); + } + } + } + + private void checkContentTypeSupport(ContentType requestFormat, RepresentationType representationType) + 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); } } 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 selectProcessor(final Class cls) throws ODataHandlerException { @@ -491,7 +540,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) { diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerException.java index cc4d66272..8ebbc26c2 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerException.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerException.java @@ -29,7 +29,8 @@ public class ODataHandlerException extends ODataTranslatedException { /** parameter: HTTP method */ INVALID_HTTP_METHOD, /** parameter: HTTP method */ HTTP_METHOD_NOT_ALLOWED, /** parameter: processor interface */ PROCESSOR_NOT_IMPLEMENTED, - FUNCTIONALITY_NOT_IMPLEMENTED, + /** no parameter */ FUNCTIONALITY_NOT_IMPLEMENTED, + /** parameter: content type */ UNSUPPORTED_CONTENT_TYPE, /** parameter: version */ ODATA_VERSION_NOT_SUPPORTED; @Override diff --git a/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties b/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties index c61619d98..034a6bde5 100644 --- a/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties +++ b/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties @@ -24,6 +24,7 @@ ODataHandlerException.HTTP_METHOD_NOT_ALLOWED=HTTP method '%1$s' not allowed for ODataHandlerException.PROCESSOR_NOT_IMPLEMENTED=No processor for interface '%1$s' registered. ODataHandlerException.FUNCTIONALITY_NOT_IMPLEMENTED=The requested functionality has not been implemented (yet). ODataHandlerException.ODATA_VERSION_NOT_SUPPORTED=OData version '%1$s' is not supported. +ODataHandlerException.UNSUPPORTED_CONTENT_TYPE=The content type '%1$s' is not supported for this request. UriParserSyntaxException.MUST_BE_LAST_SEGMENT=The segment '%1$s' must be the last segment. UriParserSyntaxException.UNKNOWN_SYSTEM_QUERY_OPTION=The system query option '%1$s' is not defined.