blob: 4528d3a7221b60abe4ba2befc2af29e1d49aba4f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core;
import java.util.LinkedList;
import java.util.List;
import org.apache.olingo.commons.api.edm.EdmAction;
import org.apache.olingo.commons.api.edm.EdmActionImport;
import org.apache.olingo.commons.api.edm.EdmEntityType;
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.constants.ODataServiceVersion;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpMethod;
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.ODataServerError;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.batch.exception.BatchDeserializerException;
import org.apache.olingo.server.api.deserializer.DeserializerException;
import org.apache.olingo.server.api.processor.ActionComplexCollectionProcessor;
import org.apache.olingo.server.api.processor.ActionComplexProcessor;
import org.apache.olingo.server.api.processor.ActionEntityCollectionProcessor;
import org.apache.olingo.server.api.processor.ActionEntityProcessor;
import org.apache.olingo.server.api.processor.ActionPrimitiveCollectionProcessor;
import org.apache.olingo.server.api.processor.ActionPrimitiveProcessor;
import org.apache.olingo.server.api.processor.BatchProcessor;
import org.apache.olingo.server.api.processor.ComplexCollectionProcessor;
import org.apache.olingo.server.api.processor.ComplexProcessor;
import org.apache.olingo.server.api.processor.CountComplexCollectionProcessor;
import org.apache.olingo.server.api.processor.CountEntityCollectionProcessor;
import org.apache.olingo.server.api.processor.CountPrimitiveCollectionProcessor;
import org.apache.olingo.server.api.processor.DefaultProcessor;
import org.apache.olingo.server.api.processor.EntityCollectionProcessor;
import org.apache.olingo.server.api.processor.EntityProcessor;
import org.apache.olingo.server.api.processor.ErrorProcessor;
import org.apache.olingo.server.api.processor.MediaEntityProcessor;
import org.apache.olingo.server.api.processor.MetadataProcessor;
import org.apache.olingo.server.api.processor.PrimitiveCollectionProcessor;
import org.apache.olingo.server.api.processor.PrimitiveProcessor;
import org.apache.olingo.server.api.processor.PrimitiveValueProcessor;
import org.apache.olingo.server.api.processor.Processor;
import org.apache.olingo.server.api.processor.ReferenceCollectionProcessor;
import org.apache.olingo.server.api.processor.ReferenceProcessor;
import org.apache.olingo.server.api.processor.ServiceDocumentProcessor;
import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
import org.apache.olingo.server.api.serializer.RepresentationType;
import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceAction;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.UriResourceFunction;
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.core.batchhandler.BatchHandler;
import org.apache.olingo.server.core.uri.parser.Parser;
import org.apache.olingo.server.core.uri.parser.UriParserException;
import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
import org.apache.olingo.server.core.uri.validator.UriValidator;
public class ODataHandler {
private final OData odata;
private final ServiceMetadata serviceMetadata;
private List<Processor> processors = new LinkedList<Processor>();
private CustomContentTypeSupport customContentTypeSupport = null;
private UriInfo uriInfo;
public ODataHandler(final OData server, final ServiceMetadata serviceMetadata) {
odata = server;
this.serviceMetadata = serviceMetadata;
register(new DefaultProcessor());
register(new DefaultRedirectProcessor());
}
public ODataResponse process(final ODataRequest request) {
ODataResponse response = new ODataResponse();
try {
processInternal(request, response);
} catch (final UriValidationException e) {
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
handleException(request, response, serverError);
} catch (final UriParserSemanticException e) {
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
handleException(request, response, serverError);
} catch (final UriParserSyntaxException e) {
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
handleException(request, response, serverError);
} catch (final UriParserException e) {
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
handleException(request, response, serverError);
} catch (ContentNegotiatorException e) {
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
handleException(request, response, serverError);
} catch (SerializerException e) {
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
handleException(request, response, serverError);
} catch (BatchDeserializerException e) {
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
handleException(request, response, serverError);
} catch (DeserializerException e) {
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
handleException(request, response, serverError);
} catch (ODataHandlerException e) {
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
handleException(request, response, serverError);
} catch (ODataApplicationException e) {
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e);
handleException(request, response, serverError);
} catch (Exception e) {
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e);
handleException(request, response, serverError);
}
return response;
}
private void processInternal(final ODataRequest request, final ODataResponse response)
throws ODataHandlerException, UriParserException, UriValidationException, ContentNegotiatorException,
ODataApplicationException, SerializerException, DeserializerException {
validateODataVersion(request, response);
uriInfo = new Parser().parseUri(request.getRawODataPath(), request.getRawQueryPath(), null,
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);
}
} 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(final ODataRequest request, final ODataResponse response,
final ODataServerError serverError) {
ErrorProcessor exceptionProcessor;
try {
exceptionProcessor = selectProcessor(ErrorProcessor.class);
} catch (ODataHandlerException e) {
// This cannot happen since there is always an ExceptionProcessor registered.
exceptionProcessor = new DefaultProcessor();
}
ContentType requestedContentType;
try {
requestedContentType = ContentNegotiator.doContentNegotiation(
uriInfo == null ? null : uriInfo.getFormatOption(), request, customContentTypeSupport,
RepresentationType.ERROR);
} catch (final ContentNegotiatorException e) {
requestedContentType = ODataFormat.JSON.getContentType(ODataServiceVersion.V40);
}
exceptionProcessor.processError(request, response, serverError, requestedContentType);
}
private void handleResourceDispatching(final ODataRequest request, final ODataResponse response)
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);
}
}
private void handleFunctionDispatching(final ODataRequest request, final ODataResponse response,
final UriResourceFunction uriResourceFunction)
throws ODataHandlerException, SerializerException, ContentNegotiatorException,
ODataApplicationException, DeserializerException {
final HttpMethod method = request.getMethod();
if(method != HttpMethod.GET) {
throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
}
EdmFunctionImport functionImport = uriResourceFunction.getFunctionImport();
// could be null for bound functions
if(functionImport == null) {
throw new ODataHandlerException("Bound functions are not implemented yet",
ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
}
List<EdmFunction> unboundFunctions = functionImport.getUnboundFunctions();
if(unboundFunctions == null || unboundFunctions.isEmpty()) {
throw new ODataHandlerException("No unbound function defined for function import",
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 HttpMethod method = request.getMethod();
if(request.getMethod() != HttpMethod.POST) {
throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
}
EdmActionImport actionImport = uriResourceAction.getActionImport();
// could be null for bound actions
if(actionImport == null) {
throw new ODataHandlerException("Bound actions are not implemented yet",
ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
}
EdmAction unboundActions = actionImport.getUnboundAction();
if(unboundActions == null) {
throw new ODataHandlerException("No unbound function defined for function import",
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 {
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);
}
}
private void handleReferenceDispatching(final ODataRequest request, final ODataResponse response,
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);
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());
}
} 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));
checkContentTypeSupport(requestFormat, 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());
}
}
}
private void handleValueDispatching(final ODataRequest request, final ODataResponse response,
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) {
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));
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 {
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 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;
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.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);
if (complexRepresentationType == RepresentationType.COMPLEX) {
selectProcessor(ActionComplexProcessor.class)
.processActionComplex(request, response, uriInfo, requestFormat, responseFormat);
} else {
selectProcessor(ActionComplexCollectionProcessor.class)
.processActionComplexCollection(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,
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;
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 if (method == HttpMethod.POST && isAction) {
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(ActionPrimitiveProcessor.class)
.processActionPrimitive(request, response, uriInfo, requestFormat, responseFormat);
} else {
selectProcessor(ActionPrimitiveCollectionProcessor.class)
.processActionPrimitiveCollection(request, response, uriInfo, requestFormat, responseFormat);
}
} 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 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) {
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 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 HttpMethod method = request.getMethod();
if (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) {
final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
if (isMedia) {
final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
request, customContentTypeSupport, RepresentationType.ENTITY);
selectProcessor(MediaEntityProcessor.class)
.createMediaEntity(request, response, uriInfo, requestFormat, responseFormat);
} else if(isAction) {
checkContentTypeSupport(requestFormat, RepresentationType.ENTITY);
final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
request, customContentTypeSupport, RepresentationType.ENTITY);
selectProcessor(ActionEntityCollectionProcessor.class)
.processActionEntityCollection(request, response, uriInfo, requestFormat, responseFormat);
} else {
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 {
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);
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.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);
selectProcessor(ActionEntityProcessor.class).processActionEntity(
request, response, uriInfo, requestFormat, responseFormat);
} else if (method == HttpMethod.DELETE) {
selectProcessor(isMedia ? 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 {
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);
}
}
}
private boolean isMedia(final UriResource pathSegment) {
return pathSegment instanceof UriResourceEntitySet
&& ((UriResourceEntitySet) pathSegment).getEntityType().hasStream()
|| pathSegment instanceof UriResourceNavigation
&& ((EdmEntityType) ((UriResourceNavigation) pathSegment).getType()).hasStream();
}
private <T extends Processor> T selectProcessor(final Class<T> cls) throws ODataHandlerException {
for (final Processor processor : processors) {
if (cls.isAssignableFrom(processor.getClass())) {
processor.init(odata, serviceMetadata);
return cls.cast(processor);
}
}
throw new ODataHandlerException("Processor: " + cls.getSimpleName() + " not registered.",
ODataHandlerException.MessageKeys.PROCESSOR_NOT_IMPLEMENTED, cls.getSimpleName());
}
public void register(final Processor processor) {
processors.add(0, processor);
}
public void register(final CustomContentTypeSupport customContentTypeSupport) {
this.customContentTypeSupport = customContentTypeSupport;
}
}