KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > taglibs > standard > tag > common > fmt > SetLocaleSupport


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.taglibs.standard.tag.common.fmt;
18
19 import java.text.DateFormat JavaDoc;
20 import java.text.NumberFormat JavaDoc;
21 import java.util.Enumeration JavaDoc;
22 import java.util.Locale JavaDoc;
23 import java.util.Vector JavaDoc;
24
25 import javax.servlet.ServletResponse JavaDoc;
26 import javax.servlet.http.HttpServletRequest JavaDoc;
27 import javax.servlet.jsp.JspException JavaDoc;
28 import javax.servlet.jsp.PageContext JavaDoc;
29 import javax.servlet.jsp.jstl.core.Config;
30 import javax.servlet.jsp.jstl.fmt.LocalizationContext;
31 import javax.servlet.jsp.tagext.Tag JavaDoc;
32 import javax.servlet.jsp.tagext.TagSupport JavaDoc;
33
34 import org.apache.taglibs.standard.resources.Resources;
35 import org.apache.taglibs.standard.tag.common.core.Util;
36
37 /**
38  * Support for tag handlers for <setLocale>, the locale setting tag in
39  * JSTL 1.0.
40  *
41  * @author Jan Luehe
42  */

43
44 public abstract class SetLocaleSupport extends TagSupport JavaDoc {
45
46     
47     //*********************************************************************
48
// Private constants
49

50     private static final char HYPHEN = '-';
51     private static final char UNDERSCORE = '_';
52
53
54     //*********************************************************************
55
// Protected state
56

57     protected Object JavaDoc value; // 'value' attribute
58
protected String JavaDoc variant; // 'variant' attribute
59

60
61     //*********************************************************************
62
// Private state
63

64     private int scope; // 'scope' attribute
65

66
67     //*********************************************************************
68
// Constructor and initialization
69

70     public SetLocaleSupport() {
71     super();
72     init();
73     }
74
75     private void init() {
76     value = variant = null;
77     scope = PageContext.PAGE_SCOPE;
78     }
79
80
81    //*********************************************************************
82
// Tag attributes known at translation time
83

84     public void setScope(String JavaDoc scope) {
85     this.scope = Util.getScope(scope);
86     }
87
88
89     //*********************************************************************
90
// Tag logic
91

92     public int doEndTag() throws JspException JavaDoc {
93     Locale JavaDoc locale = null;
94
95     if (value == null) {
96         locale = Locale.getDefault();
97     } else if (value instanceof String JavaDoc) {
98         if (((String JavaDoc) value).trim().equals("")) {
99         locale = Locale.getDefault();
100         } else {
101         locale = parseLocale((String JavaDoc) value, variant);
102         }
103     } else {
104         locale = (Locale JavaDoc) value;
105     }
106
107     Config.set(pageContext, Config.FMT_LOCALE, locale, scope);
108     setResponseLocale(pageContext, locale);
109
110     return EVAL_PAGE;
111     }
112
113     // Releases any resources we may have (or inherit)
114
public void release() {
115     init();
116     }
117
118
119     //*********************************************************************
120
// Public utility methods
121

122     /**
123      * See parseLocale(String, String) for details.
124      */

125     public static Locale JavaDoc parseLocale(String JavaDoc locale) {
126     return parseLocale(locale, null);
127     }
128
129     /**
130      * Parses the given locale string into its language and (optionally)
131      * country components, and returns the corresponding
132      * <tt>java.util.Locale</tt> object.
133      *
134      * If the given locale string is null or empty, the runtime's default
135      * locale is returned.
136      *
137      * @param locale the locale string to parse
138      * @param variant the variant
139      *
140      * @return <tt>java.util.Locale</tt> object corresponding to the given
141      * locale string, or the runtime's default locale if the locale string is
142      * null or empty
143      *
144      * @throws IllegalArgumentException if the given locale does not have a
145      * language component or has an empty country component
146      */

147     public static Locale JavaDoc parseLocale(String JavaDoc locale, String JavaDoc variant) {
148
149     Locale JavaDoc ret = null;
150     String JavaDoc language = locale;
151     String JavaDoc country = null;
152     int index = -1;
153
154     if (((index = locale.indexOf(HYPHEN)) > -1)
155             || ((index = locale.indexOf(UNDERSCORE)) > -1)) {
156         language = locale.substring(0, index);
157         country = locale.substring(index+1);
158     }
159
160     if ((language == null) || (language.length() == 0)) {
161         throw new IllegalArgumentException JavaDoc(
162         Resources.getMessage("LOCALE_NO_LANGUAGE"));
163     }
164
165     if (country == null) {
166         if (variant != null)
167         ret = new Locale JavaDoc(language, "", variant);
168         else
169         ret = new Locale JavaDoc(language, "");
170     } else if (country.length() > 0) {
171         if (variant != null)
172         ret = new Locale JavaDoc(language, country, variant);
173         else
174         ret = new Locale JavaDoc(language, country);
175     } else {
176         throw new IllegalArgumentException JavaDoc(
177         Resources.getMessage("LOCALE_EMPTY_COUNTRY"));
178     }
179
180     return ret;
181     }
182
183
184     //*********************************************************************
185
// Package-scoped utility methods
186

187     /*
188      * Stores the given locale in the response object of the given page
189      * context, and stores the locale's associated charset in the
190      * javax.servlet.jsp.jstl.fmt.request.charset session attribute, which
191      * may be used by the <requestEncoding> action in a page invoked by a
192      * form included in the response to set the request charset to the same as
193      * the response charset (this makes it possible for the container to
194      * decode the form parameter values properly, since browsers typically
195      * encode form field values using the response's charset).
196      *
197      * @param pageContext the page context whose response object is assigned
198      * the given locale
199      * @param locale the response locale
200      */

201     static void setResponseLocale(PageContext JavaDoc pc, Locale JavaDoc locale) {
202     // set response locale
203
ServletResponse JavaDoc response = pc.getResponse();
204     response.setLocale(locale);
205     
206     // get response character encoding and store it in session attribute
207
if (pc.getSession() != null) {
208             try {
209             pc.setAttribute(RequestEncodingSupport.REQUEST_CHAR_SET,
210                 response.getCharacterEncoding(),
211                 PageContext.SESSION_SCOPE);
212             } catch (IllegalStateException JavaDoc ex) {} // invalidated session ignored
213
}
214     }
215  
216     /*
217      * Returns the formatting locale to use with the given formatting action
218      * in the given page.
219      *
220      * @param pc The page context containing the formatting action
221      * @param fromTag The formatting action
222      * @param format <tt>true</tt> if the formatting action is of type
223      * <formatXXX> (as opposed to <parseXXX>), and <tt>false</tt> otherwise
224      * (if set to <tt>true</tt>, the formatting locale that is returned by
225      * this method is used to set the response locale).
226      *
227      * @param avail the array of available locales
228      *
229      * @return the formatting locale to use
230      */

231     static Locale JavaDoc getFormattingLocale(PageContext JavaDoc pc,
232                       Tag JavaDoc fromTag,
233                       boolean format,
234                       Locale JavaDoc[] avail) {
235
236     LocalizationContext locCtxt = null;
237     
238     // Get formatting locale from enclosing <fmt:bundle>
239
Tag JavaDoc parent = findAncestorWithClass(fromTag, BundleSupport.class);
240     if (parent != null) {
241         /*
242          * use locale from localization context established by parent
243          * <fmt:bundle> action, unless that locale is null
244          */

245         locCtxt = ((BundleSupport) parent).getLocalizationContext();
246         if (locCtxt.getLocale() != null) {
247         if (format) {
248             setResponseLocale(pc, locCtxt.getLocale());
249         }
250         return locCtxt.getLocale();
251         }
252     }
253
254     // Use locale from default I18N localization context, unless it is null
255
if ((locCtxt = BundleSupport.getLocalizationContext(pc)) != null) {
256         if (locCtxt.getLocale() != null) {
257         if (format) {
258             setResponseLocale(pc, locCtxt.getLocale());
259         }
260         return locCtxt.getLocale();
261         }
262     }
263
264     /*
265      * Establish formatting locale by comparing the preferred locales
266      * (in order of preference) against the available formatting
267      * locales, and determining the best matching locale.
268      */

269     Locale JavaDoc match = null;
270     Locale JavaDoc pref = getLocale(pc, Config.FMT_LOCALE);
271     if (pref != null) {
272         // Preferred locale is application-based
273
match = findFormattingMatch(pref, avail);
274     } else {
275         // Preferred locales are browser-based
276
match = findFormattingMatch(pc, avail);
277     }
278     if (match == null) {
279         //Use fallback locale.
280
pref = getLocale(pc, Config.FMT_FALLBACK_LOCALE);
281         if (pref != null) {
282         match = findFormattingMatch(pref, avail);
283         }
284     }
285     if (format && (match != null)) {
286         setResponseLocale(pc, match);
287     }
288
289     return match;
290     }
291
292     /**
293      * Setup the available formatting locales that will be used
294      * by getFormattingLocale(PageContext).
295      */

296     static Locale JavaDoc[] availableFormattingLocales;
297     static {
298         Locale JavaDoc[] dateLocales = DateFormat.getAvailableLocales();
299         Locale JavaDoc[] numberLocales = NumberFormat.getAvailableLocales();
300         Vector JavaDoc vec = new Vector JavaDoc(dateLocales.length);
301         for (int i=0; i<dateLocales.length; i++) {
302             for (int j=0; j<numberLocales.length; j++) {
303                 if (dateLocales[i].equals(numberLocales[j])) {
304                     vec.add(dateLocales[i]);
305                     break;
306                 }
307             }
308         }
309         availableFormattingLocales = new Locale JavaDoc[vec.size()];
310         availableFormattingLocales = (Locale JavaDoc[])vec.toArray(availableFormattingLocales);
311         /*
312         for (int i=0; i<availableFormattingLocales.length; i++) {
313             System.out.println("AvailableLocale[" + i + "] " + availableFormattingLocales[i]);
314         }
315         */

316     }
317     
318     /*
319      * Returns the formatting locale to use when <fmt:message> is used
320      * with a locale-less localization context.
321      *
322      * @param pc The page context containing the formatting action
323      * @return the formatting locale to use
324      */

325     static Locale JavaDoc getFormattingLocale(PageContext JavaDoc pc) {
326     /*
327      * Establish formatting locale by comparing the preferred locales
328      * (in order of preference) against the available formatting
329      * locales, and determining the best matching locale.
330      */

331     Locale JavaDoc match = null;
332     Locale JavaDoc pref = getLocale(pc, Config.FMT_LOCALE);
333     if (pref != null) {
334         // Preferred locale is application-based
335
match = findFormattingMatch(pref, availableFormattingLocales);
336     } else {
337         // Preferred locales are browser-based
338
match = findFormattingMatch(pc, availableFormattingLocales);
339     }
340     if (match == null) {
341         //Use fallback locale.
342
pref = getLocale(pc, Config.FMT_FALLBACK_LOCALE);
343         if (pref != null) {
344         match = findFormattingMatch(pref, availableFormattingLocales);
345         }
346     }
347     if (match != null) {
348         setResponseLocale(pc, match);
349     }
350
351     return match;
352     }
353
354     /*
355      * Returns the locale specified by the named scoped attribute or context
356      * configuration parameter.
357      *
358      * <p> The named scoped attribute is searched in the page, request,
359      * session (if valid), and application scope(s) (in this order). If no such
360      * attribute exists in any of the scopes, the locale is taken from the
361      * named context configuration parameter.
362      *
363      * @param pageContext the page in which to search for the named scoped
364      * attribute or context configuration parameter
365      * @param name the name of the scoped attribute or context configuration
366      * parameter
367      *
368      * @return the locale specified by the named scoped attribute or context
369      * configuration parameter, or <tt>null</tt> if no scoped attribute or
370      * configuration parameter with the given name exists
371      */

372     static Locale JavaDoc getLocale(PageContext JavaDoc pageContext, String JavaDoc name) {
373     Locale JavaDoc loc = null;
374
375     Object JavaDoc obj = Config.find(pageContext, name);
376     if (obj != null) {
377         if (obj instanceof Locale JavaDoc) {
378         loc = (Locale JavaDoc) obj;
379         } else {
380         loc = parseLocale((String JavaDoc) obj);
381         }
382     }
383
384     return loc;
385     }
386
387
388     //*********************************************************************
389
// Private utility methods
390

391     /*
392      * Determines the client's preferred locales from the request, and compares
393      * each of the locales (in order of preference) against the available
394      * locales in order to determine the best matching locale.
395      *
396      * @param pageContext Page containing the formatting action
397      * @param avail Available formatting locales
398      *
399      * @return Best matching locale, or <tt>null</tt> if no match was found
400      */

401     private static Locale JavaDoc findFormattingMatch(PageContext JavaDoc pageContext,
402                           Locale JavaDoc[] avail) {
403     Locale JavaDoc match = null;
404     for (Enumeration JavaDoc enum_ = Util.getRequestLocales((HttpServletRequest JavaDoc)pageContext.getRequest());
405          enum_.hasMoreElements(); ) {
406             Locale JavaDoc locale = (Locale JavaDoc)enum_.nextElement();
407         match = findFormattingMatch(locale, avail);
408         if (match != null) {
409         break;
410         }
411     }
412     
413     return match;
414     }
415
416     /*
417      * Returns the best match between the given preferred locale and the
418      * given available locales.
419      *
420      * The best match is given as the first available locale that exactly
421      * matches the given preferred locale ("exact match"). If no exact match
422      * exists, the best match is given to an available locale that meets
423      * the following criteria (in order of priority):
424      * - available locale's variant is empty and exact match for both
425      * language and country
426      * - available locale's variant and country are empty, and exact match
427      * for language.
428      *
429      * @param pref the preferred locale
430      * @param avail the available formatting locales
431      *
432      * @return Available locale that best matches the given preferred locale,
433      * or <tt>null</tt> if no match exists
434      */

435     private static Locale JavaDoc findFormattingMatch(Locale JavaDoc pref, Locale JavaDoc[] avail) {
436     Locale JavaDoc match = null;
437         boolean langAndCountryMatch = false;
438         for (int i=0; i<avail.length; i++) {
439             if (pref.equals(avail[i])) {
440                 // Exact match
441
match = avail[i];
442                 break;
443             } else if (
444                     !"".equals(pref.getVariant()) &&
445                     "".equals(avail[i].getVariant()) &&
446                     pref.getLanguage().equals(avail[i].getLanguage()) &&
447                     pref.getCountry().equals(avail[i].getCountry())) {
448                 // Language and country match; different variant
449
match = avail[i];
450                 langAndCountryMatch = true;
451             } else if (
452                     !langAndCountryMatch &&
453                     pref.getLanguage().equals(avail[i].getLanguage()) &&
454                     ("".equals(avail[i].getCountry()))) {
455                 // Language match
456
if (match == null) {
457                     match = avail[i];
458                 }
459             }
460         }
461     return match;
462     }
463 }
464
Popular Tags