Coverage Report - org.codehaus.plexus.i18n.I18NTokenizer
 
Classes in this File Line Coverage Branch Coverage Complexity
I18NTokenizer
85 %
24/28
66 %
8/12
2,6
I18NTokenizer$1
N/A
N/A
2,6
I18NTokenizer$AcceptLanguage
100 %
3/3
N/A
2,6
 
 1  
 package org.codehaus.plexus.i18n;
 2  
 
 3  
 /*
 4  
  * Copyright 2001-2007 Codehaus Foundation.
 5  
  *
 6  
  * Licensed under the Apache License, Version 2.0 (the "License");
 7  
  * you may not use this file except in compliance with the License.
 8  
  * You may obtain a copy of the License at
 9  
  *
 10  
  *      http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  
  * See the License for the specific language governing permissions and
 16  
  * limitations under the License.
 17  
  */
 18  
 
 19  
 import java.util.ArrayList;
 20  
 import java.util.Collections;
 21  
 import java.util.Iterator;
 22  
 import java.util.Locale;
 23  
 import java.util.NoSuchElementException;
 24  
 import java.util.StringTokenizer;
 25  
 
 26  
 /**
 27  
  * Parses the HTTP <code>Accept-Language</code> header as per section
 28  
  * 14.4 of RFC 2068 (HTTP 1.1 header field definitions).
 29  
  *
 30  
  * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
 31  
  * @version $Id: I18NTokenizer.java 6675 2007-07-20 23:05:53Z olamy $
 32  
  *
 33  
  * @todo Move this class out of here as its purely web related.
 34  
  */
 35  3
 public class I18NTokenizer
 36  
     implements Iterator
 37  
 {
 38  
     /**
 39  
      * Separates elements of the <code>Accept-Language</code> HTTP
 40  
      * header.
 41  
      */
 42  
     private static final String LOCALE_SEPARATOR = ",";
 43  
 
 44  
     /**
 45  
      * Separates locale from quality within elements.
 46  
      */
 47  
     private static final char QUALITY_SEPARATOR = ';';
 48  
 
 49  
     /**
 50  
      * The default quality value for an <code>AcceptLanguage</code>
 51  
      * object.
 52  
      */
 53  1
     private static final Float DEFAULT_QUALITY = new Float(1.0f);
 54  
 
 55  
     /**
 56  
      * The parsed locales.
 57  
      */
 58  1
     private ArrayList locales = new ArrayList(3);
 59  
 
 60  
     /**
 61  
      * Parses the <code>Accept-Language</code> header.
 62  
      *
 63  
      * @param header The <code>Accept-Language</code> header
 64  
      * (i.e. <code>en, es;q=0.8, zh-TW;q=0.1</code>).
 65  
      */
 66  
     public I18NTokenizer(String header)
 67  1
     {
 68  1
         StringTokenizer tok = new StringTokenizer(header, LOCALE_SEPARATOR);
 69  4
         while (tok.hasMoreTokens())
 70  
         {
 71  3
             AcceptLanguage acceptLang = new AcceptLanguage();
 72  3
             String element = tok.nextToken().trim();
 73  
             int index;
 74  
 
 75  
             // Record and cut off any quality value that comes after a
 76  
             // semi-colon.
 77  3
             if ( (index = element.indexOf(QUALITY_SEPARATOR)) != -1 )
 78  
             {
 79  2
                 String q = element.substring(index);
 80  2
                 element = element.substring(0, index);
 81  2
                 if ( (index = q.indexOf('=')) != -1 )
 82  
                 {
 83  
                     try
 84  
                     {
 85  2
                         acceptLang.quality =
 86  
                             Float.valueOf(q.substring(index + 1));
 87  
                     }
 88  0
                     catch (NumberFormatException useDefault)
 89  
                     {
 90  2
                     }
 91  
                 }
 92  
             }
 93  
 
 94  3
             element = element.trim();
 95  
 
 96  
             // Create a Locale from the language.  A dash may separate the
 97  
             // language from the country.
 98  3
             if ( (index = element.indexOf('-')) == -1 )
 99  
             {
 100  
                 // No dash means no country.
 101  2
                 acceptLang.locale = new Locale(element, "");
 102  
             }
 103  
             else
 104  
             {
 105  1
                 acceptLang.locale = new Locale(element.substring(0, index),
 106  
                                                element.substring(index + 1));
 107  
             }
 108  
 
 109  3
             locales.add(acceptLang);
 110  3
         }
 111  
 
 112  
         // Sort by quality in descending order.
 113  1
         Collections.sort(locales, Collections.reverseOrder());
 114  1
     }
 115  
 
 116  
     /**
 117  
      * @return Whether there are more locales.
 118  
      */
 119  
     public boolean hasNext()
 120  
     {
 121  0
         return !locales.isEmpty();
 122  
     }
 123  
 
 124  
     /**
 125  
      * Creates a <code>Locale</code> from the next element of the
 126  
      * <code>Accept-Language</code> header.
 127  
      *
 128  
      * @return The next highest-rated <code>Locale</code>.
 129  
      * @throws NoSuchElementException No more locales.
 130  
      */
 131  
     public Object next()
 132  
     {
 133  3
         if (locales.isEmpty())
 134  
         {
 135  0
             throw new NoSuchElementException();
 136  
         }
 137  3
         return ((AcceptLanguage) locales.remove(0)).locale;
 138  
     }
 139  
 
 140  
     /**
 141  
      * Not implemented.
 142  
      */
 143  
     public final void remove()
 144  
     {
 145  0
         throw new UnsupportedOperationException(getClass().getName() +
 146  
                                                 " does not support remove()");
 147  
     }
 148  
 
 149  
     /**
 150  
      * Struct representing an element of the HTTP
 151  
      * <code>Accept-Language</code> header.
 152  
      */
 153  6
     private class AcceptLanguage implements Comparable
 154  
     {
 155  
         /**
 156  
          * The language and country.
 157  
          */
 158  
         Locale locale;
 159  
 
 160  
         /**
 161  
          * The quality of our locale (as values approach
 162  
          * <code>1.0</code>, they indicate increased user preference).
 163  
          */
 164  3
         Float quality = DEFAULT_QUALITY;
 165  
 
 166  
         public final int compareTo(Object acceptLang)
 167  
         {
 168  2
             return quality.compareTo( ((AcceptLanguage) acceptLang).quality );
 169  
         }
 170  
     }
 171  
 }