Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
I18NTokenizer |
|
| 2.6;2,6 | ||||
I18NTokenizer$1 |
|
| 2.6;2,6 | ||||
I18NTokenizer$AcceptLanguage |
|
| 2.6;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 | } |