Repository: olingo-odata4
Updated Branches:
  refs/heads/master f3919036a -> 03a02d2d6


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


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

Branch: refs/heads/master
Commit: 03a02d2d69f2a76aba1db889ca5e94606cd3e7ed
Parents: f391903
Author: ramya vasanth <[email protected]>
Authored: Wed May 23 15:36:18 2018 +0530
Committer: ramya vasanth <[email protected]>
Committed: Wed May 23 15:36:18 2018 +0530

----------------------------------------------------------------------
 .../http/PreferHeaderForGetAndDeleteITCase.java | 355 +++++++++++++++++++
 .../basicBatchPostWithPreferHeader.batch        |  34 ++
 .../olingo/server/core/ODataDispatcher.java     |  43 ++-
 .../server/core/ODataExceptionHelper.java       |   3 +-
 .../server/core/ODataHandlerException.java      |   4 +-
 .../server/core/batchhandler/BatchHandler.java  |  23 ++
 .../server-core-exceptions-i18n.properties      |   1 +
 7 files changed, 459 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03a02d2d/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/PreferHeaderForGetAndDeleteITCase.java
----------------------------------------------------------------------
diff --git 
a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/PreferHeaderForGetAndDeleteITCase.java
 
b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/PreferHeaderForGetAndDeleteITCase.java
new file mode 100644
index 0000000..180c957
--- /dev/null
+++ 
b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/PreferHeaderForGetAndDeleteITCase.java
@@ -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;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03a02d2d/fit/src/test/resources/basicBatchPostWithPreferHeader.batch
----------------------------------------------------------------------
diff --git a/fit/src/test/resources/basicBatchPostWithPreferHeader.batch 
b/fit/src/test/resources/basicBatchPostWithPreferHeader.batch
new file mode 100644
index 0000000..319a6a0
--- /dev/null
+++ b/fit/src/test/resources/basicBatchPostWithPreferHeader.batch
@@ -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--
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03a02d2d/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
index 63f45c5..35a716d 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
@@ -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 {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03a02d2d/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHelper.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHelper.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHelper.java
index ce6e94e..4f75590 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHelper.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHelper.java
@@ -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());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03a02d2d/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerException.java
----------------------------------------------------------------------
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 acf7c38..5596512 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
@@ -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() {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03a02d2d/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java
index 9b6c643..c5f8746 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java
@@ -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);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03a02d2d/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties
----------------------------------------------------------------------
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 f9aa128..964cf35 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
@@ -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.

Reply via email to