Repository: olingo-odata4 Updated Branches: refs/heads/Olingo-317_DeSerializerRefactoring ab6fd5e2b -> ce3598521
[OLINGO-317] Minor ContentType refactoring Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/ce359852 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/ce359852 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/ce359852 Branch: refs/heads/Olingo-317_DeSerializerRefactoring Commit: ce3598521da0b4b6576067ea82278a8b22823bde Parents: ab6fd5e Author: Michael Bolz <[email protected]> Authored: Mon Jun 23 15:19:23 2014 +0200 Committer: Michael Bolz <[email protected]> Committed: Mon Jun 23 15:19:23 2014 +0200 ---------------------------------------------------------------------- .../apache/olingo/commons/api/data/Value.java | 2 - .../olingo/commons/api/format/AcceptType.java | 259 ++++++++++++ .../olingo/commons/api/format/ContentType.java | 407 +++---------------- .../olingo/commons/api/format/ODataFormat.java | 27 +- .../olingo/commons/core/data/AbstractValue.java | 5 - 5 files changed, 332 insertions(+), 368 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce359852/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Value.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Value.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Value.java index 08a420d..268a026 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Value.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Value.java @@ -36,8 +36,6 @@ public interface Value { Object get(); - NullValue asNull(); - PrimitiveValue asPrimitive(); EnumValue asEnum(); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce359852/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 new file mode 100644 index 0000000..07a5452 --- /dev/null +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/AcceptType.java @@ -0,0 +1,259 @@ +/******************************************************************************* + * 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.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.regex.Pattern; + +/** + * Internally used {@link AcceptType} for OData library. + * + * See RFC 7231, chapter 5.3.2: + * <pre> + * Accept = #( media-range [ accept-params ] ) + * media-range = ( "*/*" + * / ( type "/" "*" ) + * / ( type "/" subtype ) + * ) *( OWS ";" OWS parameter ) + * accept-params = weight *( accept-ext ) + * accept-ext = OWS ";" OWS token [ "=" ( token / quoted-string ) ] + * weight = OWS ";" OWS "q=" qvalue + * qvalue = ( "0" [ "." 0*3DIGIT ] ) / ( "1" [ "." 0*3("0") ] ) + * </pre> + * + * Once created a {@link AcceptType} is <b>IMMUTABLE</b>. + */ +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, null, 1F); + + private final String type; + private final String subtype; + private final Map<String, String> parameters; + private final Float quality; + + private AcceptType(final String type, final String subtype, final Map<String, String> parameters, + final Float quality) { + this.type = type; + this.subtype = subtype; + this.parameters = createParameterMap(); + this.parameters.putAll(parameters); + this.quality = quality; + } + + private TreeMap<String, String> createParameterMap() { + return new TreeMap<String, String>(new Comparator<String>() { + @Override + public int compare(final String o1, final String o2) { + return o1.compareToIgnoreCase(o2); + } + }); + } + + private AcceptType(final String type) { + if (type == null) { + throw new IllegalArgumentException("Type parameter MUST NOT be null."); + } + List<String> typeSubtype = new ArrayList<String>(); + this.parameters = createParameterMap(); + ContentType.parse(type, typeSubtype, parameters); + this.type = typeSubtype.get(0); + this.subtype = typeSubtype.get(1); + if (MEDIA_TYPE_WILDCARD.equals(this.type) && !MEDIA_TYPE_WILDCARD.equals(this.subtype)) { + throw new IllegalArgumentException("Illegal combination of WILDCARD type with NONE WILDCARD subtype."); + } + final String q = parameters.get(PARAMETER_Q); + if (q == null) { + quality = 1F; + } else { + if (Q_PARAMETER_VALUE_PATTERN.matcher(q).matches()) { + quality = Float.valueOf(q); + } else { + throw new IllegalArgumentException("Illegal quality parameter."); + } + parameters.remove(PARAMETER_Q); + } + } + + /** + * Creates an accept type. + * @param type + * @param subtype + * @param parameters + * @param quality + * @return a new <code>AcceptType</code> object + */ + public static AcceptType create(final String type, final String subtype, final Map<String, String> parameters, + final Float quality) { + return new AcceptType(type, subtype, parameters, quality); + } + + public static AcceptType create(final ContentType contentType) { + return create(contentType.getType(), contentType.getSubtype(), contentType.getParameters(), 1F); + } + + /** + * Create an {@link AcceptType} based on given input string (<code>format</code>). + * @param format + * @return a new <code>AcceptType</code> object + * @throws IllegalArgumentException if input string is not parseable + */ + public static AcceptType create(final String format) { + if (format == null) { + throw new IllegalArgumentException("Parameter format MUST NOT be NULL."); + } + return new AcceptType(format); + } + + /** + * Parses the given input string (<code>format</code>) and returns created {@link AcceptType} if input was valid or + * return <code>NULL</code> if input was not parseable. + * @param format + * @return a new <code>ContentType</code> object + */ + public static AcceptType parse(final String format) { + try { + return AcceptType.create(format); + } catch (IllegalArgumentException e) { + return null; + } + } + + public String getType() { + return type; + } + + public String getSubtype() { + return subtype; + } + + public Map<String, String> getParameters() { + return parameters; + } + + public Float getQuality() { + return quality; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + result.append(type).append('/').append(subtype); + for (final String key : parameters.keySet()) { + result.append(';').append(key).append('=').append(parameters.get(key)); + } + if (quality < 1F) { + result.append(';').append(PARAMETER_Q).append('=').append(quality); + } + return result.toString(); + } + + /** + * <p>Determines whether this accept type matches a given content type.</p> + * <p>A match is defined as fulfilling all of the following conditions: + * <ul> + * <li>the type must be '*' or equal to the content-type's type,</li> + * <li>the subtype must be '*' or equal to the content-type's subtype,</li> + * <li>all parameters must have the same value as in the content-type's parameter map.</li> + * </ul></p> + * @param contentType + * @return whether this accept type matches the given content type + */ + public boolean matches(final ContentType contentType) { + if (type.equals(MEDIA_TYPE_WILDCARD)) { + return true; + } + if (!type.equalsIgnoreCase(contentType.getType())) { + return false; + } + if (subtype.equals(MEDIA_TYPE_WILDCARD)) { + return true; + } + if (!subtype.equalsIgnoreCase(contentType.getSubtype())) { + return false; + } + Map<String, String> compareParameters = contentType.getParameters(); + for (final String key : parameters.keySet()) { + if (compareParameters.containsKey(key)) { + if (!parameters.get(key).equalsIgnoreCase(compareParameters.get(key))) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** + * Create a list of {@link AcceptType} based on given input strings (<code>contentTypes</code>). + * + * If one of the given strings can not be parsed an exception is thrown (hence no list is returned with the parseable + * strings). + * @param acceptTypeStrings a list of strings + * @return a list of new <code>AcceptType</code> objects + * @throws IllegalArgumentException if one of the given input string is not parseable this exceptions is thrown + */ + public static List<AcceptType> create(final List<String> acceptTypeStrings) { + List<AcceptType> acceptTypes = new ArrayList<AcceptType>(acceptTypeStrings.size()); + for (String contentTypeString : acceptTypeStrings) { + acceptTypes.add(create(contentTypeString)); + } + return acceptTypes; + } + + /** + * Sort given list of Accept types + * according to their quality-parameter values and their specificity + * as defined in RFC 7231, chapters 3.1.1.1, 5.3.1, and 5.3.2. + * @param toSort list which is sorted and hence re-arranged + */ + public static void sort(List<AcceptType> toSort) { + Collections.sort(toSort, + new Comparator<AcceptType>() { + @Override + public int compare(final AcceptType a1, final AcceptType a2) { + int compare = a1.getQuality().compareTo(a2.getQuality()); + if (compare != 0) { + return compare; + } + compare = (a1.getType().equals(MEDIA_TYPE_WILDCARD) ? 1 : 0) + - (a2.getType().equals(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); + if (compare != 0) { + return compare; + } + return a2.getParameters().size() - a1.getParameters().size(); + } + }); + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce359852/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 12a3152..2ff67bb 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 @@ -19,7 +19,6 @@ package org.apache.olingo.commons.api.format; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -29,7 +28,6 @@ import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; -import java.util.regex.Pattern; /** * Internally used {@link ContentType} for OData library. @@ -44,55 +42,19 @@ import java.util.regex.Pattern; * OWS = *( SP / HTAB ) ; optional whitespace * </pre> * - * Especially for <code>Accept</code> Header as defined in - * RFC 7231, chapter 5.3.2: - * <pre> - * Accept = #( media-range [ accept-params ] ) - * media-range = ( "*/*" - * / ( type "/" "*" ) - * / ( type "/" subtype ) - * ) *( OWS ";" OWS parameter ) - * accept-params = weight *( accept-ext ) - * accept-ext = OWS ";" OWS token [ "=" ( token / quoted-string ) ] - * weight = OWS ";" OWS "q=" qvalue - * qvalue = ( "0" [ "." 0*3DIGIT ] ) / ( "1" [ "." 0*3("0") ] ) - * </pre> - * * Once created a {@link ContentType} is <b>IMMUTABLE</b>. */ public class ContentType { - private static final Comparator<String> Q_PARAMETER_COMPARATOR = new Comparator<String>() { - @Override - public int compare(final String o1, final String o2) { - Float f1 = parseQParameterValue(o1); - Float f2 = parseQParameterValue(o2); - return f2.compareTo(f1); - } - }; - 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 = "/"; - private static final String MEDIA_TYPE_WILDCARD = "*"; - public static final String PARAMETER_Q = "q"; public static final String PARAMETER_TYPE = "type"; public static final String PARAMETER_CHARSET = "charset"; public static final String CHARSET_UTF_8 = "UTF-8"; - private static final Pattern Q_PARAMETER_VALUE_PATTERN = Pattern.compile("1|0|1\\.0{1,3}|0\\.\\d{1,3}"); - - public static final ContentType WILDCARD = create(MEDIA_TYPE_WILDCARD, MEDIA_TYPE_WILDCARD); - - public static final ContentType APPLICATION_XHTML_XML = create("application", "xhtml+xml"); - public static final ContentType APPLICATION_SVG_XML = create("application", "svg+xml"); - public static final ContentType APPLICATION_FORM_URLENCODED = create("application", "x-www-form-urlencoded"); - public static final ContentType MULTIPART_FORM_DATA = create("multipart", "form-data"); - public static final ContentType TEXT_XML = create("text", "xml"); - public static final ContentType TEXT_HTML = create("text", "html"); - 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); @@ -103,43 +65,37 @@ public class ContentType { 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"); - public static final ContentType APPLICATION_ATOM_XML_FEED_CS_UTF_8 = ContentType.create(APPLICATION_ATOM_XML_FEED, + public static final ContentType APPLICATION_ATOM_XML_FEED_CS_UTF_8 = create(APPLICATION_ATOM_XML_FEED, PARAMETER_CHARSET, 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); 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); + PARAMETER_CHARSET, 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 = ContentType - .create(TEXT_PLAIN, PARAMETER_CHARSET, CHARSET_UTF_8); + public static final ContentType TEXT_PLAIN_CS_UTF_8 = create(TEXT_PLAIN, PARAMETER_CHARSET, CHARSET_UTF_8); public static final ContentType MULTIPART_MIXED = create("multipart", "mixed"); + public static final ContentType APPLICATION_XHTML_XML = create("application", "xhtml+xml"); + public static final ContentType APPLICATION_SVG_XML = create("application", "svg+xml"); + public static final ContentType APPLICATION_FORM_URLENCODED = create("application", "x-www-form-urlencoded"); + public static final ContentType MULTIPART_FORM_DATA = create("multipart", "form-data"); + public static final ContentType TEXT_XML = create("text", "xml"); + public static final ContentType TEXT_HTML = create("text", "html"); + private final String type; private final String subtype; private final Map<String, String> parameters; - private ContentType(final String type) { - if (type == null) { - throw new IllegalArgumentException("Type parameter MUST NOT be null."); - } - this.type = validateType(type); - subtype = null; - parameters = Collections.emptyMap(); - } - /** * Creates a content type from type, subtype, and parameters. - * @param type - * @param subtype - * @param parameters - */ + * @param type + * @param subtype + * @param parameters + */ private ContentType(final String type, final String subtype, final Map<String, String> parameters) { - if ((type == null || MEDIA_TYPE_WILDCARD.equals(type)) && !MEDIA_TYPE_WILDCARD.equals(subtype)) { - throw new IllegalArgumentException("Illegal combination of WILDCARD type with NONE WILDCARD subtype."); - } this.type = validateType(type); this.subtype = validateType(subtype); @@ -153,13 +109,12 @@ public class ContentType { } }); this.parameters.putAll(parameters); - this.parameters.remove(PARAMETER_Q); } } private String validateType(final String type) { - if (type == null || type.isEmpty()) { - return MEDIA_TYPE_WILDCARD; + if (type == null || type.isEmpty() || "*".equals(type)) { + throw new IllegalArgumentException("Illegal type '" + type + "'."); } int len = type.length(); for (int i = 0; i < len; i++) { @@ -201,14 +156,14 @@ public class ContentType { * @return a new <code>ContentType</code> object */ public static ContentType create(final ContentType contentType, - final String parameterKey, final String parameterValue) { - ContentType ct = new ContentType(contentType.type, contentType.subtype, contentType.parameters); - ct.parameters.put(parameterKey, parameterValue); - return ct; + final String parameterKey, final String parameterValue) { + ContentType newContentType = new ContentType(contentType.type, contentType.subtype, contentType.parameters); + newContentType.parameters.put(parameterKey, parameterValue); + return newContentType; } /** - * Create a {@link ContentType} based on given input string (<code>format</code>). + * Creates a {@link ContentType} based on given input string (<code>format</code>). * Supported format is <code>Media Type</code> format as defined in RFC 7231, chapter 3.1.1.1. * @param format a string in format as defined in RFC 7231, chapter 3.1.1.1 * @return a new <code>ContentType</code> object @@ -218,51 +173,10 @@ public class ContentType { if (format == null) { throw new IllegalArgumentException("Parameter format MUST NOT be NULL."); } - - // split 'types' and 'parameters' - String[] typesAndParameters = format.split(PARAMETER_SEPARATOR, 2); - String types = typesAndParameters[0]; - String parameters = (typesAndParameters.length > 1 ? typesAndParameters[1] : null); - // - Map<String, String> parametersMap = parseParameters(parameters); - // - if (types.contains(TYPE_SUBTYPE_SEPARATOR)) { - String[] tokens = types.split(TYPE_SUBTYPE_SEPARATOR); - 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 { - return new ContentType(tokens[0], tokens[1], parametersMap); - } - } else { - throw new IllegalArgumentException("Too many '" + TYPE_SUBTYPE_SEPARATOR + "' in format '" + format + "'."); - } - } else if (MEDIA_TYPE_WILDCARD.equals(types)) { - return ContentType.WILDCARD; - } else { - throw new IllegalArgumentException("No separator '" + TYPE_SUBTYPE_SEPARATOR + "' was found in format '" + format - + "'."); - } - } - - /** - * Create a list of {@link ContentType} based on given input strings (<code>contentTypes</code>). - * - * Supported format is <code>Media Type</code> format as defined in RFC 7231, chapter 3.1.1.1. - * If one of the given strings can not be parsed an exception is thrown (hence no list is returned with the parseable - * strings). - * @param contentTypeStrings a list of strings in format as defined in <code>RFC 2616 section 3.7</code> - * @return a list of new <code>ContentType</code> object - * @throws IllegalArgumentException if one of the given input string is not parseable this exceptions is thrown - */ - public static List<ContentType> create(final List<String> contentTypeStrings) { - List<ContentType> contentTypes = new ArrayList<ContentType>(contentTypeStrings.size()); - for (String contentTypeString : contentTypeStrings) { - contentTypes.add(create(contentTypeString)); - } - return contentTypes; + List<String> typeSubtype = new ArrayList<String>(); + Map<String, String> parameters = new HashMap<String, String>(); + parse(format, typeSubtype, parameters); + return new ContentType(typeSubtype.get(0), typeSubtype.get(1), parameters); } /** @@ -282,23 +196,36 @@ public class ContentType { } } - /** - * Sort given list (which must contains content-type formatted string) for their {@value #PARAMETER_Q} value - * as defined in RFC 7231, chapter 3.1.1.1, and RFC 7231, chapter 5.3.1. - * - * <b>Attention:</b> For invalid values a {@value #PARAMETER_Q} value from <code>-1</code> is used for sorting. - * - * @param toSort list which is sorted and hence re-arranged - */ - public static void sortForQParameter(final List<String> toSort) { - Collections.sort(toSort, ContentType.Q_PARAMETER_COMPARATOR); + protected static void parse(final String format, List<String> typeSubtype, Map<String, String> parameters) { + final String[] typesAndParameters = format.split(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 (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 '" + TYPE_SUBTYPE_SEPARATOR + "' in format '" + format + "'."); + } + } else { + throw new IllegalArgumentException("No separator '" + 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. - * <b>Attention:</b> <code>q</code> parameter is validated but not added to result map - * * <p> * See RFC 7231: * The type, subtype, and parameter name tokens are case-insensitive. @@ -309,10 +236,9 @@ public class ContentType { * </p> * * @param parameters - * @return Map with keys mapped to values + * @param parameterMap */ - private static Map<String, String> parseParameters(final String parameters) { - Map<String, String> parameterMap = new HashMap<String, String>(); + private static void parseParameters(final String parameters, Map<String, String> parameterMap) { if (parameters != null) { String[] splittedParameters = parameters.split(PARAMETER_SEPARATOR); for (String parameter : splittedParameters) { @@ -320,56 +246,12 @@ public class ContentType { 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 - + "')."); - } - if (PARAMETER_Q.equals(key.toLowerCase(Locale.ENGLISH))) { - // q parameter is only validated but not added - if (!Q_PARAMETER_VALUE_PATTERN.matcher(value).matches()) { - throw new IllegalArgumentException("Value of 'q' parameter is not valid (q='" + value + "')."); - } - } else { - parameterMap.put(key, value); - } - } - } - return parameterMap; - } - - /** - * Parse value of {@value #PARAMETER_Q} <code>parameter</code> out of content type/parameters. - * If no {@value #PARAMETER_Q} <code>parameter</code> is in <code>content type/parameters</code> parameter found - * <code>1</code> is returned. - * If {@value #PARAMETER_Q} <code>parameter</code> is invalid <code>-1</code> is returned. - * - * @param contentType parameter which is parsed for {@value #PARAMETER_Q} <code>parameter</code> value - * @return value of {@value #PARAMETER_Q} <code>parameter</code> or <code>1</code> or <code>-1</code> - */ - private static Float parseQParameterValue(final String contentType) { - if (contentType != null) { - String[] splittedParameters = contentType.split(PARAMETER_SEPARATOR); - for (String parameter : splittedParameters) { - String[] keyValue = parameter.split(PARAMETER_KEY_VALUE_SEPARATOR); - String key = keyValue[0].trim().toLowerCase(Locale.ENGLISH); - if (PARAMETER_Q.equalsIgnoreCase(key)) { - String value = keyValue.length > 1 ? keyValue[1] : null; - if (Q_PARAMETER_VALUE_PATTERN.matcher(value).matches()) { - return Float.valueOf(value); - } - return Float.valueOf(-1); + throw new IllegalArgumentException( + "Value of parameter '" + key + "' starts with whitespace ('" + parameters + "')."); } + parameterMap.put(key, value); } } - return Float.valueOf(1); - } - - /** - * Check if parameter with key value is an allowed parameter. - * @param key - * @return - */ - private static boolean isParameterAllowed(final String key) { - return key != null && !PARAMETER_Q.equals(key.toLowerCase(Locale.ENGLISH)); } public String getType() { @@ -488,11 +370,7 @@ public class ContentType { return false; } } else if (!subtype.equals(other.subtype)) { - if (other.subtype == null) { - return false; - } else if (!subtype.equals(MEDIA_TYPE_WILDCARD) && !other.subtype.equals(MEDIA_TYPE_WILDCARD)) { - return false; - } + return false; } // type checks @@ -501,14 +379,7 @@ public class ContentType { return false; } } else if (!type.equals(other.type)) { - if (!type.equals(MEDIA_TYPE_WILDCARD) && !other.type.equals(MEDIA_TYPE_WILDCARD)) { - return false; - } - } - - // if wildcards are set, content types are defined as 'equal' - if (countWildcards() > 0 || other.countWildcards() > 0) { - return true; + return false; } return null; @@ -523,19 +394,12 @@ public class ContentType { * returned */ private static boolean areEqual(final String first, final String second) { - if (first == null) { - if (second != null) { - return false; - } - } else if (!first.equalsIgnoreCase(second)) { - return false; - } - return true; + return first == null && second == null || first.equalsIgnoreCase(second); } /** - * Get {@link ContentType} as string as defined in RFC 7231 (http://www.ietf.org/rfc/rfc7231.txt, chapter 3.1.1.1: - * Media Type) + * Get {@link ContentType} as string as defined in RFC 7231 + * (http://www.ietf.org/rfc/rfc7231.txt, chapter 3.1.1.1: Media Type) * @return string representation of <code>ContentType</code> object */ public String toContentTypeString() { @@ -544,10 +408,7 @@ public class ContentType { sb.append(type).append(TYPE_SUBTYPE_SEPARATOR).append(subtype); for (String key : parameters.keySet()) { - if (isParameterAllowed(key)) { - String value = parameters.get(key); - sb.append(";").append(key).append("=").append(value); - } + sb.append(";").append(key).append("=").append(parameters.get(key)); } return sb.toString(); } @@ -556,150 +417,4 @@ public class ContentType { public String toString() { return toContentTypeString(); } - - /** - * Find best match between this {@link ContentType} and the {@link ContentType} in the list. - * If a match (this {@link ContentType} is equal to a {@link ContentType} in list) is found either this or the - * {@link ContentType} from the list is returned based on which {@link ContentType} has less "**" characters set - * (checked with {@link #compareWildcardCounts(ContentType)}. - * If no match (none {@link ContentType} in list is equal to this {@link ContentType}) is found <code>NULL</code> is - * returned. - * - * @param toMatchContentTypes list of {@link ContentType}s which are matches against this {@link ContentType} - * @return best matched content type in list or <code>NULL</code> if none content type match to this content type - * instance - */ - public ContentType match(final List<ContentType> toMatchContentTypes) { - for (ContentType supportedContentType : toMatchContentTypes) { - if (equals(supportedContentType)) { - if (compareWildcardCounts(supportedContentType) < 0) { - return this; - } else { - return supportedContentType; - } - } - } - return null; - } - - /** - * Find best match between this {@link ContentType} and the {@link ContentType} in the list ignoring all set - * parameters. - * If a match (this {@link ContentType} is equal to a {@link ContentType} in list) is found either this or the - * {@link ContentType} from the list is returned based on which {@link ContentType} has less "**" characters set - * (checked with {@link #compareWildcardCounts(ContentType)}. - * If no match (none {@link ContentType} in list is equal to this {@link ContentType}) is found <code>NULL</code> is - * returned. - * - * @param toMatchContentTypes list of {@link ContentType}s which are matches against this {@link ContentType} - * @return best matched content type in list or <code>NULL</code> if none content type match to this content type - * instance - */ - public ContentType matchCompatible(final List<ContentType> toMatchContentTypes) { - for (ContentType supportedContentType : toMatchContentTypes) { - if (isCompatible(supportedContentType)) { - if (compareWildcardCounts(supportedContentType) < 0) { - return this; - } else { - return supportedContentType; - } - } - } - return null; - } - - /** - * Check if a valid compatible match for this {@link ContentType} exists in given list. - * Compatible in this case means that <b>all set parameters are ignored</b>. - * For more detail what a valid match is see {@link #matchCompatible(List)}. - * - * @param toMatchContentTypes list of {@link ContentType}s which are matches against this {@link ContentType} - * @return <code>true</code> if a compatible content type was found in given list - * or <code>false</code> if none compatible content type match was found - */ - public boolean hasCompatible(final List<ContentType> toMatchContentTypes) { - return matchCompatible(toMatchContentTypes) != null; - } - - /** - * Check if a valid match for this {@link ContentType} exists in given list. - * For more detail what a valid match is see {@link #match(List)}. - * - * @param toMatchContentTypes list of {@link ContentType}s which are matches against this {@link ContentType} - * @return <code>true</code> if a matching content type was found in given list - * or <code>false</code> if none matching content type match was found - */ - public boolean hasMatch(final List<ContentType> toMatchContentTypes) { - return match(toMatchContentTypes) != null; - } - - /** - * Compare wildcards counts/weights of both {@link ContentType}. - * - * The smaller {@link ContentType} has lesser weighted wildcards then the bigger {@link ContentType}. - * As result this method returns this object weighted wildcards minus the given parameter object weighted wildcards. - * - * A type wildcard is weighted with <code>2</code> and a subtype wildcard is weighted with <code>1</code>. - * - * @param otherContentType {@link ContentType} to be compared to - * @return this object weighted wildcards minus the given parameter object weighted wildcards. - */ - public int compareWildcardCounts(final ContentType otherContentType) { - return countWildcards() - otherContentType.countWildcards(); - } - - private int countWildcards() { - int count = 0; - if (MEDIA_TYPE_WILDCARD.equals(type)) { - count += 2; - } - if (MEDIA_TYPE_WILDCARD.equals(subtype)) { - count++; - } - return count; - } - - /** - * - * @return <code>true</code> if <code>type</code> or <code>subtype</code> of this instance is a "*". - */ - public boolean hasWildcard() { - return (MEDIA_TYPE_WILDCARD.equals(type) || MEDIA_TYPE_WILDCARD.equals(subtype)); - } - - /** - * - * @return <code>true</code> if both <code>type</code> and <code>subtype</code> of this instance are a "*". - */ - public boolean isWildcard() { - return (MEDIA_TYPE_WILDCARD.equals(type) && MEDIA_TYPE_WILDCARD.equals(subtype)); - } - - public static List<ContentType> convert(final List<String> types) { - List<ContentType> results = new ArrayList<ContentType>(); - for (String contentType : types) { - results.add(ContentType.create(contentType)); - } - return results; - } - - /** - * Check if a valid match for given content type formated string (<code>toMatch</code>) exists in given list. - * Therefore the given content type formated string (<code>toMatch</code>) is converted into a {@link ContentType} - * with a simple {@link #create(String)} call (during which an exception can occur). - * - * For more detail in general see {@link #hasMatch(List)} and for what a valid match is see {@link #match(List)}. - * - * @param toMatch content type formated string (<code>toMatch</code>) for which is checked if a match exists in given - * list - * @param matchExamples list of {@link ContentType}s which are matches against content type formated string - * (<code>toMatch</code>) - * @return <code>true</code> if a matching content type was found in given list - * or <code>false</code> if none matching content type match was found - */ - public static boolean match(final String toMatch, final ContentType... matchExamples) { - ContentType toMatchContentType = ContentType.create(toMatch); - - return toMatchContentType.hasMatch(Arrays.asList(matchExamples)); - } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce359852/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ODataFormat.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ODataFormat.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ODataFormat.java index bc122e2..d1e3cc1 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ODataFormat.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/format/ODataFormat.java @@ -57,25 +57,25 @@ public enum ODataFormat { private static final String JSON_METADATA_PARAMETER_V4 = "odata.metadata"; private static final Map<ODataServiceVersion, Map<ODataFormat, ContentType>> FORMAT_PER_VERSION = new - HashMap<ODataServiceVersion, Map<ODataFormat, ContentType>>(); + HashMap<ODataServiceVersion, Map<ODataFormat, ContentType>>(); static { final Map<ODataFormat, ContentType> v3 = new HashMap<ODataFormat, ContentType>(); v3.put(ODataFormat.JSON_NO_METADATA, ContentType.create( - ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V3, "nometadata")); + ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V3, "nometadata")); v3.put(ODataFormat.JSON, ContentType.create( - ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V3, "minimalmetadata")); + ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V3, "minimalmetadata")); v3.put(ODataFormat.JSON_FULL_METADATA, ContentType.create( - ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V3, "fullmetadata")); + ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V3, "fullmetadata")); FORMAT_PER_VERSION.put(ODataServiceVersion.V30, v3); final Map<ODataFormat, ContentType> v4 = new HashMap<ODataFormat, ContentType>(); v4.put(ODataFormat.JSON_NO_METADATA, ContentType.create( - ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V4, "none")); + ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V4, "none")); v4.put(ODataFormat.JSON, ContentType.create( - ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V4, "minimal")); + ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V4, "minimal")); v4.put(ODataFormat.JSON_FULL_METADATA, ContentType.create( - ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V4, "full")); + ContentType.APPLICATION_JSON, JSON_METADATA_PARAMETER_V4, "full")); FORMAT_PER_VERSION.put(ODataServiceVersion.V40, v4); } @@ -121,12 +121,9 @@ public enum ODataFormat { if (contentType == null) { return null; } - if (contentType.hasWildcard()) { - throw new IllegalArgumentException("Content Type must be fully specified!"); - } if (contentType.isCompatible(ContentType.APPLICATION_ATOM_XML) - || contentType.isCompatible(ContentType.APPLICATION_ATOM_SVC)) { + || contentType.isCompatible(ContentType.APPLICATION_ATOM_SVC)) { return ATOM; } else if (contentType.isCompatible(ContentType.APPLICATION_XML)) { return XML; @@ -135,8 +132,8 @@ public enum ODataFormat { if (jsonVariant != null) { for (ODataFormat candidate : FORMAT_PER_VERSION.get(ODataServiceVersion.V30).keySet()) { if (FORMAT_PER_VERSION.get(ODataServiceVersion.V30).get(candidate).getParameters() - .get(JSON_METADATA_PARAMETER_V3) - .equals(jsonVariant)) { + .get(JSON_METADATA_PARAMETER_V3) + .equals(jsonVariant)) { return candidate; } } @@ -145,8 +142,8 @@ public enum ODataFormat { if (jsonVariant != null) { for (ODataFormat candidate : FORMAT_PER_VERSION.get(ODataServiceVersion.V40).keySet()) { if (FORMAT_PER_VERSION.get(ODataServiceVersion.V40).get(candidate).getParameters() - .get(JSON_METADATA_PARAMETER_V4) - .equals(jsonVariant)) { + .get(JSON_METADATA_PARAMETER_V4) + .equals(jsonVariant)) { return candidate; } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce359852/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractValue.java ---------------------------------------------------------------------- diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractValue.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractValue.java index 2d91ffd..79566bb 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractValue.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractValue.java @@ -69,11 +69,6 @@ public abstract class AbstractValue implements Value { } @Override - public NullValue asNull() { - return isNull() ? (NullValue) this : null; - } - - @Override public PrimitiveValue asPrimitive() { return isPrimitive() ? (PrimitiveValue) this : null; }
