You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ra...@apache.org on 2018/03/12 08:37:31 UTC

olingo-odata4 git commit: [OLINGO-1238] Code Improvements in handling exceptions with odataVersion headers and accept headers

Repository: olingo-odata4
Updated Branches:
  refs/heads/master 75cc7197e -> eb112032d


[OLINGO-1238] Code Improvements in handling exceptions with odataVersion headers and accept headers


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

Branch: refs/heads/master
Commit: eb112032ddc0fa5264b91811d8a5ce4020326d0f
Parents: 75cc719
Author: ramya vasanth <ra...@sap.com>
Authored: Mon Mar 12 14:07:22 2018 +0530
Committer: ramya vasanth <ra...@sap.com>
Committed: Mon Mar 12 14:07:22 2018 +0530

----------------------------------------------------------------------
 .../AcceptHeaderAcceptCharsetHeaderITCase.java  | 336 +++++++++++++++++++
 .../http/ODataVersionConformanceITCase.java     | 179 ++++++++++
 .../api/edm/constants/ODataServiceVersion.java  |  15 +
 .../commons/api/format/AcceptCharset.java       | 155 +++++++++
 .../olingo/commons/api/format/AcceptType.java   |  31 +-
 .../commons/api/format/AcceptCharsetTest.java   | 132 ++++++++
 .../commons/api/format/AcceptTypeTest.java      |  93 ++++-
 .../AcceptHeaderContentNegotiatorException.java |  53 +++
 .../olingo/server/core/ContentNegotiator.java   |  73 +++-
 .../server/core/ContentNegotiatorException.java |   6 +-
 .../server/core/ODataExceptionHelper.java       |   7 +
 .../olingo/server/core/ODataHandlerImpl.java    |  20 +-
 .../server-core-exceptions-i18n.properties      |   6 +
 .../server/core/ContentNegotiatorTest.java      |  79 ++++-
 .../server/core/ODataHandlerImplTest.java       | 173 ++++++++++
 15 files changed, 1327 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/AcceptHeaderAcceptCharsetHeaderITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/AcceptHeaderAcceptCharsetHeaderITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/AcceptHeaderAcceptCharsetHeaderITCase.java
