[OLINGO-328] refactor content negotiation
This commit is contained in:
parent
0ffc26d1b2
commit
acc12ff742
|
@ -46,6 +46,11 @@
|
|||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.apache.olingo.server.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ public class ODataRequest {
|
|||
String key = name.toUpperCase();
|
||||
if (headers.containsKey(key)) {
|
||||
List<String> oldValues = headers.get(key);
|
||||
|
||||
|
||||
List<String> newValues = new ArrayList<String>();
|
||||
newValues.addAll(oldValues);
|
||||
newValues.addAll(values);
|
||||
|
|
|
@ -20,8 +20,9 @@ package org.apache.olingo.server.api.processor;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
public interface SupportCustomContentTypes {
|
||||
public interface CustomContentTypeSupport {
|
||||
|
||||
public List<FormatContentTypeMapping> modifySupportedContentTypes(
|
||||
List<FormatContentTypeMapping> supportedContentTypes, Class<? extends Processor> processorClass);
|
||||
|
||||
public List<String> getSupportedContentTypes(Class<? extends Processor> processorClass);
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 + "')";
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<FormatContentTypeMapping> getDefaultSupportedContentTypes(Class<? extends Processor> processorClass) {
|
||||
List<FormatContentTypeMapping> defaults = new ArrayList<FormatContentTypeMapping>();
|
||||
|
||||
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<FormatContentTypeMapping> getSupportedContentTypes(Processor processor,
|
||||
Class<? extends Processor> processorClass) {
|
||||
|
||||
List<FormatContentTypeMapping> supportedContentTypes = getDefaultSupportedContentTypes(processorClass);
|
||||
|
||||
if (processor instanceof CustomContentTypeSupport) {
|
||||
supportedContentTypes =
|
||||
((CustomContentTypeSupport) processor).modifySupportedContentTypes(supportedContentTypes, processorClass);
|
||||
}
|
||||
|
||||
return supportedContentTypes;
|
||||
}
|
||||
|
||||
public String doContentNegotiation(FormatOption formatOption, ODataRequest request,
|
||||
List<FormatContentTypeMapping> supportedContentTypes) {
|
||||
String requestedContentType = null;
|
||||
|
||||
List<String> 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<String> acceptedContentTypes = new ArrayList<String>();
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
|
@ -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<Class<? extends Processor>, Processor> processors = new HashMap<Class<? extends Processor>, Processor>();
|
||||
|
@ -72,12 +85,17 @@ public class ODataHandler {
|
|||
UriValidator validator = new UriValidator();
|
||||
validator.validate(uriInfo, request.getMethod());
|
||||
|
||||
String requestedContentType = doContentNegotiation();
|
||||
String requestedContentType = null;
|
||||
List<FormatContentTypeMapping> 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<String> 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");
|
||||
|
|
|
@ -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<String> headerValues = new ArrayList<String>();
|
||||
|
|
|
@ -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<ServiceDocumentProcessor> 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<FormatContentTypeMapping> 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<FormatContentTypeMapping> createCustomContentTypeMapping(String formatString, String contentTypeString) {
|
||||
List<FormatContentTypeMapping> 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<FormatContentTypeMapping>();
|
||||
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<FormatContentTypeMapping> 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<FormatContentTypeMapping> 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<FormatContentTypeMapping> 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<FormatContentTypeMapping> customMapping;
|
||||
|
||||
ProcessorStub(List<FormatContentTypeMapping> mapping) {
|
||||
this.customMapping = mapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(OData odata, Edm edm) {}
|
||||
|
||||
@Override
|
||||
public List<FormatContentTypeMapping> modifySupportedContentTypes(
|
||||
List<FormatContentTypeMapping> 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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<String> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue