diff --git a/lib/server-api/pom.xml b/lib/server-api/pom.xml
index 3d8fa8788..6af6456be 100644
--- a/lib/server-api/pom.xml
+++ b/lib/server-api/pom.xml
@@ -46,6 +46,11 @@
2.5
provided
+
+
+ junit
+ junit
+
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java
index e9d9caa7d..8372f8036 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java
@@ -18,8 +18,6 @@
*/
package org.apache.olingo.server.api;
-import java.util.List;
-
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataRequest.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataRequest.java
index 5be8b96d7..45cf503f7 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataRequest.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataRequest.java
@@ -54,7 +54,7 @@ public class ODataRequest {
String key = name.toUpperCase();
if (headers.containsKey(key)) {
List oldValues = headers.get(key);
-
+
List newValues = new ArrayList();
newValues.addAll(oldValues);
newValues.addAll(values);
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/SupportCustomContentTypes.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/CustomContentTypeSupport.java
similarity index 80%
rename from lib/server-api/src/main/java/org/apache/olingo/server/api/processor/SupportCustomContentTypes.java
rename to lib/server-api/src/main/java/org/apache/olingo/server/api/processor/CustomContentTypeSupport.java
index 0a032e102..75a57b101 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/SupportCustomContentTypes.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/CustomContentTypeSupport.java
@@ -20,8 +20,9 @@ package org.apache.olingo.server.api.processor;
import java.util.List;
-public interface SupportCustomContentTypes {
+public interface CustomContentTypeSupport {
+
+ public List modifySupportedContentTypes(
+ List supportedContentTypes, Class extends Processor> processorClass);
- public List getSupportedContentTypes(Class extends Processor> processorClass);
-
}
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
index 4d1a94d25..3ce2570b7 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
@@ -19,8 +19,6 @@
package org.apache.olingo.server.api.processor;
import java.io.InputStream;
-import java.util.Collections;
-import java.util.List;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.format.ODataFormat;
@@ -33,7 +31,7 @@ import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.uri.UriInfo;
public class DefaultProcessor implements MetadataProcessor, ServiceDocumentProcessor {
-
+
private OData odata;
private Edm edm;
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/FormatContentTypeMapping.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/FormatContentTypeMapping.java
new file mode 100644
index 000000000..2fe69b60c
--- /dev/null
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/FormatContentTypeMapping.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.api.processor;
+
+public class FormatContentTypeMapping {
+
+ private String formatAlias;
+ private String contentType;
+
+ public FormatContentTypeMapping(String formatAlias, String contentType) {
+ super();
+ this.formatAlias = formatAlias;
+ this.contentType = contentType;
+ }
+
+ public String getFormatAlias() {
+ return formatAlias;
+ }
+
+ public String getContentType() {
+ return contentType;
+ }
+
+ public void setFormatAlias(String formatAlias) {
+ this.formatAlias = formatAlias;
+ }
+
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ @Override
+ public String toString() {
+ return "('" + formatAlias + "', '" + contentType + "')";
+ }
+
+}
\ No newline at end of file
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/MetadataProcessor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/MetadataProcessor.java
index 64d5c1667..89f8e5303 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/MetadataProcessor.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/MetadataProcessor.java
@@ -22,7 +22,7 @@ import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.uri.UriInfo;
-public interface MetadataProcessor extends Processor{
+public interface MetadataProcessor extends Processor {
void readMetadata(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format);
}
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/Processor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/Processor.java
index ef2b8a09c..014fba7cc 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/Processor.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/Processor.java
@@ -18,8 +18,6 @@
*/
package org.apache.olingo.server.api.processor;
-import java.util.List;
-
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.server.api.OData;
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/api/ODataRequestTest.java b/lib/server-api/src/test/java/org/apache/olingo/server/api/ODataRequestTest.java
similarity index 100%
rename from lib/server-test/src/test/java/org/apache/olingo/server/api/ODataRequestTest.java
rename to lib/server-api/src/test/java/org/apache/olingo/server/api/ODataRequestTest.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
new file mode 100644
index 000000000..baf6d7b0c
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.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.server.core;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.http.HttpContentType;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.processor.CustomContentTypeSupport;
+import org.apache.olingo.server.api.processor.FormatContentTypeMapping;
+import org.apache.olingo.server.api.processor.MetadataProcessor;
+import org.apache.olingo.server.api.processor.Processor;
+import org.apache.olingo.server.api.uri.queryoption.FormatOption;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ContentNegotiator {
+
+ private final static Logger LOG = LoggerFactory.getLogger(ContentNegotiator.class);
+
+ private List getDefaultSupportedContentTypes(Class extends Processor> processorClass) {
+ List defaults = new ArrayList();
+
+ if (processorClass == MetadataProcessor.class) {
+ defaults.add(new FormatContentTypeMapping("xml", ContentType.APPLICATION_XML.toContentTypeString()));
+ }
+ else {
+ defaults.add(new FormatContentTypeMapping("json", ContentType.APPLICATION_JSON.toContentTypeString()));
+ }
+
+ return defaults;
+ }
+
+ public List getSupportedContentTypes(Processor processor,
+ Class extends Processor> processorClass) {
+
+ List supportedContentTypes = getDefaultSupportedContentTypes(processorClass);
+
+ if (processor instanceof CustomContentTypeSupport) {
+ supportedContentTypes =
+ ((CustomContentTypeSupport) processor).modifySupportedContentTypes(supportedContentTypes, processorClass);
+ }
+
+ return supportedContentTypes;
+ }
+
+ public String doContentNegotiation(FormatOption formatOption, ODataRequest request,
+ List supportedContentTypes) {
+ String requestedContentType = null;
+
+ List acceptHeaderValues = request.getHeader(HttpHeader.ACCEPT);
+
+ boolean supported = false;
+
+ if (formatOption != null) {
+
+ if ("json".equalsIgnoreCase(formatOption.getText())) {
+ requestedContentType = HttpContentType.APPLICATION_JSON;
+ for (FormatContentTypeMapping entry : supportedContentTypes) {
+ if (requestedContentType.equalsIgnoreCase(entry.getContentType())){
+ supported = true;
+ break;
+ }
+ }
+ } else {
+ requestedContentType = formatOption.getText();
+ for (FormatContentTypeMapping entry : supportedContentTypes) {
+ if (requestedContentType.equalsIgnoreCase(entry.getFormatAlias())){
+ supported = true;
+ break;
+ }
+ }
+ }
+ } else if (acceptHeaderValues != null) {
+ List acceptedContentTypes = new ArrayList();
+
+// for (String acceptHeaderValue : acceptHeaderValues) {
+// acceptedContentTypes.addAll(parseAcceptHeader(acceptHeaderValue));
+// }
+
+ for (String acceptedContentType : acceptedContentTypes) {
+// if (isContentTypeSupported(acceptedContentType, supportedContentTypes)) {
+// requestedContentType = acceptedContentType;
+// }
+ }
+
+ if (requestedContentType == null) {
+ throw new RuntimeException("unsupported accept content type: " + acceptedContentTypes + " != "
+ + supportedContentTypes);
+ }
+
+ requestedContentType = null;
+ } else {
+ requestedContentType = HttpContentType.APPLICATION_JSON;
+ for (FormatContentTypeMapping entry : supportedContentTypes) {
+ if (requestedContentType.equalsIgnoreCase(entry.getContentType())){
+ supported = true;
+ break;
+ }
+ }
+ }
+
+ if (!supported) {
+ throw new RuntimeException("unsupported accept content type: " + requestedContentType + " != "
+ + supportedContentTypes);
+ }
+
+ LOG.debug("requested content type: " + requestedContentType);
+
+ return requestedContentType;
+ }
+}
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
index f7248c392..28bc559fc 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
@@ -18,6 +18,10 @@
*/
package org.apache.olingo.server.core;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -25,6 +29,8 @@ import java.util.Map;
import org.apache.olingo.commons.api.ODataRuntimeException;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import org.apache.olingo.commons.api.format.AcceptType;
+import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpMethod;
@@ -32,20 +38,27 @@ import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.processor.CollectionProcessor;
+import org.apache.olingo.server.api.processor.FormatContentTypeMapping;
import org.apache.olingo.server.api.processor.DefaultProcessor;
import org.apache.olingo.server.api.processor.EntityProcessor;
import org.apache.olingo.server.api.processor.MetadataProcessor;
import org.apache.olingo.server.api.processor.Processor;
import org.apache.olingo.server.api.processor.ServiceDocumentProcessor;
+import org.apache.olingo.server.api.processor.CustomContentTypeSupport;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceNavigation;
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
+import org.apache.olingo.server.api.uri.queryoption.FormatOption;
import org.apache.olingo.server.core.uri.parser.Parser;
import org.apache.olingo.server.core.uri.validator.UriValidator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class ODataHandler {
+ private final static Logger LOG = LoggerFactory.getLogger(ODataHandler.class);
+
private final OData odata;
private final Edm edm;
private Map, Processor> processors = new HashMap, Processor>();
@@ -72,12 +85,17 @@ public class ODataHandler {
UriValidator validator = new UriValidator();
validator.validate(uriInfo, request.getMethod());
- String requestedContentType = doContentNegotiation();
+ String requestedContentType = null;
+ List supportedContentTypes = null;
switch (uriInfo.getKind()) {
case metadata:
MetadataProcessor mp = selectProcessor(MetadataProcessor.class);
- mp.readMetadata(request, response, uriInfo, HttpContentType.APPLICATION_XML);
+
+ /* TODO content negotiation */
+ requestedContentType = ContentType.APPLICATION_XML.toContentTypeString();
+
+ mp.readMetadata(request, response, uriInfo, requestedContentType);
break;
case service:
if ("".equals(request.getRawODataPath())) {
@@ -85,11 +103,15 @@ public class ODataHandler {
rdp.redirect(request, response);
} else {
ServiceDocumentProcessor sdp = selectProcessor(ServiceDocumentProcessor.class);
+
+ /* TODO content negotiation */
+ requestedContentType = ContentType.APPLICATION_JSON.toContentTypeString();
+
sdp.readServiceDocument(request, response, uriInfo, requestedContentType);
}
break;
case resource:
- handleResourceDispatching(request, response, uriInfo, requestedContentType);
+ handleResourceDispatching(request, response, uriInfo);
break;
default:
throw new ODataRuntimeException("not implemented");
@@ -102,27 +124,32 @@ public class ODataHandler {
}
}
- private String doContentNegotiation() {
- // TODO: Content Negotiation
- return HttpContentType.APPLICATION_JSON;
- }
-
- private void handleResourceDispatching(final ODataRequest request, ODataResponse response, UriInfo uriInfo,
- String requestedContentType) {
+ private void handleResourceDispatching(final ODataRequest request, ODataResponse response, UriInfo uriInfo) {
int lastPathSegmentIndex = uriInfo.getUriResourceParts().size() - 1;
UriResource lastPathSegment = uriInfo.getUriResourceParts().get(lastPathSegmentIndex);
+ String requestedContentType = null;
+ List supportedContentTypes = null;
+
switch (lastPathSegment.getKind()) {
case entitySet:
if (((UriResourcePartTyped) lastPathSegment).isCollection()) {
if (request.getMethod().equals(HttpMethod.GET)) {
- CollectionProcessor esp = selectProcessor(CollectionProcessor.class);
- esp.readCollection(request, response, uriInfo, requestedContentType);
+ CollectionProcessor cp = selectProcessor(CollectionProcessor.class);
+
+ /* TODO content negotiation */
+ requestedContentType = ContentType.APPLICATION_JSON.toContentTypeString();
+
+ cp.readCollection(request, response, uriInfo, requestedContentType);
} else {
throw new ODataRuntimeException("not implemented");
}
} else {
if (request.getMethod().equals(HttpMethod.GET)) {
EntityProcessor ep = selectProcessor(EntityProcessor.class);
+
+ /* TODO content negotiation */
+ requestedContentType = ContentType.APPLICATION_JSON.toContentTypeString();
+
ep.readEntity(request, response, uriInfo, requestedContentType);
} else {
throw new ODataRuntimeException("not implemented");
@@ -132,14 +159,22 @@ public class ODataHandler {
case navigationProperty:
if (((UriResourceNavigation) lastPathSegment).isCollection()) {
if (request.getMethod().equals(HttpMethod.GET)) {
- CollectionProcessor esp = selectProcessor(CollectionProcessor.class);
- esp.readCollection(request, response, uriInfo, requestedContentType);
+ CollectionProcessor cp = selectProcessor(CollectionProcessor.class);
+
+ /* TODO content negotiation */
+ requestedContentType = ContentType.APPLICATION_JSON.toContentTypeString();
+
+ cp.readCollection(request, response, uriInfo, requestedContentType);
} else {
throw new ODataRuntimeException("not implemented");
}
} else {
if (request.getMethod().equals(HttpMethod.GET)) {
EntityProcessor ep = selectProcessor(EntityProcessor.class);
+
+ /* TODO content negotiation */
+ requestedContentType = ContentType.APPLICATION_JSON.toContentTypeString();
+
ep.readEntity(request, response, uriInfo, requestedContentType);
} else {
throw new ODataRuntimeException("not implemented");
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
index 36ef5c59d..1b15995a1 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
@@ -182,7 +182,7 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
odRequest.setRawServiceResolutionUri(rawServiceResolutionUri);
}
- private void extractHeaders(ODataRequest odRequest, final HttpServletRequest req) {
+ static void extractHeaders(ODataRequest odRequest, final HttpServletRequest req) {
for (Enumeration> headerNames = req.getHeaderNames(); headerNames.hasMoreElements();) {
String headerName = (String) headerNames.nextElement();
List headerValues = new ArrayList();
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
new file mode 100644
index 000000000..ba5802bdc
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java
@@ -0,0 +1,327 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core;
+
+import static org.mockito.Mockito.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpMethod;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.processor.CollectionProcessor;
+import org.apache.olingo.server.api.processor.CustomContentTypeSupport;
+import org.apache.olingo.server.api.processor.FormatContentTypeMapping;
+import org.apache.olingo.server.api.processor.MetadataProcessor;
+import org.apache.olingo.server.api.processor.Processor;
+import org.apache.olingo.server.api.processor.ServiceDocumentProcessor;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.queryoption.FormatOption;
+import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ContentNegotiatorTest {
+
+ static final private String ACCEPT_CASE_JSON = "application/json;odata=verbose;q=0.2";
+ static final private String ACCEPT_CASE_XML = "application/xml";
+ static final private String ACCEPT_CASE_TEXT = "text/plain;q=0.5";
+ static final private String ACCEPT_CASE_MULTI = "text/plain;q=0.5,application/aaa;q=0.4";
+
+ //@formatter:off (Eclipse formatter)
+ //CHECKSTYLE:OFF (Maven checkstyle)
+
+ String[][] casesServiceDocument = {
+ /* expected $format accept alias ct mapping */
+ { "application/json", null, null, null ,null },
+ { "application/json", "json", null, null ,null },
+ { "application/json", "json", "application/json", null ,null },
+ { "a", "a", null, "a" ,"a/a" },
+
+// { "application/json", null, "application/json", null ,null },
+// { "application/json", null, ACCEPT_CASE_JSON, null ,null },
+// { "application/json", null, "*/*", null ,null },
+// { "a/a", "a", null, "a, b" ,"a/a,b/b" },
+// { "a", null, "*/*", "a, b" ,null },
+// { "a", "a", "*/*", "a, b" ,null },
+ };
+
+ String[][] casesMetadata = {
+ /* expected $format accept alias ct mapping */
+ { "application/xml", null, null, null ,null },
+ { "application/xml", "xml", null, null ,null },
+ { "application/xml", null, "application/xml", null ,null },
+ { "application/xml", "xml", "application/xml", null ,null },
+ { "application/xml", null, ACCEPT_CASE_XML, null ,null },
+ { "application/xml", null, "*/*", null ,null },
+ { "a", "a", null, "a, b" ,null },
+ { "a", "a", null, "a, b" ,null },
+ { "a", null, "*/*", "a, b" ,null },
+ { "a", "a", "*/*", "a, b" ,null },
+ };
+
+// String[][] casesEntitySet = {
+// /* expected $format accept supported $formatmapping */
+// { "application/json", null, null, null ,null },
+// { "application/json", "json", null, null ,null },
+// { "application/json", "json", "application/json", null ,null },
+// { "application/json", null, "application/json", null ,null },
+// { "application/json", null, ACCEPT_CASE_JSON, null ,null },
+// { "application/json", null, "*/*", null ,null },
+// { "a", "a", null, "a, b" ,null },
+// { "a", null, "*/*", "a, b" ,null },
+// { "a", "a", "*/*", "a, b" ,null },
+// };
+ //CHECKSTYLE:ON
+ //@formatter:on
+
+ private final static Logger LOG = LoggerFactory.getLogger(ContentNegotiatorTest.class);
+
+ @Test
+ public void testServiceDocumentSingleCase() {
+ String[] useCase = { "application/json", null, null, null, null };
+
+ testContentNegotiation(useCase, ServiceDocumentProcessor.class);
+ }
+
+ @Test
+ public void testServiceDocumentDefault() {
+ for (String[] useCase : casesServiceDocument) {
+ testContentNegotiation(useCase, ServiceDocumentProcessor.class);
+ }
+ }
+
+ public void testContentNegotiation(String[] useCase, Class processorClass) {
+
+ LOG.debug(Arrays.asList(useCase).toString());
+
+ ODataRequest request = new ODataRequest();
+ request.setMethod(HttpMethod.GET);
+ request.setRawODataPath("/" + (useCase[1] == null ? "" : "?$format=" + useCase[1]));
+
+ ContentNegotiator cn = new ContentNegotiator();
+
+ ProcessorStub p = new ProcessorStub(createCustomContentTypeMapping(useCase[3], useCase[4]));
+
+ List supportedContentTypes =
+ cn.getSupportedContentTypes(p, processorClass);
+
+ FormatOption fo = null;
+ if (useCase[1] != null) {
+ fo = mock(FormatOption.class);
+ when(fo.getText()).thenReturn(useCase[1]);
+ }
+
+ String requestedContentType = cn.doContentNegotiation(fo, request, supportedContentTypes);
+
+ assertNotNull(requestedContentType);
+ assertEquals(useCase[0], requestedContentType);
+ }
+
+ private List createCustomContentTypeMapping(String formatString, String contentTypeString) {
+ List map = null;
+
+ assertTrue(!(formatString == null ^ contentTypeString == null));
+
+ if (formatString != null) {
+ String[] formats = formatString.split(",");
+ String[] contentTypes = contentTypeString.split(",");
+
+ assertEquals(formats.length, contentTypes.length);
+
+ map = new ArrayList();
+ for (int i = 0; i < formats.length; i++) {
+ map.add(new FormatContentTypeMapping(formats[i], contentTypes[i]));
+ }
+ }
+
+ return map;
+ }
+
+ @Test
+ @Ignore
+ public void testMetadataDefault() {
+
+ for (String[] useCase : casesMetadata) {
+ ODataRequest request = new ODataRequest();
+ request.setMethod(HttpMethod.GET);
+ request.setRawODataPath("/$metadata" + (useCase[1] == null ? "" : "?$format=" + useCase[1]));
+
+// ODataResponse response = callHandler(useCase, request);
+//
+// assertEquals(useCase[0], response.getHeaders().get(HttpHeader.CONTENT_TYPE));
+ }
+ }
+
+// @Test
+// public void testEntitySet() {
+//
+// for (String[] useCase : casesEntitySet) {
+// ODataRequest request = new ODataRequest();
+// request.setMethod(HttpMethod.GET);
+// request.setRawODataPath("/ESAllPrim" + (useCase[1] == null ? "" : "?$format=" + useCase[1]));
+//
+// ODataResponse response = callHandler(useCase, request, new CollectionProcessorStub());
+//
+// assertEquals(useCase[0], response.getHeaders().get(HttpHeader.CONTENT_TYPE));
+// }
+// }
+
+// private ODataResponse callHandler(String[] useCase, ODataRequest request,
+// Processor defaultProcessor) {
+// ODataHandler handler = createHandler();
+//
+// if (useCase[2] != null) {
+// request.addHeader(HttpHeader.ACCEPT, Arrays.asList(useCase[2]));
+// }
+//
+// if (useCase[3] != null) {
+// String[] aliase = useCase[3].split(",");
+// String[] mappings = useCase[4].split(",");
+//
+// FormatContentTypeMapping[] formatCTMap = new FormatContentTypeMapping[aliase.length];
+//
+// for(int i=0; i< formatCTMap.length; i++) {
+// formatCTMap[i] = new FormatContentTypeMapping(aliase[i], mappings[i]);
+// }
+//
+//
+// ProcessorStub stub = new ProcessorStub(formatCTMap);
+// handler.register(stub);
+// } else {
+// if (defaultProcessor != null) {
+// handler.register(defaultProcessor);
+// }
+// }
+//
+// ODataResponse response = handler.process(request);
+// return response;
+// }
+
+// ODataResponse callHandler(String[] useCase, ODataRequest request) {
+// return callHandler(useCase, request, null);
+// }
+
+ private class CollectionProcessorStub implements CollectionProcessor {
+
+ @Override
+ public void init(OData odata, Edm edm) {}
+
+ @Override
+ public void readCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
+ response.setHeader(HttpHeader.CONTENT_TYPE, format);
+ }
+ }
+
+ @Test
+ public void testDefaultSupportedContentTypesServiceDocument() {
+ ContentNegotiator cn = new ContentNegotiator();
+
+ ProcessorStub p = new ProcessorStub(null);
+
+ List supportedContentTypes =
+ cn.getSupportedContentTypes(p, ServiceDocumentProcessor.class);
+
+ assertNotNull(supportedContentTypes);
+ assertEquals(1, supportedContentTypes.size());
+ assertEquals("json", supportedContentTypes.get(0).getFormatAlias());
+ assertEquals("application/json", supportedContentTypes.get(0).getContentType());
+ }
+
+ @Test
+ public void testDefaultSupportedContentTypesMetadata() {
+ ContentNegotiator cn = new ContentNegotiator();
+
+ ProcessorStub p = new ProcessorStub(null);
+
+ List supportedContentTypes = cn.getSupportedContentTypes(p, MetadataProcessor.class);
+
+ assertNotNull(supportedContentTypes);
+ assertEquals(1, supportedContentTypes.size());
+ assertEquals("xml", supportedContentTypes.get(0).getFormatAlias());
+ assertEquals("application/xml", supportedContentTypes.get(0).getContentType());
+ }
+
+ @Test
+ public void testCustomSupportedContentTypesServiceDocument() {
+ ContentNegotiator cn = new ContentNegotiator();
+
+ ProcessorStub p = new ProcessorStub(Arrays.asList(new FormatContentTypeMapping("a", "a/a")));
+
+ List supportedContentTypes =
+ cn.getSupportedContentTypes(p, ServiceDocumentProcessor.class);
+
+ assertNotNull(supportedContentTypes);
+ assertEquals(2, supportedContentTypes.size());
+ assertEquals("json", supportedContentTypes.get(0).getFormatAlias());
+ assertEquals("application/json", supportedContentTypes.get(0).getContentType());
+ assertEquals("a", supportedContentTypes.get(1).getFormatAlias());
+ assertEquals("a/a", supportedContentTypes.get(1).getContentType());
+ }
+
+ private class ProcessorStub implements ServiceDocumentProcessor, MetadataProcessor,
+ CollectionProcessor,
+ CustomContentTypeSupport {
+
+ List customMapping;
+
+ ProcessorStub(List mapping) {
+ this.customMapping = mapping;
+ }
+
+ @Override
+ public void init(OData odata, Edm edm) {}
+
+ @Override
+ public List modifySupportedContentTypes(
+ List supportedContentTypes,
+ Class extends Processor> processorClass) {
+ if (customMapping != null) {
+ supportedContentTypes.addAll(customMapping);
+ }
+ return supportedContentTypes;
+ }
+
+ @Override
+ public void readServiceDocument(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
+ response.setHeader(HttpHeader.CONTENT_TYPE, format);
+ }
+
+ @Override
+ public void readCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
+ response.setHeader(HttpHeader.CONTENT_TYPE, format);
+ }
+
+ @Override
+ public void readMetadata(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
+ response.setHeader(HttpHeader.CONTENT_TYPE, format);
+ }
+
+ }
+}
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataHttpHandlerImplTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataHttpHandlerImplTest.java
index faa82e321..371507643 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataHttpHandlerImplTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataHttpHandlerImplTest.java
@@ -23,6 +23,8 @@ import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import java.util.Arrays;
+
import javax.servlet.http.HttpServletRequest;
import org.apache.olingo.commons.api.ODataRuntimeException;
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/ContentNegotiationTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/ContentNegotiationTest.java
deleted file mode 100644
index db5b9847a..000000000
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/ContentNegotiationTest.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.olingo.server.core;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.*;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.withSettings;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.olingo.commons.api.edm.Edm;
-import org.apache.olingo.commons.api.http.HttpHeader;
-import org.apache.olingo.commons.api.http.HttpMethod;
-import org.apache.olingo.server.api.OData;
-import org.apache.olingo.server.api.ODataRequest;
-import org.apache.olingo.server.api.ODataResponse;
-import org.apache.olingo.server.api.processor.CollectionProcessor;
-import org.apache.olingo.server.api.processor.MetadataProcessor;
-import org.apache.olingo.server.api.processor.Processor;
-import org.apache.olingo.server.api.processor.ServiceDocumentProcessor;
-import org.apache.olingo.server.api.processor.SupportCustomContentTypes;
-import org.apache.olingo.server.api.uri.UriInfo;
-import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
-import org.junit.Ignore;
-import org.junit.Test;
-
-public class ContentNegotiationTest {
-
-// static final private String ACCEPT_CASE1 = "text/plain;q=0.5";
-// static final private String ACCEPT_CASE2 = "application/json;odata=verbose;q=0.2";
-
- //@formatter:off (Eclipse formatter)
- //CHECKSTYLE:OFF (Maven checkstyle)
-
- String[][] casesServiceDocument = {
- /* expected $format accept supported */
- { "application/json", null, null, null },
- { "application/json", "json", null, null },
- { "application/json", "json", "application/json", null },
- { "application/json", null, "application/json", null },
- { "application/json", null, "*/*", null },
-// { "aaa", "aaa", null, "aaa, bbb" },
-// { "aaa", null, "*/*", "aaa, bbb" },
- };
-
- String[][] casesMetadata = {
- /* expected $format accept supported */
- { "application/xml", null, null, null },
- { "application/xml", "xml", null, null },
- { "application/xml", null, "application/xml", null },
- { "application/xml", "xml", "application/xml", null },
- { "application/xml", null, "*/*", null },
-// { "aaa", "aaa", null, "aaa, bbb" },
- };
-
- String[][] casesEntitySet = {
- /* expected $format accept supported */
- { "application/json", null, null, null },
- { "application/json", "json", null, null },
- { "application/json", "json", "application/json", null },
- { "application/json", null, "*/*", null },
- };
-
- //CHECKSTYLE:ON
- //@formatter:on
-
- private ODataHandler createHandler() {
- OData odata = OData.newInstance();
- Edm edm = odata.createEdm(new EdmTechProvider());
- return new ODataHandler(odata, edm);
-
- }
-
- @Test
- public void testServiceDocumentDefault() {
-
- for (String[] useCase : casesServiceDocument) {
- ODataRequest request = new ODataRequest();
- request.setMethod(HttpMethod.GET);
- request.setRawODataPath("/" + (useCase[1] == null ? "" : "?$format=" + useCase[1]));
-
- ODataResponse response = callHandler(useCase, request);
-
- assertEquals(useCase[0], response.getHeaders().get(HttpHeader.CONTENT_TYPE));
- }
- }
-
- @Test
- public void testMetadataDefault() {
-
- for (String[] useCase : casesMetadata) {
- ODataRequest request = new ODataRequest();
- request.setMethod(HttpMethod.GET);
- request.setRawODataPath("/$metadata" + (useCase[1] == null ? "" : "?$format=" + useCase[1]));
-
- ODataResponse response = callHandler(useCase, request);
-
- assertEquals(useCase[0], response.getHeaders().get(HttpHeader.CONTENT_TYPE));
- }
- }
-
- @Test
- public void testEntitySet() {
-
- for (String[] useCase : casesEntitySet) {
- ODataRequest request = new ODataRequest();
- request.setMethod(HttpMethod.GET);
- request.setRawODataPath("/ESAllPrim" + (useCase[1] == null ? "" : "?$format=" + useCase[1]));
-
- ODataResponse response = callHandler(useCase, request, new CollectionProcessorStub());
-
- assertEquals(useCase[0], response.getHeaders().get(HttpHeader.CONTENT_TYPE));
- }
- }
-
- private ODataResponse callHandler(String[] useCase, ODataRequest request,
- Processor defaultProcessor) {
- ODataHandler handler = createHandler();
-
- if (useCase[3] != null) {
- ProcessorStub stub = new ProcessorStub(useCase[3].split(","));
- handler.register(stub);
- } else {
- if (defaultProcessor != null) {
- handler.register(defaultProcessor);
- }
- }
-
- ODataResponse response = handler.process(request);
- return response;
- }
-
- ODataResponse callHandler(String[] useCase, ODataRequest request) {
- return callHandler(useCase, request, null);
- }
-
- private class ProcessorStub implements ServiceDocumentProcessor, MetadataProcessor, CollectionProcessor,
- SupportCustomContentTypes {
-
- String[] formats;
-
- ProcessorStub(String[] strings) {
- this.formats = strings;
- }
-
- @Override
- public void init(OData odata, Edm edm) {}
-
- @Override
- public List getSupportedContentTypes(Class extends Processor> processorClass) {
- return Arrays.asList(formats);
- }
-
- @Override
- public void readServiceDocument(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
- response.setHeader(HttpHeader.CONTENT_TYPE, format);
- }
-
- @Override
- public void readCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
- response.setHeader(HttpHeader.CONTENT_TYPE, format);
- }
-
- @Override
- public void readMetadata(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
- response.setHeader(HttpHeader.CONTENT_TYPE, format);
- }
-
- }
-
- private class CollectionProcessorStub implements CollectionProcessor {
-
- @Override
- public void init(OData odata, Edm edm) {}
-
- @Override
- public void readCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
- response.setHeader(HttpHeader.CONTENT_TYPE, format);
- }
- }
-
-}