new file mode 100644
index 0000000..b60ebb0
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/AcceptHeaderAcceptCharsetHeaderITCase.java
@@ -0,0 +1,336 @@
+/*
+ * 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.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+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.junit.Test;
+
+public class AcceptHeaderAcceptCharsetHeaderITCase extends AbstractBaseTestITCase {
+
+  private static final String SERVICE_URI = TecSvcConst.BASE_URI + "/";
+  
+  @Test
+  public void validAcceptHeader() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT, "application/json");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode());
+
+    final String content = IOUtils.toString(connection.getInputStream());
+    assertNotNull(content);
+  }
+  
+  @Test
+  public void invalidAcceptHeader1() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT, "abc");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
+
+    final String content = IOUtils.toString(connection.getErrorStream());
+    assertTrue(content.contains("The content-type range 'abc' is not supported "
+        + "as value of the Accept header."));
+  }
+  
+  @Test
+  public void invalidAcceptHeader2() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT, "application/xyz");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.NOT_ACCEPTABLE.getStatusCode(), connection.getResponseCode());
+
+    final String content = IOUtils.toString(connection.getErrorStream());
+    assertTrue(content.contains("The content-type range 'application/xyz' is "
+        + "not supported as value of the Accept header."));
+  }
+  
+  @Test
+  public void validAcceptCharsetHeader() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT_CHARSET, "utf-8;q=0.1");
+    connection.setRequestProperty(HttpHeader.ACCEPT, ContentType.APPLICATION_JSON.toContentTypeString());
+    connection.connect();
+
+    assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode());
+    assertNotNull(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    ContentType contentType = ContentType.parse(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    assertEquals("application", contentType.getType());
+    assertEquals("json", contentType.getSubtype());
+    assertEquals(3, contentType.getParameters().size());
+    assertEquals("0.1", contentType.getParameter("q"));
+    assertEquals("minimal", contentType.getParameter("odata.metadata"));
+    assertEquals("utf-8", contentType.getParameter("charset"));
+
+    final String content = IOUtils.toString(connection.getInputStream());
+    assertNotNull(content);
+  }
+  
+  @Test
+  public void invalidAcceptCharsetHeader1() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT_CHARSET, "US-ASCII");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.NOT_ACCEPTABLE.getStatusCode(), connection.getResponseCode());
+    
+    final String content = IOUtils.toString(connection.getErrorStream());
+    assertTrue(content.contains("The charset specified in Accept charset header "
+        + "'US-ASCII' is not supported."));
+  }
+  
+  @Test
+  public void invalidAcceptCharsetHeader2() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT_CHARSET, "abc");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
+    
+    final String content = IOUtils.toString(connection.getErrorStream());
+    assertTrue(content.contains("The charset specified in Accept charset header 'abc' is not supported."));
+  }
+  
+  @Test
+  public void unsupportedAcceptHeaderWithSupportedAcceptCharsetHeader() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT_CHARSET, "utf8;q=0.1");
+    connection.setRequestProperty(HttpHeader.ACCEPT, "application/json;charset=iso8859-1");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode());
+    assertNotNull(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    ContentType contentType = ContentType.parse(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    assertEquals("application", contentType.getType());
+    assertEquals("json", contentType.getSubtype());
+    assertEquals(3, contentType.getParameters().size());
+    assertEquals("0.1", contentType.getParameter("q"));
+    assertEquals("minimal", contentType.getParameter("odata.metadata"));
+    assertEquals("utf8", contentType.getParameter("charset"));
+
+    final String content = IOUtils.toString(connection.getInputStream());
+    assertNotNull(content);
+  }
+  
+  @Test
+  public void supportedAcceptHeaderWithUnSupportedAcceptCharsetHeader() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT_CHARSET, "iso-8859-1");
+    connection.setRequestProperty(HttpHeader.ACCEPT, "application/json;charset=utf8");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.NOT_ACCEPTABLE.getStatusCode(), connection.getResponseCode());
+
+    final String content = IOUtils.toString(connection.getErrorStream());
+    assertTrue(content.contains("The charset specified in Accept charset header "
+        + "'iso-8859-1' is not supported."));
+  }
+  
+  @Test
+  public void validFormatWithAcceptCharsetHeader() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim?$format=json");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT_CHARSET, "utf-8;q=0.1");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode());
+    assertNotNull(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    ContentType contentType = ContentType.parse(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    assertEquals("application", contentType.getType());
+    assertEquals("json", contentType.getSubtype());
+    assertEquals(3, contentType.getParameters().size());
+    assertEquals("0.1", contentType.getParameter("q"));
+    assertEquals("minimal", contentType.getParameter("odata.metadata"));
+    assertEquals("utf-8", contentType.getParameter("charset"));
+
+    final String content = IOUtils.toString(connection.getInputStream());
+    assertNotNull(content);
+  }
+  
+  @Test
+  public void validFormatWithUnsupportedAcceptCharsetHeader() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim?$format=json");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT_CHARSET, "iso-8859-1");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.NOT_ACCEPTABLE.getStatusCode(), connection.getResponseCode());
+
+    final String content = IOUtils.toString(connection.getErrorStream());
+    assertTrue(content.contains("The charset specified in Accept charset header "
+        + "'iso-8859-1' is not supported."));
+  }
+  
+  @Test
+  public void validFormatWithIllegalAcceptCharsetHeader() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim?$format=json");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT_CHARSET, "abc");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
+
+    final String content = IOUtils.toString(connection.getErrorStream());
+    assertTrue(content.contains("The charset specified in Accept charset "
+        + "header 'abc' is not supported."));
+  }
+  
+  @Test
+  public void multipleValuesInAcceptCharsetHeader1() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT_CHARSET, "utf-8;q=0.1,iso-8859-1,unicode-1-1");
+    connection.setRequestProperty(HttpHeader.ACCEPT, "application/json");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode());
+    assertNotNull(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    ContentType contentType = ContentType.parse(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    assertEquals("application", contentType.getType());
+    assertEquals("json", contentType.getSubtype());
+    assertEquals(3, contentType.getParameters().size());
+    assertEquals("minimal", contentType.getParameter("odata.metadata"));
+    assertEquals("utf-8", contentType.getParameter("charset"));
+    assertEquals("0.1", contentType.getParameter("q"));
+
+    final String content = IOUtils.toString(connection.getInputStream());
+    assertNotNull(content);
+  }
+  
+  @Test
+  public void multipleValuesInAcceptCharsetHeader2() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim"); 
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT_CHARSET, "utf-8;q=0.1,utf-8;q=0.8,utf8");
+    connection.setRequestProperty(HttpHeader.ACCEPT, ContentType.APPLICATION_JSON.toContentTypeString());
+    connection.connect();
+
+    assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode());
+    assertNotNull(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    ContentType contentType = ContentType.parse(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    assertEquals("application", contentType.getType());
+    assertEquals("json", contentType.getSubtype());
+    assertEquals(2, contentType.getParameters().size());
+    assertEquals("utf8", contentType.getParameter("charset"));
+    assertEquals("minimal", contentType.getParameter("odata.metadata"));
+    
+    final String content = IOUtils.toString(connection.getInputStream());
+    assertNotNull(content);
+  }
+  
+  @Test
+  public void multipleValuesInAcceptHeader1() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT, "application/json,"
+        + "application/json;q=0.1,application/json;q=0.8");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode());
+    assertNotNull(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    ContentType contentType = ContentType.parse(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    assertEquals("application", contentType.getType());
+    assertEquals("json", contentType.getSubtype());
+    assertEquals(1, contentType.getParameters().size());
+    assertEquals("minimal", contentType.getParameter("odata.metadata"));
+
+    final String content = IOUtils.toString(connection.getInputStream());
+    assertNotNull(content);
+  }
+  
+  @Test
+  public void multipleValuesInAcceptHeader2() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ACCEPT, "application/json,"
+        + "application/json;q=0.1,application/json;q=0.8,abc");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode());
+    assertNotNull(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    ContentType contentType = ContentType.parse(connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+    assertEquals("application", contentType.getType());
+    assertEquals("json", contentType.getSubtype());
+    assertEquals(1, contentType.getParameters().size());
+    assertEquals("minimal", contentType.getParameter("odata.metadata"));
+
+    final String content = IOUtils.toString(connection.getInputStream());
+    assertNotNull(content);
+  }
+  
+  @Override
+  protected ODataClient getClient() {
+    return null;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/ODataVersionConformanceITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/ODataVersionConformanceITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/ODataVersionConformanceITCase.java
new file mode 100644
index 0000000..a8c8912
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/ODataVersionConformanceITCase.java
@@ -0,0 +1,179 @@
+/*
+ * 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.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.olingo.client.api.ODataClient;
+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.junit.Test;
+
+public class ODataVersionConformanceITCase extends AbstractBaseTestITCase {
+
+  private static final String SERVICE_URI = TecSvcConst.BASE_URI + "/";
+
+  @Test
+  public void invalidODataVersionHeader1() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name()); 
+    connection.setRequestProperty(HttpHeader.ODATA_VERSION, "3.0");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
+    assertEquals("4.0", connection.getHeaderField(HttpHeader.ODATA_VERSION));
+
+    final String content = IOUtils.toString(connection.getErrorStream());
+    assertTrue(content.contains("OData version '3.0' is not supported."));
+  }
+  
+  @Test
+  public void invalidODataVersionHeader2() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ODATA_VERSION, "5.0");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
+    assertEquals("4.0", connection.getHeaderField(HttpHeader.ODATA_VERSION));
+
+    final String content = IOUtils.toString(connection.getErrorStream());
+    assertTrue(content.contains("OData version '5.0' is not supported."));
+  }
+  
+  @Test
+  public void invalidODataMaxVersionHeader1() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ODATA_MAX_VERSION, "3.0");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
+    assertEquals("4.0", connection.getHeaderField(HttpHeader.ODATA_VERSION));
+
+    final String content = IOUtils.toString(connection.getErrorStream());
+    assertTrue(content.contains("OData version '3.0' is not supported."));
+  }
+  
+  @Test
+  public void validODataMaxVersionHeader() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ODATA_MAX_VERSION, "5.0");
+    connection.connect();
+
+    assertEquals("4.0", connection.getHeaderField(HttpHeader.ODATA_VERSION));
+
+    final String content = IOUtils.toString(connection.getErrorStream());
+    assertNotNull(content);
+  }
+
+  @Test
+  public void validODataVersionAndMaxVersionHeader() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ODATA_VERSION, "4.0");
+    connection.setRequestProperty(HttpHeader.ODATA_MAX_VERSION, "5.0");
+    connection.connect();
+
+    assertEquals("4.0", connection.getHeaderField(HttpHeader.ODATA_VERSION));
+
+    final String content = IOUtils.toString(connection.getErrorStream());
+    assertNotNull(content);;
+  }
+  
+  @Test
+  public void validODataVersionAndMaxVersionHeader1() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim?$format=json");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ODATA_VERSION, "4.0");
+    connection.setRequestProperty(HttpHeader.ODATA_MAX_VERSION, "4.01");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode());
+    assertEquals("4.0", connection.getHeaderField(HttpHeader.ODATA_VERSION));
+    assertEquals("application/json; odata.metadata=minimal", 
+        connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+
+    final String content = IOUtils.toString(connection.getInputStream());
+    assertNotNull(content);
+  }
+  
+  @Test
+  public void validODataVersionAndMaxVersionHeader2() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim?$format=json");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ODATA_VERSION, "4.0");
+    connection.setRequestProperty(HttpHeader.ODATA_MAX_VERSION, "4.0");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode());
+    assertEquals("4.0", connection.getHeaderField(HttpHeader.ODATA_VERSION));
+    assertEquals("application/json; odata.metadata=minimal", 
+        connection.getHeaderField(HttpHeader.CONTENT_TYPE));
+
+    final String content = IOUtils.toString(connection.getInputStream());
+    assertNotNull(content);
+  }
+  
+  @Test
+  public void invalidODataVersionAndMaxVersionHeader() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty(HttpHeader.ODATA_VERSION, "5.0");
+    connection.setRequestProperty(HttpHeader.ODATA_MAX_VERSION, "5.0");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
+    assertEquals("4.0", connection.getHeaderField(HttpHeader.ODATA_VERSION));
+
+    final String content = IOUtils.toString(connection.getErrorStream());
+    assertTrue(content.contains("OData version '5.0' is not supported."));
+  }
+  
+  @Override
+  protected ODataClient getClient() {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/constants/ODataServiceVersion.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/constants/ODataServiceVersion.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/constants/ODataServiceVersion.java
index c781191..1ef8929 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/constants/ODataServiceVersion.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/constants/ODataServiceVersion.java
@@ -87,6 +87,21 @@ public enum ODataServiceVersion {
     return me > other;
   }
 
+  public static boolean isValidODataVersion(String value) {
+    final double version4 = Double.parseDouble(extractDataServiceVersionString(ODataServiceVersion.V40.toString()));
+    final double version401 = Double.parseDouble(extractDataServiceVersionString(ODataServiceVersion.V401.toString()));
+    final double other = Double.parseDouble(extractDataServiceVersionString(value));
+    
+    return (other == version4) || (other == version401);
+  }
+  
+  public static boolean isValidMaxODataVersion(String value) {
+    final double version4 = Double.parseDouble(extractDataServiceVersionString(ODataServiceVersion.V40.toString()));
+    final double other = Double.parseDouble(extractDataServiceVersionString(value));
+    
+    return other >= version4;
+  }
+  
   /**
    * Extract data service version and return it.
    *

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptCharset.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptCharset.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptCharset.java
new file mode 100644
index 0000000..85eaf91
--- /dev/null
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptCharset.java
@@ -0,0 +1,155 @@
+/*
+ * 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.commons.api.format;
+
+import java.nio.charset.Charset;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+public class AcceptCharset {
+
+  private static final Pattern Q_PATTERN = Pattern.compile("\\A(?:0(?:\\.\\d{0,3})?)|(?:1(?:\\.0{0,3})?)\\Z");
+  private final String charset;
+  private final Map<String, String> parameters;
+  private final Float quality;
+  
+  private AcceptCharset(final String charset) {
+    parameters = TypeUtil.createParameterMap();
+    this.charset = parse(charset, parameters);
+    
+    if (TypeUtil.MEDIA_TYPE_WILDCARD.equals(this.charset)) {
+      throw new IllegalArgumentException("Unsupported charset in accept charset header:" + this.charset);
+    } else {
+      try {
+        Charset.forName(this.charset);
+      } catch (UnsupportedCharsetException e) {
+        throw new UnsupportedCharsetException("Illegal charset in accept charset header:" + this.charset);
+      }
+      if (!(this.charset.equalsIgnoreCase("utf8")) && !(this.charset.equalsIgnoreCase("utf-8"))) {
+        throw new IllegalArgumentException("Unsupported charset in accept charset header:" + this.charset);
+      }
+    }
+    final String q = parameters.get(TypeUtil.PARAMETER_Q);
+    if (q == null) {
+      quality = 1F;
+    } else if (Q_PATTERN.matcher(q).matches()) {
+        quality = Float.valueOf(q);
+    } else {
+      throw new IllegalArgumentException("Illegal quality parameter '" + q + "'.");
+    }
+  }
+
+  private String parse(String acceptCharset, Map<String, String> parameters) {
+    final String[] charsetAndParameters = acceptCharset.split(TypeUtil.PARAMETER_SEPARATOR, 2);
+    acceptCharset = charsetAndParameters[0];
+    final String params = (charsetAndParameters.length > 1 ? charsetAndParameters[1] : null);
+    TypeUtil.parseParameters(params, parameters);
+    return acceptCharset;
+  }
+  
+  /**
+   * Creates a list of {@link AcceptCharset} objects based on given input string.
+   * @param acceptCharsets accept types, comma-separated, as specified for the HTTP header <code>Accept-Charset</code>
+   * @return a list of <code>AcceptType</code> objects
+   * @throws Exception 
+   * @throws IllegalArgumentException if input string is not parseable
+   */
+  public static List<AcceptCharset> create(final String acceptCharsets) {
+    if (acceptCharsets == null) {
+      throw new IllegalArgumentException("Type parameter MUST NOT be null.");
+    }
+    List<AcceptCharset> result = new ArrayList<AcceptCharset>();
+    List<Exception> exceptionList = new ArrayList<Exception>();
+
+    String[] values = acceptCharsets.split(",");
+    for (String value : values) {
+      try {
+        result.add(new AcceptCharset(value.trim()));
+      } catch (UnsupportedCharsetException e) {
+        exceptionList.add(e);
+      } catch (IllegalArgumentException e) {
+        exceptionList.add(e);
+      }
+    }
+
+    if (result.isEmpty()) {
+      if (exceptionList.get(0) instanceof UnsupportedCharsetException) {
+        throw new UnsupportedCharsetException(exceptionList.get(0).getMessage());
+      } else if (exceptionList.get(0) instanceof IllegalArgumentException) {
+        throw new IllegalArgumentException(exceptionList.get(0).getMessage());
+      }
+    }
+    sort(result);
+    
+    return result;
+  }
+  
+  public String getCharset() {
+    return charset;
+  }
+
+  public Map<String, String> getParameters() {
+    return Collections.unmodifiableMap(parameters);
+  }
+
+  public String getParameter(final String name) {
+    return parameters.get(name.toLowerCase(Locale.ROOT));
+  }
+
+  public Float getQuality() {
+    return quality;
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder result = new StringBuilder();
+    result.append(charset);
+    for (final Map.Entry<String, String> entry : parameters.entrySet()) {
+      result.append(';').append(entry.getKey()).append('=').append(entry.getValue());
+    }
+
+    return result.toString();
+  }
+  
+  /**
+   * Sorts given list of Accept charsets
+   * according to their quality-parameter values and their specificity
+   * as defined in RFC 2616, chapters 14.2.
+   * @param toSort list which is sorted and hence re-arranged
+   */
+  private static void sort(List<AcceptCharset> toSort) {
+    Collections.sort(toSort,
+        new Comparator<AcceptCharset>() {
+      @Override
+      public int compare(final AcceptCharset a1, final AcceptCharset a2) {
+        int compare = a2.getQuality().compareTo(a1.getQuality());
+        if (compare != 0) {
+          return compare;
+        }
+        return a2.getParameters().size() - a1.getParameters().size();
+      }
+    });
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java
index f864008..d2a1b24 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java
@@ -63,9 +63,6 @@ public final class AcceptType {
   }
 
   private AcceptType(final String type) {
-    if (type == null) {
-      throw new IllegalArgumentException("Type parameter MUST NOT be null.");
-    }
     List<String> typeSubtype = new ArrayList<String>();
     parameters = TypeUtil.createParameterMap();
 
@@ -119,13 +116,24 @@ public final class AcceptType {
    * @throws IllegalArgumentException if input string is not parseable
    */
   public static List<AcceptType> create(final String acceptTypes) {
+    if (acceptTypes == null) {
+      throw new IllegalArgumentException("Type parameter MUST NOT be null.");
+    }
     List<AcceptType> result = new ArrayList<AcceptType>();
+    List<IllegalArgumentException> exceptionList = new ArrayList<IllegalArgumentException>();
 
     String[] values = acceptTypes.split(",");
     for (String value : values) {
-      result.add(new AcceptType(value.trim()));
+      try {
+        result.add(new AcceptType(value.trim()));
+      } catch (IllegalArgumentException e) {
+        exceptionList.add(e);
+      }
     }
 
+    if (result.isEmpty()) {
+      throw exceptionList.get(0);
+    }
     sort(result);
 
     return result;
@@ -198,13 +206,18 @@ public final class AcceptType {
     }
     Map<String, String> compareParameters = contentType.getParameters();
     for (final Map.Entry<String, String> entry : parameters.entrySet()) {
-      if (compareParameters.containsKey(entry.getKey()) || TypeUtil.PARAMETER_Q.equalsIgnoreCase(entry.getKey())) {
-        String compare = compareParameters.get(entry.getKey());
-        if (!entry.getValue().equalsIgnoreCase(compare) && !TypeUtil.PARAMETER_Q.equalsIgnoreCase(entry.getKey())) {
+      if (entry.getKey().equalsIgnoreCase(ContentType.PARAMETER_CHARSET) && 
+          compareParameters.containsKey(entry.getKey())) {
+        continue;
+      } else {
+        if (compareParameters.containsKey(entry.getKey()) || TypeUtil.PARAMETER_Q.equalsIgnoreCase(entry.getKey())) {
+          String compare = compareParameters.get(entry.getKey());
+          if (!entry.getValue().equalsIgnoreCase(compare) && !TypeUtil.PARAMETER_Q.equalsIgnoreCase(entry.getKey())) {
+            return false;
+          }
+        } else {
           return false;
         }
-      } else {
-        return false;
       }
     }
     return true;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptCharsetTest.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptCharsetTest.java b/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptCharsetTest.java
new file mode 100644
index 0000000..a963f66
--- /dev/null
+++ b/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptCharsetTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.commons.api.format;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.List;
+
+import org.junit.Test;
+
+public class AcceptCharsetTest {
+  @Test
+  public void wildcard() {
+    expectCreateError("*");
+  }
+  
+  @Test
+  public void illegalCharset() {
+    expectCreateError("abc");
+  }
+  
+  @Test
+  public void unsupportedCharset() {
+    expectCreateError("iso-8859-1");
+  }
+  
+  @Test
+  public void correctCharset() {
+    List<AcceptCharset> charsets = AcceptCharset.create("utf-8");
+    assertEquals("utf-8", charsets.get(0).getCharset());
+  }
+  
+  @Test
+  public void correctCharsetWithQParams() {
+    List<AcceptCharset> charsets = AcceptCharset.create("utf-8;q=0.8");
+    assertEquals("utf-8", charsets.get(0).getCharset());
+    assertEquals(1, charsets.get(0).getParameters().size());
+    assertEquals("0.8", charsets.get(0).getParameter(TypeUtil.PARAMETER_Q));
+    assertEquals(Float.parseFloat("0.8"), 
+        charsets.get(0).getQuality().floatValue(), Float.parseFloat("0.8"));
+  }
+  
+  @Test
+  public void multipleCharsetsWithQParams() {
+    List<AcceptCharset> charsets = AcceptCharset.create("utf-8;q=0.1, utf8;q=0.8");
+    assertEquals("utf8", charsets.get(0).getCharset());
+    assertEquals("utf-8", charsets.get(1).getCharset());
+    assertEquals(1, charsets.get(0).getParameters().size());
+    assertEquals(1, charsets.get(1).getParameters().size());
+    assertEquals("0.8", charsets.get(0).getParameter(TypeUtil.PARAMETER_Q));
+    assertEquals("0.1", charsets.get(1).getParameter(TypeUtil.PARAMETER_Q));
+  }
+  
+  @Test
+  public void multipleCharsetsWithQParamsAndUnsupportedCharsets() {
+    List<AcceptCharset> charsets = AcceptCharset.create("utf-8;q=0.1, utf8;q=0.8, iso-8859-1, abc");
+    assertEquals("utf8", charsets.get(0).getCharset());
+    assertEquals("utf-8", charsets.get(1).getCharset());
+    assertEquals(1, charsets.get(0).getParameters().size());
+    assertEquals(1, charsets.get(1).getParameters().size());
+    assertEquals("0.8", charsets.get(0).getParameter(TypeUtil.PARAMETER_Q));
+    assertEquals("0.1", charsets.get(1).getParameter(TypeUtil.PARAMETER_Q));
+    assertEquals("utf8;q=0.8", charsets.get(0).toString());
+  }
+  
+  @Test
+  public void multipleCharsetsWithSameQParams() {
+    List<AcceptCharset> charsets = AcceptCharset.create("utf-8;q=0.1, utf8;q=0.1");
+    assertEquals("utf-8", charsets.get(0).getCharset());
+    assertEquals("utf8", charsets.get(1).getCharset());
+    assertEquals(1, charsets.get(0).getParameters().size());
+    assertEquals(1, charsets.get(1).getParameters().size());
+    assertEquals("0.1", charsets.get(0).getParameter(TypeUtil.PARAMETER_Q));
+    assertEquals("0.1", charsets.get(1).getParameter(TypeUtil.PARAMETER_Q));
+    assertEquals("utf-8;q=0.1", charsets.get(0).toString());
+  }
+  
+  @Test
+  public void multipleCharsetsFail() {
+    expectCreateError("iso-8859-5, unicode-1-1;q=0.8");
+  }
+  
+  private void expectCreateError(final String value) {
+    try {
+      AcceptCharset.create(value);
+      fail("Expected exception not thrown.");
+    } catch (UnsupportedCharsetException e) {
+      assertNotNull(e);
+    } catch (final IllegalArgumentException e) {
+      assertNotNull(e);
+    }
+  }
+  
+  @Test
+  public void illegalQParam() {
+    expectCreateError("utf-8;q=12");
+  }
+  
+  @Test
+  public void emptyCharset() {
+    expectCreateError("");
+  }
+  
+  @Test
+  public void nullCharset() {
+    expectCreateError(null);
+  }
+  
+  @Test
+  public void trailingSemicolon() {
+    expectCreateError("utf-8;");
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptTypeTest.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptTypeTest.java b/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptTypeTest.java
index 8902975..8fe0af1 100644
--- a/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptTypeTest.java
+++ b/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptTypeTest.java
@@ -171,4 +171,95 @@ public class AcceptTypeTest {
       assertNotNull(e);
     }
   }
-}
+  
+  @Test
+  public void multipleTypeswithQParameter() {
+    List<AcceptType> acceptTypes = AcceptType.create("application/json;q=0.2,application/json;q=0.2");
+
+    assertEquals(2, acceptTypes.size());
+    final AcceptType acceptType = acceptTypes.get(0);
+    assertEquals("application", acceptType.getType());
+    assertEquals("json", acceptType.getSubtype());
+    assertEquals("0.2", acceptType.getParameters().get(TypeUtil.PARAMETER_Q));
+    assertEquals("0.2", acceptType.getParameter(TypeUtil.PARAMETER_Q));
+    assertEquals(Float.valueOf(0.2F), acceptType.getQuality());
+    assertEquals("application/json;q=0.2", acceptType.toString());
+  }
+  
+  @Test
+  public void multipleTypeswithIllegalTypes() {
+    List<AcceptType> acceptTypes = AcceptType.create("application/json;q=0.2,abc");
+
+    assertEquals(1, acceptTypes.size());
+    final AcceptType acceptType = acceptTypes.get(0);
+    assertEquals("application", acceptType.getType());
+    assertEquals("json", acceptType.getSubtype());
+    assertEquals("0.2", acceptType.getParameters().get(TypeUtil.PARAMETER_Q));
+    assertEquals("0.2", acceptType.getParameter(TypeUtil.PARAMETER_Q));
+    assertEquals(Float.valueOf(0.2F), acceptType.getQuality());
+    assertEquals("application/json;q=0.2", acceptType.toString());
+  }
+  
+  @Test
+  public void multipleFormatErrors() {
+    expectCreateError("/,abc,a/a;parameter=");
+  }
+  
+  @Test
+  public void nullAcceptType() {
+    expectCreateError(null);
+  }
+  
+  @Test
+  public void emptyAcceptType() {
+    expectCreateError("");
+  }
+  
+  @Test
+  public void noTypeAcceptType() {
+    expectCreateError("/json");
+  }
+  
+  @Test
+  public void withCharset() {
+    List<AcceptType> acceptTypes = AcceptType.create("application/json;charset=utf-8");
+    assertEquals(1, acceptTypes.size());
+    final AcceptType acceptType = acceptTypes.get(0);
+    assertEquals("application", acceptType.getType());
+    assertEquals("json", acceptType.getSubtype());
+    assertEquals("utf-8", acceptType.getParameter(ContentType.PARAMETER_CHARSET));
+    
+    assertTrue(acceptType.matches(ContentType.create("application/json;"
+        + "odata.metadata=minimal;charset=utf-8")));
+    assertFalse(acceptType.matches(ContentType.create("application/atom+xml;"
+        + "odata.metadata=minimal;charset=utf-8")));
+    assertFalse(acceptType.matches(ContentType.create("application/json;"
+        + "odata.metadata=minimal")));
+  }
+  
+  @Test
+  public void withSubtypeStar1() {
+    List<AcceptType> acceptTypes = AcceptType.create("application/json,application/*");
+    assertEquals(2, acceptTypes.size());
+    final AcceptType acceptType1 = acceptTypes.get(0);
+    assertEquals("application", acceptType1.getType());
+    assertEquals("json", acceptType1.getSubtype());
+    
+    final AcceptType acceptType2 = acceptTypes.get(1);
+    assertEquals("application", acceptType2.getType());
+    assertEquals("*", acceptType2.getSubtype());
+  }
+  
+  @Test
+  public void withSubtypeStar2() {
+    List<AcceptType> acceptTypes = AcceptType.create("application/*,application/json");
+    assertEquals(2, acceptTypes.size());
+    final AcceptType acceptType1 = acceptTypes.get(0);
+    assertEquals("application", acceptType1.getType());
+    assertEquals("json", acceptType1.getSubtype());
+    
+    final AcceptType acceptType2 = acceptTypes.get(1);
+    assertEquals("application", acceptType2.getType());
+    assertEquals("*", acceptType2.getSubtype());
+  }
+ }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/lib/server-core/src/main/java/org/apache/olingo/server/core/AcceptHeaderContentNegotiatorException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/AcceptHeaderContentNegotiatorException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/AcceptHeaderContentNegotiatorException.java
new file mode 100644
index 0000000..e051560
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/AcceptHeaderContentNegotiatorException.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+public class AcceptHeaderContentNegotiatorException extends ContentNegotiatorException {
+  private static final long serialVersionUID = -8112658467394158700L;
+
+  public static enum MessageKeys implements MessageKey {
+    /** parameter: list of content-type ranges */
+    UNSUPPORTED_ACCEPT_TYPES,
+    /** parameter: format string */
+    UNSUPPORTED_FORMAT_OPTION,
+    /** parameter: accept charset header*/
+     UNSUPPORTED_ACCEPT_CHARSET_HEADER_OPTIONS;
+
+    @Override
+    public String getKey() {
+      return name();
+    }
+  }
+
+  public AcceptHeaderContentNegotiatorException(final String developmentMessage, final MessageKey messageKey,
+      final String... parameters) {
+    super(developmentMessage, messageKey, parameters);
+  }
+
+  public AcceptHeaderContentNegotiatorException(final String developmentMessage, final Throwable cause,
+      final MessageKey messageKey,
+      final String... parameters) {
+    super(developmentMessage, cause, messageKey, parameters);
+  }
+
+  @Override
+  protected String getBundleName() {
+    return DEFAULT_SERVER_BUNDLE_NAME;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
index 4aaeee7..4ece2b8 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
@@ -18,10 +18,14 @@
  */
 package org.apache.olingo.server.core;
 
+import java.nio.charset.Charset;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.olingo.commons.api.format.AcceptCharset;
 import org.apache.olingo.commons.api.format.AcceptType;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.http.HttpHeader;
@@ -87,6 +91,23 @@ public final class ContentNegotiator {
     final List<ContentType> supportedContentTypes =
         getSupportedContentTypes(customContentTypeSupport, representationType);
     final String acceptHeaderValue = request.getHeader(HttpHeader.ACCEPT);
+    String acceptCharset = request.getHeader(HttpHeader.ACCEPT_CHARSET);
+    List<AcceptCharset> charsets = null;
+    if (acceptCharset != null) {
+      try {
+        charsets = new ArrayList<AcceptCharset>();
+        charsets = AcceptCharset.create(acceptCharset); 
+      } catch (UnsupportedCharsetException e) {
+        throw new AcceptHeaderContentNegotiatorException(e.getMessage(),
+            AcceptHeaderContentNegotiatorException.MessageKeys.UNSUPPORTED_ACCEPT_CHARSET_HEADER_OPTIONS, 
+            e.getMessage().substring(e.getMessage().lastIndexOf(":") + 1));
+      } catch (IllegalArgumentException e) {
+        throw new ContentNegotiatorException(e.getMessage(),
+            ContentNegotiatorException.MessageKeys.UNSUPPORTED_ACCEPT_CHARSET, 
+            e.getMessage().substring(e.getMessage().lastIndexOf(":") + 1));
+      }
+    }
+      
     ContentType result = null;
 
     if (formatOption != null && formatOption.getFormat() != null) {
@@ -97,9 +118,11 @@ public final class ContentNegotiator {
         result = getAcceptedType(
             AcceptType.fromContentType(contentType == null ?
                 ContentType.create(formatOption.getFormat()) : contentType),
-                supportedContentTypes);
+                supportedContentTypes, charsets);
       } catch (final IllegalArgumentException e) {
-        // Exception results in result = null for next check.
+        throw new AcceptHeaderContentNegotiatorException(
+            "Unsupported $format=" + formatString,
+            AcceptHeaderContentNegotiatorException.MessageKeys.UNSUPPORTED_FORMAT_OPTION, formatString);
       }
       if (result == null) {
         throw new ContentNegotiatorException("Unsupported $format = " + formatString,
@@ -107,18 +130,25 @@ public final class ContentNegotiator {
       }
     } else if (acceptHeaderValue != null) {
       try {
-        result = getAcceptedType(AcceptType.create(acceptHeaderValue), supportedContentTypes);
+        result = getAcceptedType(AcceptType.create(acceptHeaderValue), 
+            supportedContentTypes, charsets);
       } catch (final IllegalArgumentException e) {
-        result = null;
-      }
+        throw new AcceptHeaderContentNegotiatorException(
+            "Unsupported or illegal Accept header value: " + acceptHeaderValue + " != " + supportedContentTypes,
+            AcceptHeaderContentNegotiatorException.MessageKeys.UNSUPPORTED_ACCEPT_TYPES, acceptHeaderValue);
+      } 
       if (result == null) {
+        List<AcceptType> types = AcceptType.create(acceptHeaderValue);
         throw new ContentNegotiatorException(
-            "Unsupported or illegal Accept header value: " + acceptHeaderValue + " != " + supportedContentTypes,
+            "The combination of type and subtype " + types.get(0) +
+            " != " + supportedContentTypes,
             ContentNegotiatorException.MessageKeys.UNSUPPORTED_ACCEPT_TYPES, acceptHeaderValue);
       }
     } else {
       final ContentType requestedContentType = getDefaultSupportedContentTypes(representationType).get(0);
-      result = getAcceptedType(AcceptType.fromContentType(requestedContentType), supportedContentTypes);
+      result = getAcceptedType(AcceptType.fromContentType(requestedContentType), 
+          supportedContentTypes, charsets);
+      
       if (result == null) {
         throw new ContentNegotiatorException(
             "unsupported accept content type: " + requestedContentType + " != " + supportedContentTypes,
@@ -145,16 +175,39 @@ public final class ContentNegotiator {
   }
 
   private static ContentType getAcceptedType(final List<AcceptType> acceptedContentTypes,
-      final List<ContentType> supportedContentTypes) {
+      final List<ContentType> supportedContentTypes, List<AcceptCharset> charsets) throws ContentNegotiatorException {
+    if (charsets != null) {
+      for (AcceptCharset charset : charsets) {
+        return getContentType(acceptedContentTypes, supportedContentTypes, charset);
+      }
+    } else {
+      return getContentType(acceptedContentTypes, supportedContentTypes, null);
+    }
+    return null;
+  }
+
+  private static ContentType getContentType(List<AcceptType> acceptedContentTypes,
+      List<ContentType> supportedContentTypes, AcceptCharset charset) throws ContentNegotiatorException {
     for (final AcceptType acceptedType : acceptedContentTypes) {
       for (final ContentType supportedContentType : supportedContentTypes) {
         ContentType contentType = supportedContentType;
         final String charSetValue = acceptedType.getParameter(ContentType.PARAMETER_CHARSET);
-        if (charSetValue != null) {
+        if (charset != null) {
+          contentType = ContentType.create(contentType, ContentType.PARAMETER_CHARSET, charset.toString());
+        } else if (charSetValue != null) {
+          try {
+            Charset.forName(charSetValue);
+          } catch (UnsupportedCharsetException e) {
+            throw new AcceptHeaderContentNegotiatorException(
+                "Illegal charset in Accept header: " + charSetValue,
+                AcceptHeaderContentNegotiatorException.MessageKeys.UNSUPPORTED_ACCEPT_CHARSET_HEADER_OPTIONS, 
+                charSetValue);
+          }
           if ("utf8".equalsIgnoreCase(charSetValue) || "utf-8".equalsIgnoreCase(charSetValue)) {
             contentType = ContentType.create(contentType, ContentType.PARAMETER_CHARSET, "utf-8");
           } else {
-            throw new IllegalArgumentException("charset not supported: " + acceptedType);
+            throw new ContentNegotiatorException("Unsupported accept-header-charset = " + charSetValue,
+                ContentNegotiatorException.MessageKeys.UNSUPPORTED_ACCEPT_HEADER_CHARSET, acceptedType.toString());
           }
         }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiatorException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiatorException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiatorException.java
index 12a0582..1b62d8f 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiatorException.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiatorException.java
@@ -31,7 +31,11 @@ public class ContentNegotiatorException extends ODataLibraryException {
     /** no parameter */
     NO_CONTENT_TYPE_SUPPORTED,
     /** parameter: format string */
-    UNSUPPORTED_FORMAT_OPTION;
+    UNSUPPORTED_FORMAT_OPTION,
+    /**parameter: accept charset */
+    UNSUPPORTED_ACCEPT_CHARSET,
+    /** parameter: accept header charset */
+    UNSUPPORTED_ACCEPT_HEADER_CHARSET;
 
     @Override
     public String getKey() {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/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 20c0634..1e0efb1 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
@@ -83,6 +83,13 @@ public class ODataExceptionHelper {
     return serverError;
   }
 
+  public static ODataServerError createServerErrorObject(final AcceptHeaderContentNegotiatorException e,
+      final Locale requestedLocale) {
+    ODataServerError serverError = basicTranslatedError(e, requestedLocale);
+    serverError.setStatusCode(HttpStatusCode.BAD_REQUEST.getStatusCode());
+    return serverError;
+  }
+  
   public static ODataServerError createServerErrorObject(final ODataHandlerException e, final Locale requestedLocale) {
     ODataServerError serverError = basicTranslatedError(e, requestedLocale);
     if (ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED.equals(e.getMessageKey())

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java
index 0bc59be..3c18e09 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java
@@ -95,6 +95,9 @@ public class ODataHandlerImpl implements ODataHandler {
     } catch (final UriParserException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
       handleException(request, response, serverError, e);
+    } catch (AcceptHeaderContentNegotiatorException e) {
+      ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
+      handleException(request, response, serverError, e);
     } catch (ContentNegotiatorException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
       handleException(request, response, serverError, e);
@@ -126,6 +129,7 @@ public class ODataHandlerImpl implements ODataHandler {
     final int measurementHandle = debugger.startRuntimeMeasurement("ODataHandler", "processInternal");
 
     response.setHeader(HttpHeader.ODATA_VERSION, ODataServiceVersion.V40.toString());
+    
     try {
       validateODataVersion(request);
     } catch (final ODataHandlerException e) {
@@ -180,6 +184,8 @@ public class ODataHandlerImpl implements ODataHandler {
       final FormatOption formatOption = getFormatOption(request, uriInfo);
       requestedContentType = ContentNegotiator.doContentNegotiation(formatOption, request,
           getCustomContentTypeSupport(), RepresentationType.ERROR);
+    } catch (final AcceptHeaderContentNegotiatorException e) {
+      requestedContentType = ContentType.JSON;
     } catch (final ContentNegotiatorException e) {
       requestedContentType = ContentType.JSON;
     }
@@ -221,11 +227,17 @@ public class ODataHandlerImpl implements ODataHandler {
   }
 
   private void validateODataVersion(final ODataRequest request) throws ODataHandlerException {
-    final String maxVersion = request.getHeader(HttpHeader.ODATA_MAX_VERSION);
-    if (maxVersion != null && ODataServiceVersion.isBiggerThan(ODataServiceVersion.V40.toString(), maxVersion)) {
-      throw new ODataHandlerException("ODataVersion not supported: " + maxVersion,
-          ODataHandlerException.MessageKeys.ODATA_VERSION_NOT_SUPPORTED, maxVersion);
+    final String odataVersion = request.getHeader(HttpHeader.ODATA_VERSION);
+   if (odataVersion != null && !ODataServiceVersion.isValidODataVersion(odataVersion)) {
+      throw new ODataHandlerException("ODataVersion not supported: " + odataVersion,
+          ODataHandlerException.MessageKeys.ODATA_VERSION_NOT_SUPPORTED, odataVersion);
     }
+    
+    final String maxVersion = request.getHeader(HttpHeader.ODATA_MAX_VERSION);
+    if (maxVersion != null && !ODataServiceVersion.isValidMaxODataVersion(maxVersion)) {
+        throw new ODataHandlerException("ODataVersion not supported: " + maxVersion,
+            ODataHandlerException.MessageKeys.ODATA_VERSION_NOT_SUPPORTED, maxVersion);
+      }
   }
 
   <T extends Processor> T selectProcessor(final Class<T> cls) throws ODataHandlerException {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/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 6eb9620..19ae702 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
@@ -103,6 +103,12 @@ ContentNegotiatorException.UNSUPPORTED_ACCEPT_TYPES=The content-type range '%1$s
 ContentNegotiatorException.UNSUPPORTED_CONTENT_TYPE=The content type '%1$s' is not supported.
 ContentNegotiatorException.NO_CONTENT_TYPE_SUPPORTED=No content type has been specified as supported.
 ContentNegotiatorException.UNSUPPORTED_FORMAT_OPTION=The $format option '%1$s' is not supported.
+ContentNegotiatorException.UNSUPPORTED_ACCEPT_CHARSET=The charset specified in Accept charset header '%1$s' is not supported.
+ContentNegotiatorException.UNSUPPORTED_ACCEPT_HEADER_CHARSET=The charset specified in Accept header '%1$s' is not supported.
+
+AcceptHeaderContentNegotiatorException.UNSUPPORTED_ACCEPT_TYPES=The content-type range '%1$s' is not supported as value of the Accept header.
+AcceptHeaderContentNegotiatorException.UNSUPPORTED_FORMAT_OPTION=The $format option '%1$s' is not supported.
+AcceptHeaderContentNegotiatorException.UNSUPPORTED_ACCEPT_CHARSET_HEADER_OPTIONS=The charset specified in Accept charset header '%1$s' is not supported.
 
 SerializerException.NULL_METADATA_OR_EDM=The server does not define any service metadata.
 SerializerException.NOT_IMPLEMENTED=The requested serialization method has not been implemented yet.

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java
index f863c70..46ec985 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java
@@ -18,9 +18,7 @@
  */
 package org.apache.olingo.server.core;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyListOf;
 import static org.mockito.Mockito.mock;
@@ -42,11 +40,15 @@ public class ContentNegotiatorTest {
 
   static final private String ACCEPT_CASE_MIN = ContentType.JSON.toContentTypeString();
   static final private String ACCEPT_CASE_MIN_UTF8 = "application/json;charset=UTF-8;odata.metadata=minimal";
+  static final private String ACCEPT_CASE_MIN_UTF81 = "application/json;charset=utf-8;odata.metadata=minimal";
+  static final private String ACCEPT_CASE_ISO_8859_1 = "application/json;charset=ISO-8859-1";
   static final private String ACCEPT_CASE_FULL = ContentType.JSON_FULL_METADATA.toContentTypeString();
   static final private String ACCEPT_CASE_NONE = ContentType.JSON_NO_METADATA.toContentTypeString();
   static final private String ACCEPT_CASE_MIN_UTF8_IEEE754 =
       "application/json;charset=UTF-8;odata.metadata=minimal;IEEE754Compatible=true";
   static final private String ACCEPT_CASE_MIN_IEEE754 = ACCEPT_CASE_MIN + ";IEEE754Compatible=true";
+  String ACCEPT_CASE_MIN_IEEE754_1 = ACCEPT_CASE_MIN + ";IEEE754Compatible=false";
+  static final private String ACCEPT_CASE_MIN_IEEE754_FAIL = ACCEPT_CASE_MIN + ";IEEE754Compatible=xyz";
   static final private String ACCEPT_CASE_JSONQ = "application/json;q=0.2";
   static final private String ACCEPT_CASE_XML = ContentType.APPLICATION_XML.toContentTypeString();
   static final private String ACCEPT_CASE_JSON = ContentType.APPLICATION_JSON.toContentTypeString();
@@ -79,7 +81,8 @@ public class ContentNegotiatorTest {
       { ACCEPT_CASE_MIN_UTF8_IEEE754, null,             ACCEPT_CASE_MIN_UTF8_IEEE754,   null                  },
       { ACCEPT_CASE_MIN_IEEE754,      ACCEPT_CASE_MIN_IEEE754, ACCEPT_CASE_MIN ,        null                  },
       { ACCEPT_CASE_XML,              "xml",            null,                           null                  },
-      { ACCEPT_CASE_XML,              null,             ACCEPT_CASE_XML,                null                  }
+      { ACCEPT_CASE_XML,              null,             ACCEPT_CASE_XML,                null                  },
+	  { ACCEPT_CASE_MIN_IEEE754_1,    null,             ACCEPT_CASE_MIN_IEEE754_1,      null                  }
   };
 
   String[][] casesMetadata = {
@@ -120,8 +123,31 @@ public class ContentNegotiatorTest {
       { null,                   null,             "*",                   null             },
       { null,                   "a/b;charset=ISO-8859-1", null,          "a/b"            },
       { null,                   null,             "a/b;charset=ISO-8859-1", "a/b"         },
-      { null,                   null,             null,                  "text/plain"     }
+      { null,                   null,             null,                  "text/plain"     },
+	  { null,                   "xxx",            null,                  null             },
+      { null,                   null,             ACCEPT_CASE_MIN_IEEE754_FAIL,null       }
   };
+  
+  String[][] casesAcceptCharset = {
+      /* expected               $format           accept                 modified content types  acceptCharset*/
+      { ACCEPT_CASE_MIN_UTF8,    null,             null,                  null,                    "utf-8"    },
+      { ACCEPT_CASE_MIN_UTF8,   "json",           ACCEPT_CASE_MIN_UTF8,   null,                    "utf-8"    },
+      { ACCEPT_CASE_MIN_UTF8,    null,            ACCEPT_CASE_ISO_8859_1, null,                    "utf-8"    },
+      { ACCEPT_CASE_MIN_UTF81,   null,            ACCEPT_CASE_ISO_8859_1, null,                    "utf-8"    },
+      { ACCEPT_CASE_MIN_UTF81,   null,           "application/json;charset=abc", null,             "utf-8"    },
+      { ACCEPT_CASE_MIN_UTF8,   null,            "application/json;charset=utf-8", null,              null    },
+      { ACCEPT_CASE_MIN_UTF8,   null,            "application/json;charset=utf8", null,              null    }
+  };
+  
+  String[][] casesAcceptCharsetFail = {
+      /* expected               $format           accept                 modified content types  acceptCharset*/
+      { null,                   null,             null,                   null,                    "ISO-8859-1"},
+      { null,                   "json",           ACCEPT_CASE_MIN_UTF8,   null,                    "abc"       },
+      { null,                   null,             ACCEPT_CASE_ISO_8859_1, null,                    "*"         },
+      { null,                   null,             ACCEPT_CASE_ISO_8859_1, null,                     null       },
+      { null,                   null,             "application/json;charset=abc", null,             null       }
+  };
+  
   //CHECKSTYLE:ON
   //@formatter:on
 
@@ -163,6 +189,8 @@ public class ContentNegotiatorTest {
       try {
         testContentNegotiation(useCase, RepresentationType.COLLECTION_ENTITY);
         fail("Exception expected for '" + useCase[1] + '|' + useCase[2] + '|' + useCase[3] + "'!");
+      } catch (final AcceptHeaderContentNegotiatorException e) {
+        // Expected Exception
       } catch (final ContentNegotiatorException e) {
         // Expected Exception
       }
@@ -207,7 +235,7 @@ public class ContentNegotiatorTest {
   }
 
   private void testContentNegotiation(final String[] useCase, final RepresentationType representationType)
-      throws ContentNegotiatorException {
+      throws Exception {
 
     FormatOption formatOption = null;
     if (useCase[1] != null) {
@@ -219,6 +247,12 @@ public class ContentNegotiatorTest {
     if (useCase[2] != null) {
       request.addHeader(HttpHeader.ACCEPT, Arrays.asList(useCase[2]));
     }
+	
+	if (useCase.length > 4) {
+      if (useCase[4] != null) {
+        request.addHeader(HttpHeader.ACCEPT_CHARSET, Arrays.asList(useCase[4]));
+      }
+    }
 
     final CustomContentTypeSupport customContentTypeSupport = useCase[3] == null ? null :
       createCustomContentTypeSupport(useCase[3]);
@@ -244,4 +278,37 @@ public class ContentNegotiatorTest {
         .thenReturn(types);
     return customContentTypeSupport;
   }
+  
+  @Test
+  public void testAcceptCharset() throws Exception {
+    for (String[] useCase : casesAcceptCharset) {
+      testContentNegotiation(useCase, RepresentationType.ENTITY);
+    }
+  }
+  
+  @Test
+  public void testAcceptCharsetFail() throws Exception {
+    for (String[] useCase : casesAcceptCharsetFail) {
+      try {
+        testContentNegotiation(useCase, RepresentationType.ENTITY);
+        fail("Exception expected for '" + useCase[1] + '|' + useCase[2] + '|' + useCase[3] + "'!");
+      } catch (final AcceptHeaderContentNegotiatorException e) {
+        // Expected Exception
+      } catch (final ContentNegotiatorException e) {
+        // Expected Exception
+      }
+    }
+  }
+  
+  @Test
+  public void testSupportedTypes() throws ContentNegotiatorException, IllegalArgumentException {
+    assertTrue(ContentNegotiator.isSupported(ContentType.create("a/b"), 
+        createCustomContentTypeSupport("a/b"), RepresentationType.ENTITY));
+    assertFalse(ContentNegotiator.isSupported(ContentType.create("a/b"), 
+        createCustomContentTypeSupport("x/y"), RepresentationType.ENTITY));
+    assertTrue(ContentNegotiator.isSupported(ContentType.create("a/b"), 
+        createCustomContentTypeSupport("a/b"), RepresentationType.BATCH));
+    assertTrue(ContentNegotiator.isSupported(ContentType.create("a/b"), 
+        createCustomContentTypeSupport("a/b"), RepresentationType.BINARY));
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eb112032/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java
index bacb700..8e457b1 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
@@ -33,7 +34,10 @@ import static org.mockito.Mockito.verifyZeroInteractions;
 import java.io.InputStream;
 import java.nio.charset.Charset;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
@@ -1138,4 +1142,173 @@ public class ODataHandlerImplTest {
     assertEquals(statusCode.getStatusCode(), response.getStatusCode());
     assertNotNull(response.getContent());
   }
+  
+  @Test
+  public void validateInvalidOdataVersion1() throws Exception {
+    final String uri = "ESAllPrim(0)";
+    final EntityProcessor processor = mock(EntityProcessor.class);
+
+    final Map<String, String> header = new HashMap<String, String>();
+    header.put(HttpHeader.ODATA_VERSION, "3.0");
+    final ODataResponse response = dispatchToValidateHeaders
+        (HttpMethod.GET, uri, null, header, processor);
+    assertEquals("4.0", response.getHeader(HttpHeader.ODATA_VERSION));
+    assertEquals(400, response.getStatusCode());
+    assertNotNull(response.getContent());
+    String doc = IOUtils.toString(response.getContent());
+    assertTrue(doc.contains("OData version '3.0' is not supported."));
+  }
+  
+  @Test
+  public void validateInvalidOdataVersion2() throws Exception {
+    final String uri = "ESAllPrim(0)";
+    final EntityProcessor processor = mock(EntityProcessor.class);
+
+    final Map<String, String> header = new HashMap<String, String>();
+    header.put(HttpHeader.ODATA_VERSION, "5.0");
+    
+    final ODataResponse response = dispatchToValidateHeaders
+        (HttpMethod.GET, uri, null, header, processor);
+    assertEquals("4.0", response.getHeader(HttpHeader.ODATA_VERSION));
+    assertEquals(400, response.getStatusCode());
+    assertNotNull(response.getContent());
+    String doc = IOUtils.toString(response.getContent());
+    assertTrue(doc.contains("OData version '5.0' is not supported."));
+  }
+  
+  @Test
+  public void validateInvalidOdataMaxVersion1() throws Exception {
+    final String uri = "ESAllPrim(0)";
+    final EntityProcessor processor = mock(EntityProcessor.class);
+
+    final Map<String, String> header = new HashMap<String, String>();
+    header.put(HttpHeader.ODATA_MAX_VERSION, "3.0");
+    
+    final ODataResponse response = dispatchToValidateHeaders
+        (HttpMethod.GET, uri, null, header, processor);
+    assertEquals("4.0", response.getHeader(HttpHeader.ODATA_VERSION));
+    assertEquals(400, response.getStatusCode());
+    assertNotNull(response.getContent());
+    String doc = IOUtils.toString(response.getContent());
+    assertTrue(doc.contains("OData version '3.0' is not supported."));
+  }
+  
+  @Test
+  public void validateValidOdataMaxVersion2() throws Exception {
+    final String uri = "ESAllPrim(0)";
+    final EntityProcessor processor = mock(EntityProcessor.class);
+
+    final Map<String, String> header = new HashMap<String, String>();
+    header.put(HttpHeader.ODATA_MAX_VERSION, "5.0");
+    
+    final ODataResponse response = dispatchToValidateHeaders
+        (HttpMethod.GET, uri, null, header, processor);
+    assertEquals("4.0", response.getHeader(HttpHeader.ODATA_VERSION));
+  }
+  
+  @Test
+  public void validateValidOdataVersionAndMaxVersion1() throws Exception {
+    final String uri = "ESAllPrim(0)";
+    final EntityProcessor processor = mock(EntityProcessor.class);
+
+    final Map<String, String> headers = new HashMap<String, String>();
+    headers.put(HttpHeader.ODATA_VERSION, "4.0");
+    headers.put(HttpHeader.ODATA_MAX_VERSION, "5.0");
+    
+    final ODataResponse response = dispatchToValidateHeaders
+        (HttpMethod.GET, uri, null, headers, processor);
+    assertEquals("4.0", response.getHeader(HttpHeader.ODATA_VERSION));
+  }
+  
+  @Test
+  public void validateInvalidOdataVersionAndMaxVersion2() throws Exception {
+    final String uri = "ESAllPrim(0)";
+    final EntityProcessor processor = mock(EntityProcessor.class);
+
+    final Map<String, String> headers = new HashMap<String, String>();
+    headers.put(HttpHeader.ODATA_VERSION, "3.0");
+    headers.put(HttpHeader.ODATA_MAX_VERSION, "4.0");
+    
+    final ODataResponse response = dispatchToValidateHeaders
+        (HttpMethod.GET, uri, null, headers, processor);
+    assertEquals("4.0", response.getHeader(HttpHeader.ODATA_VERSION));
+    assertEquals(400, response.getStatusCode());
+    assertNotNull(response.getContent());
+    String doc = IOUtils.toString(response.getContent());
+    assertTrue(doc.contains("OData version '3.0' is not supported."));
+  }
+  
+  @Test
+  public void validateInvalidOdataVersionAndMaxVersion3() throws Exception {
+    final String uri = "ESAllPrim(0)";
+    final EntityProcessor processor = mock(EntityProcessor.class);
+
+    final Map<String, String> headers = new HashMap<String, String>();
+    headers.put(HttpHeader.ODATA_VERSION, "5.0");
+    headers.put(HttpHeader.ODATA_MAX_VERSION, "5.0");
+    
+    final ODataResponse response = dispatchToValidateHeaders
+        (HttpMethod.GET, uri, null, headers, processor);
+    assertEquals("4.0", response.getHeader(HttpHeader.ODATA_VERSION));
+    assertEquals(400, response.getStatusCode());
+    assertNotNull(response.getContent());
+    String doc = IOUtils.toString(response.getContent());
+    assertTrue(doc.contains("OData version '5.0' is not supported."));
+  }
+  
+  @Test
+  public void validateValidOdataVersionAndMaxVersion2() throws Exception {
+    final String uri = "ESAllPrim(0)";
+    final EntityProcessor processor = mock(EntityProcessor.class);
+
+    final Map<String, String> headers = new HashMap<String, String>();
+    headers.put(HttpHeader.ODATA_VERSION, "4.0");
+    headers.put(HttpHeader.ODATA_MAX_VERSION, "4.01");
+    
+    final ODataResponse response = dispatchToValidateHeaders
+        (HttpMethod.GET, uri, null, headers, processor);
+    assertEquals("4.0", response.getHeader(HttpHeader.ODATA_VERSION));
+  }
+  
+  @Test
+  public void validateValidOdataVersionAndMaxVersion3() throws Exception {
+    final String uri = "ESAllPrim(0)";
+    final EntityProcessor processor = mock(EntityProcessor.class);
+
+    final Map<String, String> headers = new HashMap<String, String>();
+    headers.put(HttpHeader.ODATA_VERSION, "4.0");
+    headers.put(HttpHeader.ODATA_MAX_VERSION, "4.0");
+    
+    final ODataResponse response = dispatchToValidateHeaders
+        (HttpMethod.GET, uri, null, headers, processor);
+    assertEquals("4.0", response.getHeader(HttpHeader.ODATA_VERSION));
+  }
+  
+  private ODataResponse dispatchToValidateHeaders(final HttpMethod method, final String path, final String query,
+      final Map<String, String> headers, final Processor processor) throws ODataHandlerException {
+    ODataRequest request = new ODataRequest();
+    request.setMethod(method);
+    request.setRawBaseUri(BASE_URI);
+    for (Entry<String, String> header : headers.entrySet()) {
+      request.addHeader(header.getKey(), header.getValue());
+    }
+    if (path.isEmpty()) {
+      request.setRawRequestUri(BASE_URI);
+    }
+    request.setRawODataPath(path);
+    request.setRawQueryPath(query);
+
+    final OData odata = OData.newInstance();
+    final ServiceMetadata metadata = odata.createServiceMetadata(
+        new EdmTechProvider(), Collections.<EdmxReference> emptyList());
+
+    ODataHandlerImpl handler = new ODataHandlerImpl(odata, metadata, new ServerCoreDebugger(odata));
+
+    if (processor != null) {
+      handler.register(processor);
+    }
+
+    final ODataResponse response = handler.process(request);
+    return response;
+  }
 }