[OLINGO-1238]Handling Prefer header with values being minimal and representation for GET and DELETE requests

This commit is contained in:
ramya vasanth 2018-05-23 15:36:18 +05:30
parent f3919036ae
commit 03a02d2d69
7 changed files with 459 additions and 4 deletions

View File

@ -0,0 +1,355 @@
/*
* 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.fit.tecsvc.http;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.olingo.client.api.ODataClient;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpMethod;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.fit.AbstractBaseTestITCase;
import org.apache.olingo.fit.tecsvc.TecSvcConst;
import org.apache.olingo.fit.util.StringHelper;
import org.apache.olingo.server.tecsvc.async.TechnicalAsyncService;
import org.junit.Test;
public class PreferHeaderForGetAndDeleteITCase extends AbstractBaseTestITCase {
private static final String SERVICE_URI = TecSvcConst.BASE_URI + "/";
@Test
public void preferHeaderMinimal_GetEntitySet() throws Exception {
URL url = new URL(SERVICE_URI + "ESAllPrim");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.GET.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=minimal");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=minimal' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderRepresentation_GetEntitySet() throws Exception {
URL url = new URL(SERVICE_URI + "ESAllPrim");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.GET.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=representation");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=representation' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderMinimal_GetEntity() throws Exception {
URL url = new URL(SERVICE_URI + "ESAllPrim(32767)");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.GET.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=minimal");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=minimal' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderRepresentation_GetEntity() throws Exception {
URL url = new URL(SERVICE_URI + "ESAllPrim(32767)");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.GET.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=representation");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=representation' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderRepresentation_DeleteEntity() throws Exception {
URL url = new URL(SERVICE_URI + "ESAllPrim(32767)");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.DELETE.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=representation");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=representation' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderMinimal_DeleteEntity() throws Exception {
URL url = new URL(SERVICE_URI + "ESAllPrim(32767)");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.DELETE.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=minimal");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=minimal' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderRepresentation_GetComplexProperty() throws Exception {
URL url = new URL(SERVICE_URI + "ESCompCollDerived(12345)/PropertyCompAno");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.GET.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=representation");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=representation' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderMinimal_GetSimpleProperty() throws Exception {
URL url = new URL(SERVICE_URI + "ESAllPrim(32767)/PropertyString");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.GET.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=minimal");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=minimal' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderMinimal_GetNavigationProperty() throws Exception {
URL url = new URL(SERVICE_URI + "ESAllPrim(32767)/NavPropertyETTwoPrimOne");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.GET.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=minimal");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=minimal' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderRepresentation_GetReference() throws Exception {
URL url = new URL(SERVICE_URI + "ESAllPrim(32767)/NavPropertyETTwoPrimOne/$ref");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.GET.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=representation");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=representation' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderRepresentation_GetMediaEntitySet() throws Exception {
URL url = new URL(SERVICE_URI + "ESMedia");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.GET.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=representation");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=representation' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderMinimal_GetMediaEntity() throws Exception {
URL url = new URL(SERVICE_URI + "ESMedia(1)");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.GET.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=minimal");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=minimal' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderMinimal_PostMediaEntity() throws Exception {
URL url = new URL(SERVICE_URI + "ESMedia");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.POST.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=minimal");
connection.setRequestProperty(HttpHeader.CONTENT_TYPE, "application/json");
connection.setRequestProperty(HttpHeader.ACCEPT, "application/json");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=minimal' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderRepresentation_PutMediaEntity() throws Exception {
URL url = new URL(SERVICE_URI + "ESMedia(1)");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.PUT.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=representation");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=representation' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderRepresentation_Count() throws Exception {
URL url = new URL(SERVICE_URI + "ESAllPrim/$count");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.GET.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=representation");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=representation' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderMinimal_UnboundFunction() throws Exception {
URL url = new URL(SERVICE_URI + "FICRTETKeyNav()");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.GET.name());
connection.setRequestProperty(HttpHeader.PREFER, "return=minimal");
connection.connect();
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String content = IOUtils.toString(connection.getErrorStream());
assertTrue(content.contains("The Prefer header 'return=minimal' is not supported for this HTTP Method."));
}
@Test
public void preferHeaderMinimal_Batch() throws Exception {
InputStream content = Thread.currentThread().getContextClassLoader().getResourceAsStream("basicBatchPost.batch");
final HttpURLConnection connection = postBatch(content, "batch_8194-cf13-1f56", 1, true);
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
final String response = IOUtils.toString(connection.getErrorStream());
assertTrue(response.contains("The Prefer header 'return=minimal' is not supported for this HTTP Method."));
}
private HttpURLConnection postBatch(final InputStream content, String batchBoundary,
int sleepTime, boolean preferHeader)
throws IOException {
Map<String, String> headers = new HashMap<String, String>();
String contentTypeValue = ContentType.create(
ContentType.MULTIPART_MIXED, "boundary", batchBoundary).toContentTypeString();
headers.put(HttpHeader.CONTENT_TYPE, contentTypeValue);
headers.put(HttpHeader.ACCEPT, "application/json");
if(sleepTime >= 0 && preferHeader) {
headers.put(HttpHeader.PREFER, "respond-async; " +
TechnicalAsyncService.TEC_ASYNC_SLEEP + "=" + String.valueOf(sleepTime));
}
if (preferHeader) {
headers.put(HttpHeader.PREFER, "return=minimal");
}
StringHelper.Stream s = StringHelper.toStream(content);
final URL url = new URL(SERVICE_URI + "$batch");
return postRequest(url, s.asString("utf-8"), headers);
}
private HttpURLConnection postRequest(final URL url, final String content, final Map<String, String> headers)
throws IOException {
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(HttpMethod.POST.toString());
for (Map.Entry<String, String> header : headers.entrySet()) {
connection.setRequestProperty(header.getKey(), header.getValue());
}
connection.setDoOutput(true);
final OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.append(content);
writer.close();
connection.connect();
return connection;
}
@Test
public void preferHeaderMinimal_InBatchPayload() throws Exception {
InputStream content = Thread.currentThread().getContextClassLoader().
getResourceAsStream("basicBatchPostWithPreferHeader.batch");
final HttpURLConnection connection = postBatch(content, "batch_8194-cf13-1f56", 1, false);
assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode());
StringHelper.Stream resultBody = StringHelper.toStream(connection.getInputStream());
String resBody = resultBody.asString();
assertTrue(resBody.contains("The Prefer header 'return=minimal' is not supported for this HTTP Method."));
}
@Override
protected ODataClient getClient() {
return null;
}
}

View File

@ -0,0 +1,34 @@
--batch_8194-cf13-1f56
Content-Type: application/http
Content-Transfer-Encoding: binary
GET ESAllPrim(32767) HTTP/1.1
Accept: application/json
--batch_8194-cf13-1f56
Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd
--changeset_f980-1cb6-94dd
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: changeRequest1
PUT ESAllPrim(32767) HTTP/1.1
Accept: application/json
Content-Type: application/json
{"PropertyString":"MODIFIED"}
--changeset_f980-1cb6-94dd--
--batch_8194-cf13-1f56
Content-Type: application/http
Content-Transfer-Encoding: binary
GET ESAllPrim(32767)/PropertyString HTTP/1.1
Accept: application/json
Prefer: return=minimal
--batch_8194-cf13-1f56--

View File

@ -18,14 +18,16 @@
*/
package org.apache.olingo.server.core;
import java.util.List;
import org.apache.olingo.commons.api.edm.EdmAction;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmFunction;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.EdmReturnType;
import org.apache.olingo.commons.api.edm.EdmSingleton;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
import org.apache.olingo.commons.api.edm.EdmSingleton;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpMethod;
@ -69,15 +71,17 @@ 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;
import org.apache.olingo.server.api.uri.UriResourceSingleton;
public class ODataDispatcher {
private static final String NOT_IMPLEMENTED_MESSAGE = "not implemented";
private final UriInfo uriInfo;
private final ODataHandlerImpl handler;
private static final String RETURN_MINIMAL = "return=minimal";
private static final String RETURN_REPRESENTATION = "return=representation";
public ODataDispatcher(final UriInfo uriInfo, final ODataHandlerImpl handler) {
this.uriInfo = uriInfo;
@ -277,6 +281,7 @@ public class ODataDispatcher {
.isCollection();
if (isCollection && httpMethod == HttpMethod.GET) {
validatePreferHeader(request);
final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
request, handler.getCustomContentTypeSupport(), RepresentationType.COLLECTION_REFERENCE);
handler.selectProcessor(ReferenceCollectionProcessor.class)
@ -289,6 +294,7 @@ public class ODataDispatcher {
.createReference(request, response, uriInfo, requestFormat);
} else if (!isCollection && httpMethod == HttpMethod.GET) {
validatePreferHeader(request);
final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
request, handler.getCustomContentTypeSupport(), RepresentationType.REFERENCE);
handler.selectProcessor(ReferenceProcessor.class).readReference(request, response, uriInfo, responseFormat);
@ -300,6 +306,7 @@ public class ODataDispatcher {
.updateReference(request, response, uriInfo, requestFormat);
} else if (httpMethod == HttpMethod.DELETE) {
validatePreferHeader(request);
handler.selectProcessor(ReferenceProcessor.class)
.deleteReference(request, response, uriInfo);
@ -326,6 +333,7 @@ public class ODataDispatcher {
ODataApplicationException, ODataLibraryException,
ODataHandlerException, PreconditionException {
final HttpMethod method = request.getMethod();
validatePreferHeader(request);
if (method == HttpMethod.GET) {
// This can be a GET on an EntitySet, Navigation or Function
final ContentType requestedContentType = ContentNegotiator.
@ -362,6 +370,7 @@ public class ODataDispatcher {
type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary) ?
RepresentationType.BINARY : RepresentationType.VALUE;
if (method == HttpMethod.GET) {
validatePreferHeader(request);
final ContentType requestedContentType = ContentNegotiator.
doContentNegotiation(uriInfo.getFormatOption(),
request, handler.getCustomContentTypeSupport(), valueRepresentationType);
@ -377,6 +386,7 @@ public class ODataDispatcher {
handler.selectProcessor(PrimitiveValueProcessor.class)
.updatePrimitiveValue(request, response, uriInfo, requestFormat, responseFormat);
} else if (method == HttpMethod.DELETE && resource instanceof UriResourceProperty) {
validatePreferHeader(request);
validatePreconditions(request, false);
handler.selectProcessor(PrimitiveValueProcessor.class)
.deletePrimitiveValue(request, response, uriInfo);
@ -391,6 +401,7 @@ public class ODataDispatcher {
final RepresentationType complexRepresentationType = isCollection ? RepresentationType.COLLECTION_COMPLEX
: RepresentationType.COMPLEX;
if (method == HttpMethod.GET) {
validatePreferHeader(request);
final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
request, handler.getCustomContentTypeSupport(), complexRepresentationType);
if (isCollection) {
@ -414,6 +425,7 @@ public class ODataDispatcher {
.updateComplex(request, response, uriInfo, requestFormat, responseFormat);
}
} else if (method == HttpMethod.DELETE) {
validatePreferHeader(request);
validatePreconditions(request, false);
if (isCollection) {
handler.selectProcessor(ComplexCollectionProcessor.class)
@ -433,6 +445,7 @@ public class ODataDispatcher {
final RepresentationType representationType = isCollection ? RepresentationType.COLLECTION_PRIMITIVE
: RepresentationType.PRIMITIVE;
if (method == HttpMethod.GET) {
validatePreferHeader(request);
final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
request, handler.getCustomContentTypeSupport(), representationType);
if (isCollection) {
@ -456,6 +469,7 @@ public class ODataDispatcher {
.updatePrimitive(request, response, uriInfo, requestFormat, responseFormat);
}
} else if (method == HttpMethod.DELETE) {
validatePreferHeader(request);
validatePreconditions(request, false);
if (isCollection) {
handler.selectProcessor(PrimitiveCollectionProcessor.class)
@ -471,6 +485,7 @@ public class ODataDispatcher {
private void handleCountDispatching(final ODataRequest request, final ODataResponse response,
final int lastPathSegmentIndex) throws ODataApplicationException, ODataLibraryException {
validatePreferHeader(request);
final UriResource resource = uriInfo.getUriResourceParts().get(lastPathSegmentIndex - 1);
if (resource instanceof UriResourceEntitySet
|| resource instanceof UriResourceNavigation
@ -505,6 +520,7 @@ public class ODataDispatcher {
ODataHandlerException {
final HttpMethod method = request.getMethod();
if (method == HttpMethod.GET) {
validatePreferHeader(request);
final ContentType requestedContentType = ContentNegotiator.
doContentNegotiation(uriInfo.getFormatOption(),
request, handler.getCustomContentTypeSupport(), RepresentationType.COLLECTION_ENTITY);
@ -515,6 +531,7 @@ public class ODataDispatcher {
doContentNegotiation(uriInfo.getFormatOption(),
request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY);
if (isMedia) {
validatePreferHeader(request);
final ContentType requestFormat = ContentType.parse(
request.getHeader(HttpHeader.CONTENT_TYPE));
handler.selectProcessor(MediaEntityProcessor.class)
@ -530,6 +547,23 @@ public class ODataDispatcher {
throwMethodNotAllowed(method);
}
}
/**Checks if Prefer header is set with return=minimal or
* return=representation for GET and DELETE requests
* @param request
* @throws ODataHandlerException
*/
private void validatePreferHeader(final ODataRequest request) throws ODataHandlerException {
final List<String> returnPreference = request.getHeaders(HttpHeader.PREFER);
if (null != returnPreference) {
for (String preference : returnPreference) {
if (preference.equals(RETURN_MINIMAL) || preference.equals(RETURN_REPRESENTATION)) {
throw new ODataHandlerException("Prefer Header not supported: " + preference,
ODataHandlerException.MessageKeys.INVALID_PREFER_HEADER, preference);
}
}
}
}
private boolean isSingletonMedia(final UriResource pathSegment) {
return pathSegment instanceof UriResourceSingleton
@ -544,12 +578,16 @@ public class ODataDispatcher {
ODataLibraryException, ODataHandlerException, PreconditionException {
final HttpMethod method = request.getMethod();
if (method == HttpMethod.GET) {
validatePreferHeader(request);
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) {
if (isMedia) {
validatePreferHeader(request);
}
validatePreconditions(request, false);
final ContentType requestFormat = getSupportedContentType(
request.getHeader(HttpHeader.CONTENT_TYPE),
@ -562,6 +600,7 @@ public class ODataDispatcher {
} else if (method == HttpMethod.DELETE && !isSingleton) {
validateIsSingleton(method);
validatePreconditions(request, false);
validatePreferHeader(request);
handler.selectProcessor(isMedia ? MediaEntityProcessor.class : EntityProcessor.class)
.deleteEntity(request, response, uriInfo);
} else {

View File

@ -100,7 +100,8 @@ public class ODataExceptionHelper {
|| ODataHandlerException.MessageKeys.AMBIGUOUS_XHTTP_METHOD.equals(e.getMessageKey())
|| ODataHandlerException.MessageKeys.MISSING_CONTENT_TYPE.equals(e.getMessageKey())
|| ODataHandlerException.MessageKeys.INVALID_CONTENT_TYPE.equals(e.getMessageKey())
|| ODataHandlerException.MessageKeys.UNSUPPORTED_CONTENT_TYPE.equals(e.getMessageKey())) {
|| ODataHandlerException.MessageKeys.UNSUPPORTED_CONTENT_TYPE.equals(e.getMessageKey())
|| ODataHandlerException.MessageKeys.INVALID_PREFER_HEADER.equals(e.getMessageKey())) {
serverError.setStatusCode(HttpStatusCode.BAD_REQUEST.getStatusCode());
} else if (ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED.equals(e.getMessageKey())) {
serverError.setStatusCode(HttpStatusCode.METHOD_NOT_ALLOWED.getStatusCode());

View File

@ -42,7 +42,9 @@ public class ODataHandlerException extends ODataLibraryException {
/** parameter: content type */
INVALID_CONTENT_TYPE,
/** parameter: version */
ODATA_VERSION_NOT_SUPPORTED;
ODATA_VERSION_NOT_SUPPORTED,
/** parameter: prefer header */
INVALID_PREFER_HEADER;
@Override
public String getKey() {

View File

@ -18,6 +18,8 @@
*/
package org.apache.olingo.server.core.batchhandler;
import java.util.List;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpMethod;
@ -29,12 +31,15 @@ import org.apache.olingo.server.api.batch.BatchFacade;
import org.apache.olingo.server.api.deserializer.batch.BatchDeserializerException;
import org.apache.olingo.server.api.deserializer.batch.BatchDeserializerException.MessageKeys;
import org.apache.olingo.server.api.processor.BatchProcessor;
import org.apache.olingo.server.core.ODataHandlerException;
import org.apache.olingo.server.core.ODataHandlerImpl;
import org.apache.olingo.server.core.deserializer.batch.BatchParserCommon;
public class BatchHandler {
private final BatchProcessor batchProcessor;
private final ODataHandlerImpl oDataHandler;
private static final String RETURN_MINIMAL = "return=minimal";
private static final String RETURN_REPRESENTATION = "return=representation";
public BatchHandler(final ODataHandlerImpl oDataHandler, final BatchProcessor batchProcessor) {
@ -45,10 +50,28 @@ public class BatchHandler {
public void process(final ODataRequest request, final ODataResponse response, final boolean isStrict)
throws ODataApplicationException, ODataLibraryException {
validateRequest(request);
validatePreferHeader(request);
final BatchFacade operation = new BatchFacadeImpl(oDataHandler, batchProcessor, isStrict);
batchProcessor.processBatch(operation, request, response);
}
/** Checks if Prefer header is set with return=minimal or
* return=representation for batch requests
* @param request
* @throws ODataHandlerException
*/
private void validatePreferHeader(final ODataRequest request) throws ODataHandlerException {
final List<String> returnPreference = request.getHeaders(HttpHeader.PREFER);
if (null != returnPreference) {
for (String preference : returnPreference) {
if (preference.equals(RETURN_MINIMAL) || preference.equals(RETURN_REPRESENTATION)) {
throw new ODataHandlerException("Prefer Header not supported: " + preference,
ODataHandlerException.MessageKeys.INVALID_PREFER_HEADER, preference);
}
}
}
}
private void validateRequest(final ODataRequest request) throws BatchDeserializerException {
validateHttpMethod(request);

View File

@ -27,6 +27,7 @@ ODataHandlerException.ODATA_VERSION_NOT_SUPPORTED=OData version '%1$s' is not su
ODataHandlerException.MISSING_CONTENT_TYPE=The Content-Type HTTP header must be specified for this request.
ODataHandlerException.UNSUPPORTED_CONTENT_TYPE=The content type '%1$s' is not supported for this request.
ODataHandlerException.INVALID_CONTENT_TYPE=The content type '%1$s' is not valid.
ODataHandlerException.INVALID_PREFER_HEADER=The Prefer header '%1$s' is not supported for this HTTP Method.
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.