View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *  http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.any23.http;
    19
    20  import org.apache.any23.mime.MIMEType;
    21
    22  import java.util.ArrayList;
    23  import java.util.Collection;
    24  import java.util.Collections;
    25  import java.util.HashMap;
    26  import java.util.Iterator;
    27  import java.util.List;
    28  import java.util.Map;
    29
    30  /**
    31   * Concatenates a collection of MIME specs in "type/subtype;q=x.x" notation into an HTTP Accept header value, and
    32   * removes duplicates and types covered by wildcards. For example, if the type list contains "text/*;q=0.5", then
    33   * "text/plain;q=0.1" in the list will be ignored because it's already covered by the wildcard with a higher q value.
    34   *
    35   * @author Richard Cyganiak (richard@cyganiak.de)
    36   */
    37  public class AcceptHeaderBuilder {
    38
    39      private Collection<MIMEType> mimeTypes;
    40
    41      private MIMEType highestAnyType = null;
    42
    43      private Map<String, MIMEType> highestAnySubtype = new HashMap<String, MIMEType>();
    44
    45      private Map<String, MIMEType> highestSpecificType = new HashMap<String, MIMEType>();
    46
    47      public static AcceptHeaderBuilder fromStrings(Collection<String> typesAsStrings) {
    48          Collection<MIMEType> types = new ArrayList<MIMEType>(typesAsStrings.size());
    49          for (String type : typesAsStrings) {
    50              types.add(MIMEType.parse(type));
    51          }
    52          return new AcceptHeaderBuilder(types);
    53      }
    54
    55      public AcceptHeaderBuilder(Collection<MIMEType> mimeTypes) {
    56          this.mimeTypes = mimeTypes;
    57      }
    58
    59      /**
    60       * Builds and returns an accept header.
    61       *
    62       * @return the accept header.
    63       */
    64      public String getAcceptHeader() {
    65          if (mimeTypes.isEmpty())
    66              return null;
    67          for (MIMEType mimeType : mimeTypes) {
    68              add(mimeType);
    69          }
    70          removeSpecificTypesCoveredByWildcard();
    71          removeTypesCoveredByWildcard();
    72          List<MIMEType> highest = new ArrayList<MIMEType>();
    73          if (highestAnyType != null) {
    74              highest.add(highestAnyType);
    75          }
    76          highest.addAll(highestAnySubtype.values());
    77          highest.addAll(highestSpecificType.values());
    78          Collections.sort(highest);
    79          StringBuffer result = new StringBuffer();
    80          Iterator<MIMEType> it = mimeTypes.iterator();
    81          while (it.hasNext()) {
    82              MIMEType a = it.next();
    83              if (!highest.contains(a))
    84                  continue;
    85              if (result.length() > 0) {
    86                  result.append(", ");
    87              }
    88              result.append(a);
    89          }
    90          return result.toString();
    91      }
    92
    93      private void add(MIMEType newAccept) {
    94          if (newAccept.isAnyMajorType()) {
    95              if (highestAnyType == null || newAccept.getQuality() > highestAnyType.getQuality()) {
    96                  highestAnyType = newAccept;
    97              }
    98          } else if (newAccept.isAnySubtype()) {
    99              if (!highestAnySubtype.containsKey(newAccept.getMajorType())
    100                     || newAccept.getQuality() > highestAnySubtype.get(newAccept.getMajorType()).getQuality()) {
    101                 highestAnySubtype.put(newAccept.getMajorType(), newAccept);
    102             }
    103         } else {
    104             if (!highestSpecificType.containsKey(newAccept.getFullType())
    105                     || newAccept.getQuality() > highestSpecificType.get(newAccept.getFullType()).getQuality()) {
    106                 highestSpecificType.put(newAccept.getFullType(), newAccept);
    107             }
    108         }
    109     }
    110
    111     private void removeSpecificTypesCoveredByWildcard() {
    112         for (MIMEType accept : highestSpecificType.values()) {
    113             if (highestAnySubtype.containsKey(accept.getMajorType())
    114                     && accept.getQuality() <= highestAnySubtype.get(accept.getMajorType()).getQuality()) {
    115                 highestSpecificType.remove(accept.getFullType());
    116             }
    117         }
    118         if (highestAnyType == null)
    119             return;
    120         for (MIMEType accept : highestSpecificType.values()) {
    121             if (accept.getQuality() <= highestAnyType.getQuality()) {
    122                 highestSpecificType.remove(accept.getFullType());
    123             }
    124         }
    125     }
    126
    127     private void removeTypesCoveredByWildcard() {
    128         if (highestAnyType == null)
    129             return;
    130         for (MIMEType accept : highestAnySubtype.values()) {
    131             if (accept.getQuality() <= highestAnyType.getQuality()) {
    132                 highestAnySubtype.remove(accept.getMajorType());
    133             }
    134         }
    135     }
    136
    137 }