[OLINGO-337] improve AcceptType class to allow '*'
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/62eccf9c Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/62eccf9c Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/62eccf9c Branch: refs/heads/olingo337 Commit: 62eccf9c19fef21d436309bea70c8aef0a6df1cb Parents: 1a1c061 Author: Stephan Klevenz <[email protected]> Authored: Thu Jul 3 12:54:07 2014 +0200 Committer: Stephan Klevenz <[email protected]> Committed: Thu Jul 3 12:54:07 2014 +0200 ---------------------------------------------------------------------- .../apache/olingo/fit/tecsvc/PingITCase.java | 3 - .../olingo/commons/api/format/AcceptType.java | 59 ++++++++++----- .../olingo/commons/api/format/ContentType.java | 78 +++++--------------- .../olingo/commons/api/format/TypeUtil.java | 70 ++++++++++++++++++ .../commons/api/format/AcceptTypeTest.java | 12 ++- .../commons/api/format/ContentTypeTest.java | 23 ++++++ 6 files changed, 161 insertions(+), 84 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/62eccf9c/fit/src/test/java/org/apache/olingo/fit/tecsvc/PingITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/PingITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/PingITCase.java index 44438fd..46ea276 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/PingITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/PingITCase.java @@ -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(); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/62eccf9c/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java index 7a460f1..39bdf75 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java @@ -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,23 +78,49 @@ 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); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Illegal quality parameter.", e); + } + } + } + + 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 { - throw new IllegalArgumentException("Illegal quality parameter."); + typeSubtype.add(tokens[0]); + typeSubtype.add(tokens[1]); } - parameters.remove(PARAMETER_Q); + } else { + throw new IllegalArgumentException("Too many '" + TypeUtil.TYPE_SUBTYPE_SEPARATOR + "' in format '" + format + + "'."); } + + TypeUtil.parseParameters(params, parameters); } /** @@ -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; } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/62eccf9c/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java index 9482f44..3506ffb 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ContentType.java @@ -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)); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/62eccf9c/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/TypeUtil.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/TypeUtil.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/TypeUtil.java new file mode 100644 index 0000000..bbc4463 --- /dev/null +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/TypeUtil.java @@ -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); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/62eccf9c/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptTypeTest.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptTypeTest.java b/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptTypeTest.java index 211a74b..4427bf0 100644 --- a/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptTypeTest.java +++ b/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/AcceptTypeTest.java @@ -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()); } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/62eccf9c/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/ContentTypeTest.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/ContentTypeTest.java b/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/ContentTypeTest.java new file mode 100644 index 0000000..e2098f6 --- /dev/null +++ b/lib/commons-api/src/test/java/org/apache/olingo/commons/api/format/ContentTypeTest.java @@ -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 { + +}
