[OLINGO-337] improve AcceptType class to allow '*'
This commit is contained in:
parent
434246abe9
commit
f4640911af
|
@ -23,7 +23,6 @@ import static org.junit.Assert.assertEquals;
|
|||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -43,7 +42,6 @@ public class PingITCase {
|
|||
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setRequestProperty(HttpHeader.ACCEPT, "application/json");
|
||||
connection.connect();
|
||||
|
||||
int code = connection.getResponseCode();
|
||||
|
@ -59,7 +57,6 @@ public class PingITCase {
|
|||
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setRequestProperty(HttpHeader.ACCEPT, "application/json");
|
||||
connection.connect();
|
||||
|
||||
int code = connection.getResponseCode();
|
||||
|
|
|
@ -46,11 +46,8 @@ import java.util.regex.Pattern;
|
|||
*/
|
||||
public class AcceptType {
|
||||
|
||||
private static final String MEDIA_TYPE_WILDCARD = "*";
|
||||
private static final String PARAMETER_Q = "q";
|
||||
private static final Pattern Q_PARAMETER_VALUE_PATTERN = Pattern.compile("1|0|1\\.0{1,3}|0\\.\\d{1,3}");
|
||||
|
||||
public static final AcceptType WILDCARD = create(MEDIA_TYPE_WILDCARD, MEDIA_TYPE_WILDCARD, createParameterMap(), 1F);
|
||||
public static final AcceptType WILDCARD = create(TypeUtil.MEDIA_TYPE_WILDCARD, TypeUtil.MEDIA_TYPE_WILDCARD,
|
||||
createParameterMap(), 1F);
|
||||
|
||||
private final String type;
|
||||
private final String subtype;
|
||||
|
@ -81,25 +78,51 @@ public class AcceptType {
|
|||
}
|
||||
List<String> typeSubtype = new ArrayList<String>();
|
||||
parameters = createParameterMap();
|
||||
ContentType.parse(type, typeSubtype, parameters);
|
||||
parse(type, typeSubtype, parameters);
|
||||
this.type = typeSubtype.get(0);
|
||||
subtype = typeSubtype.get(1);
|
||||
if (MEDIA_TYPE_WILDCARD.equals(this.type) && !MEDIA_TYPE_WILDCARD.equals(subtype)) {
|
||||
if (TypeUtil.MEDIA_TYPE_WILDCARD.equals(this.type) && !TypeUtil.MEDIA_TYPE_WILDCARD.equals(subtype)) {
|
||||
throw new IllegalArgumentException("Illegal combination of WILDCARD type with NONE WILDCARD subtype.");
|
||||
}
|
||||
final String q = parameters.get(PARAMETER_Q);
|
||||
final String q = parameters.get(TypeUtil.PARAMETER_Q);
|
||||
if (q == null) {
|
||||
quality = 1F;
|
||||
} else {
|
||||
if (Q_PARAMETER_VALUE_PATTERN.matcher(q).matches()) {
|
||||
try {
|
||||
quality = Float.valueOf(q);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Illegal quality parameter.");
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException("Illegal quality parameter.", e);
|
||||
}
|
||||
parameters.remove(PARAMETER_Q);
|
||||
}
|
||||
}
|
||||
|
||||
private static void
|
||||
parse(final String format, final List<String> typeSubtype, final Map<String, String> parameters) {
|
||||
final String[] typesAndParameters = format.split(TypeUtil.PARAMETER_SEPARATOR, 2);
|
||||
final String types = typesAndParameters[0];
|
||||
final String params = (typesAndParameters.length > 1 ? typesAndParameters[1] : null);
|
||||
|
||||
String[] tokens = types.split(TypeUtil.TYPE_SUBTYPE_SEPARATOR);
|
||||
if (tokens.length == 1) {
|
||||
typeSubtype.add(tokens[0]);
|
||||
typeSubtype.add(TypeUtil.MEDIA_TYPE_WILDCARD);
|
||||
} else if (tokens.length == 2) {
|
||||
if (tokens[0] == null || tokens[0].isEmpty()) {
|
||||
throw new IllegalArgumentException("No type found in format '" + format + "'.");
|
||||
} else if (tokens[1] == null || tokens[1].isEmpty()) {
|
||||
throw new IllegalArgumentException("No subtype found in format '" + format + "'.");
|
||||
} else {
|
||||
typeSubtype.add(tokens[0]);
|
||||
typeSubtype.add(tokens[1]);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Too many '" + TypeUtil.TYPE_SUBTYPE_SEPARATOR + "' in format '" + format
|
||||
+ "'.");
|
||||
}
|
||||
|
||||
TypeUtil.parseParameters(params, parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an accept type.
|
||||
* @param type
|
||||
|
@ -172,7 +195,7 @@ public class AcceptType {
|
|||
result.append(';').append(key).append('=').append(parameters.get(key));
|
||||
}
|
||||
if (quality < 1F) {
|
||||
result.append(';').append(PARAMETER_Q).append('=').append(quality);
|
||||
result.append(';').append(TypeUtil.PARAMETER_Q).append('=').append(quality);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
@ -189,13 +212,13 @@ public class AcceptType {
|
|||
* @return whether this accept type matches the given content type
|
||||
*/
|
||||
public boolean matches(final ContentType contentType) {
|
||||
if (type.equals(MEDIA_TYPE_WILDCARD)) {
|
||||
if (type.equals(TypeUtil.MEDIA_TYPE_WILDCARD)) {
|
||||
return true;
|
||||
}
|
||||
if (!type.equalsIgnoreCase(contentType.getType())) {
|
||||
return false;
|
||||
}
|
||||
if (subtype.equals(MEDIA_TYPE_WILDCARD)) {
|
||||
if (subtype.equals(TypeUtil.MEDIA_TYPE_WILDCARD)) {
|
||||
return true;
|
||||
}
|
||||
if (!subtype.equalsIgnoreCase(contentType.getSubtype())) {
|
||||
|
@ -246,13 +269,13 @@ public class AcceptType {
|
|||
if (compare != 0) {
|
||||
return compare;
|
||||
}
|
||||
compare = (a1.getType().equals(MEDIA_TYPE_WILDCARD) ? 1 : 0)
|
||||
- (a2.getType().equals(MEDIA_TYPE_WILDCARD) ? 1 : 0);
|
||||
compare = (a1.getType().equals(TypeUtil.MEDIA_TYPE_WILDCARD) ? 1 : 0)
|
||||
- (a2.getType().equals(TypeUtil.MEDIA_TYPE_WILDCARD) ? 1 : 0);
|
||||
if (compare != 0) {
|
||||
return compare;
|
||||
}
|
||||
compare = (a1.getSubtype().equals(MEDIA_TYPE_WILDCARD) ? 1 : 0)
|
||||
- (a2.getSubtype().equals(MEDIA_TYPE_WILDCARD) ? 1 : 0);
|
||||
compare = (a1.getSubtype().equals(TypeUtil.MEDIA_TYPE_WILDCARD) ? 1 : 0)
|
||||
- (a2.getSubtype().equals(TypeUtil.MEDIA_TYPE_WILDCARD) ? 1 : 0);
|
||||
if (compare != 0) {
|
||||
return compare;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.util.Comparator;
|
|||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
|
@ -46,36 +45,28 @@ import java.util.TreeMap;
|
|||
*/
|
||||
public class ContentType {
|
||||
|
||||
private static final char WHITESPACE_CHAR = ' ';
|
||||
private static final String PARAMETER_SEPARATOR = ";";
|
||||
private static final String PARAMETER_KEY_VALUE_SEPARATOR = "=";
|
||||
private static final String TYPE_SUBTYPE_SEPARATOR = "/";
|
||||
|
||||
public static final String PARAMETER_TYPE = "type";
|
||||
public static final String PARAMETER_CHARSET = "charset";
|
||||
public static final String CHARSET_UTF_8 = "UTF-8";
|
||||
|
||||
public static final ContentType APPLICATION_XML = create("application", "xml");
|
||||
public static final ContentType APPLICATION_XML_CS_UTF_8 = create(APPLICATION_XML, PARAMETER_CHARSET,
|
||||
CHARSET_UTF_8);
|
||||
public static final ContentType APPLICATION_XML_CS_UTF_8 = create(APPLICATION_XML, TypeUtil.PARAMETER_CHARSET,
|
||||
TypeUtil.CHARSET_UTF_8);
|
||||
public static final ContentType APPLICATION_ATOM_XML = create("application", "atom+xml");
|
||||
public static final ContentType APPLICATION_ATOM_XML_CS_UTF_8 = create(APPLICATION_ATOM_XML,
|
||||
PARAMETER_CHARSET, CHARSET_UTF_8);
|
||||
public static final ContentType APPLICATION_ATOM_XML_ENTRY = create(APPLICATION_ATOM_XML, PARAMETER_TYPE, "entry");
|
||||
TypeUtil.PARAMETER_CHARSET, TypeUtil.CHARSET_UTF_8);
|
||||
public static final ContentType APPLICATION_ATOM_XML_ENTRY = create(APPLICATION_ATOM_XML,TypeUtil. PARAMETER_TYPE, "entry");
|
||||
public static final ContentType APPLICATION_ATOM_XML_ENTRY_CS_UTF_8 = create(APPLICATION_ATOM_XML_ENTRY,
|
||||
PARAMETER_CHARSET, CHARSET_UTF_8);
|
||||
public static final ContentType APPLICATION_ATOM_XML_FEED = create(APPLICATION_ATOM_XML, PARAMETER_TYPE, "feed");
|
||||
TypeUtil. PARAMETER_CHARSET, TypeUtil.CHARSET_UTF_8);
|
||||
public static final ContentType APPLICATION_ATOM_XML_FEED = create(APPLICATION_ATOM_XML,TypeUtil. PARAMETER_TYPE, "feed");
|
||||
public static final ContentType APPLICATION_ATOM_XML_FEED_CS_UTF_8 = create(APPLICATION_ATOM_XML_FEED,
|
||||
PARAMETER_CHARSET, CHARSET_UTF_8);
|
||||
TypeUtil. PARAMETER_CHARSET,TypeUtil.CHARSET_UTF_8);
|
||||
public static final ContentType APPLICATION_ATOM_SVC = create("application", "atomsvc+xml");
|
||||
public static final ContentType APPLICATION_ATOM_SVC_CS_UTF_8 = create(APPLICATION_ATOM_SVC,
|
||||
PARAMETER_CHARSET, CHARSET_UTF_8);
|
||||
TypeUtil. PARAMETER_CHARSET, TypeUtil.CHARSET_UTF_8);
|
||||
public static final ContentType APPLICATION_JSON = create("application", "json");
|
||||
public static final ContentType APPLICATION_JSON_CS_UTF_8 = create(APPLICATION_JSON,
|
||||
PARAMETER_CHARSET, CHARSET_UTF_8);
|
||||
TypeUtil. PARAMETER_CHARSET,TypeUtil. CHARSET_UTF_8);
|
||||
public static final ContentType APPLICATION_OCTET_STREAM = create("application", "octet-stream");
|
||||
public static final ContentType TEXT_PLAIN = create("text", "plain");
|
||||
public static final ContentType TEXT_PLAIN_CS_UTF_8 = create(TEXT_PLAIN, PARAMETER_CHARSET, CHARSET_UTF_8);
|
||||
public static final ContentType TEXT_PLAIN_CS_UTF_8 = create(TEXT_PLAIN, TypeUtil.PARAMETER_CHARSET,TypeUtil. CHARSET_UTF_8);
|
||||
public static final ContentType MULTIPART_MIXED = create("multipart", "mixed");
|
||||
|
||||
public static final ContentType APPLICATION_XHTML_XML = create("application", "xhtml+xml");
|
||||
|
@ -118,7 +109,7 @@ public class ContentType {
|
|||
}
|
||||
int len = type.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (type.charAt(i) == WHITESPACE_CHAR) {
|
||||
if (type.charAt(i) == TypeUtil.WHITESPACE_CHAR) {
|
||||
throw new IllegalArgumentException("Illegal whitespace found for type '" + type + "'.");
|
||||
}
|
||||
}
|
||||
|
@ -196,14 +187,14 @@ public class ContentType {
|
|||
}
|
||||
}
|
||||
|
||||
protected static void
|
||||
private static void
|
||||
parse(final String format, final List<String> typeSubtype, final Map<String, String> parameters) {
|
||||
final String[] typesAndParameters = format.split(PARAMETER_SEPARATOR, 2);
|
||||
final String[] typesAndParameters = format.split(TypeUtil.PARAMETER_SEPARATOR, 2);
|
||||
final String types = typesAndParameters[0];
|
||||
final String params = (typesAndParameters.length > 1 ? typesAndParameters[1] : null);
|
||||
|
||||
if (types.contains(TYPE_SUBTYPE_SEPARATOR)) {
|
||||
String[] tokens = types.split(TYPE_SUBTYPE_SEPARATOR);
|
||||
if (types.contains(TypeUtil.TYPE_SUBTYPE_SEPARATOR)) {
|
||||
String[] tokens = types.split(TypeUtil.TYPE_SUBTYPE_SEPARATOR);
|
||||
if (tokens.length == 2) {
|
||||
if (tokens[0] == null || tokens[0].isEmpty()) {
|
||||
throw new IllegalArgumentException("No type found in format '" + format + "'.");
|
||||
|
@ -214,45 +205,14 @@ public class ContentType {
|
|||
typeSubtype.add(tokens[1]);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Too many '" + TYPE_SUBTYPE_SEPARATOR + "' in format '" + format + "'.");
|
||||
throw new IllegalArgumentException("Too many '" +TypeUtil.TYPE_SUBTYPE_SEPARATOR + "' in format '" + format + "'.");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("No separator '" + TYPE_SUBTYPE_SEPARATOR
|
||||
throw new IllegalArgumentException("No separator '" +TypeUtil.TYPE_SUBTYPE_SEPARATOR
|
||||
+ "' was found in format '" + format + "'.");
|
||||
}
|
||||
|
||||
parseParameters(params, parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Valid input are <code>;</code> separated <code>key=value</code> pairs
|
||||
* without spaces between key and value.
|
||||
* <p>
|
||||
* See RFC 7231:
|
||||
* The type, subtype, and parameter name tokens are case-insensitive.
|
||||
* Parameter values might or might not be case-sensitive, depending on
|
||||
* the semantics of the parameter name. The presence or absence of a
|
||||
* parameter might be significant to the processing of a media-type,
|
||||
* depending on its definition within the media type registry.
|
||||
* </p>
|
||||
*
|
||||
* @param parameters
|
||||
* @param parameterMap
|
||||
*/
|
||||
private static void parseParameters(final String parameters, final Map<String, String> parameterMap) {
|
||||
if (parameters != null) {
|
||||
String[] splittedParameters = parameters.split(PARAMETER_SEPARATOR);
|
||||
for (String parameter : splittedParameters) {
|
||||
String[] keyValue = parameter.split(PARAMETER_KEY_VALUE_SEPARATOR);
|
||||
String key = keyValue[0].trim().toLowerCase(Locale.ENGLISH);
|
||||
String value = keyValue.length > 1 ? keyValue[1] : null;
|
||||
if (value != null && Character.isWhitespace(value.charAt(0))) {
|
||||
throw new IllegalArgumentException(
|
||||
"Value of parameter '" + key + "' starts with whitespace ('" + parameters + "').");
|
||||
}
|
||||
parameterMap.put(key, value);
|
||||
}
|
||||
}
|
||||
TypeUtil.parseParameters(params, parameters);
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
|
@ -406,7 +366,7 @@ public class ContentType {
|
|||
public String toContentTypeString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(type).append(TYPE_SUBTYPE_SEPARATOR).append(subtype);
|
||||
sb.append(type).append(TypeUtil.TYPE_SUBTYPE_SEPARATOR).append(subtype);
|
||||
|
||||
for (String key : parameters.keySet()) {
|
||||
sb.append(";").append(key).append("=").append(parameters.get(key));
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
class TypeUtil {
|
||||
|
||||
static final String MEDIA_TYPE_WILDCARD = "*";
|
||||
static final String PARAMETER_Q = "q";
|
||||
|
||||
static final char WHITESPACE_CHAR = ' ';
|
||||
static final String PARAMETER_SEPARATOR = ";";
|
||||
static final String PARAMETER_KEY_VALUE_SEPARATOR = "=";
|
||||
static final String TYPE_SUBTYPE_SEPARATOR = "/";
|
||||
static final String TYPE_SUBTYPE_WILDCARD = "*";
|
||||
|
||||
static final String PARAMETER_TYPE = "type";
|
||||
static final String PARAMETER_CHARSET = "charset";
|
||||
static final String CHARSET_UTF_8 = "UTF-8";
|
||||
|
||||
/**
|
||||
* Valid input are <code>;</code> separated <code>key=value</code> pairs
|
||||
* without spaces between key and value.
|
||||
* <p>
|
||||
* See RFC 7231:
|
||||
* The type, subtype, and parameter name tokens are case-insensitive.
|
||||
* Parameter values might or might not be case-sensitive, depending on
|
||||
* the semantics of the parameter name. The presence or absence of a
|
||||
* parameter might be significant to the processing of a media-type,
|
||||
* depending on its definition within the media type registry.
|
||||
* </p>
|
||||
*
|
||||
* @param parameters
|
||||
* @param parameterMap
|
||||
*/
|
||||
static void parseParameters(final String parameters, final Map<String, String> parameterMap) {
|
||||
if (parameters != null) {
|
||||
String[] splittedParameters = parameters.split(TypeUtil.PARAMETER_SEPARATOR);
|
||||
for (String parameter : splittedParameters) {
|
||||
String[] keyValue = parameter.split(TypeUtil.PARAMETER_KEY_VALUE_SEPARATOR);
|
||||
String key = keyValue[0].trim().toLowerCase(Locale.ENGLISH);
|
||||
String value = keyValue.length > 1 ? keyValue[1] : null;
|
||||
if (value != null && Character.isWhitespace(value.charAt(0))) {
|
||||
throw new IllegalArgumentException(
|
||||
"Value of parameter '" + key + "' starts with whitespace ('" + parameters + "').");
|
||||
}
|
||||
parameterMap.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -23,7 +23,6 @@ import static org.junit.Assert.assertNotNull;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AcceptTypeTest {
|
||||
|
@ -45,16 +44,21 @@ public class AcceptTypeTest {
|
|||
assertEquals(1, atl.size());
|
||||
assertEquals("a/a", atl.get(0).toString());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testWrongQParameter() {
|
||||
AcceptType.create(" a/a;q=z ");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("buggy and not yet fixed")
|
||||
public void testWildcard() {
|
||||
List<AcceptType> atl = AcceptType.create("*; q=.2");
|
||||
|
||||
assertNotNull(atl);
|
||||
assertEquals(1, atl.size());
|
||||
assertEquals("", atl.get(0).getType());
|
||||
assertEquals("", atl.get(0).getSubtype());
|
||||
assertEquals("*", atl.get(0).getType());
|
||||
assertEquals("*", atl.get(0).getSubtype());
|
||||
assertEquals(".2", atl.get(0).getParameters().get("q"));
|
||||
assertEquals(new Float(0.2), atl.get(0).getQuality());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public class ContentTypeTest {
|
||||
|
||||
}
|
Loading…
Reference in New Issue