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 = ( "&#42;/&#42;"
+ *               / ( type "/" "&#42;" )
+ *               / ( 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 = ( "&#42;/&#42;"
- *               / ( type "/" "&#42;" )
- *               / ( 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;
   }

Reply via email to