1 /*
2 * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/function/ext/LocaleFunctionSupport.java,v 1.10 2006/02/05 21:47:42 elharo Exp $
3 * $Revision: 1.10 $
4 * $Date: 2006/02/05 21:47:42 $
5 *
6 * ====================================================================
7 *
8 * Copyright 2000-2002 bob mcwhirter & James Strachan.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are
13 * met:
14 *
15 * * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * * Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * * Neither the name of the Jaxen Project nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
27 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
29 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
30 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 *
38 * ====================================================================
39 * This software consists of voluntary contributions made by many
40 * individuals on behalf of the Jaxen Project and was originally
41 * created by bob mcwhirter <bob@werken.com> and
42 * James Strachan <jstrachan@apache.org>. For more information on the
43 * Jaxen Project, please see <http://www.jaxen.org/>.
44 *
45 * $Id: LocaleFunctionSupport.java,v 1.10 2006/02/05 21:47:42 elharo Exp $
46 */
47
48 package org.jaxen.function.ext;
49
50 import java.util.List;
51 import java.util.Locale;
52 import java.util.StringTokenizer;
53
54 import org.jaxen.Function;
55 import org.jaxen.Navigator;
56 import org.jaxen.function.StringFunction;
57
58 /***
59 * <p>An abstract base class for Locale-specific extension
60 * functions. This class provides convenience methods that
61 * can be inherited, specifically to find a Locale from
62 * an XPath function argument value.
63 * </p>
64 *
65 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
66 */
67 public abstract class LocaleFunctionSupport implements Function
68 {
69
70 /***
71 * Attempts to convert the given function argument value
72 * into a Locale either via casting, extracting it from a List
73 * or looking up the named Locale using reflection.
74 *
75 * @param value is either a Locale, a List containing a Locale
76 * or a String containing the name of a Locale
77 * as defined by the Locale static members.
78 *
79 * @return the Locale for the value or null if one could
80 * not be deduced
81 */
82 protected Locale getLocale(Object value, Navigator navigator)
83 {
84 if (value instanceof Locale)
85 {
86 return (Locale) value;
87 }
88 else if(value instanceof List)
89 {
90 List list = (List) value;
91 if ( ! list.isEmpty() )
92 {
93 return getLocale( list.get(0), navigator );
94 }
95 }
96 else {
97 String text = StringFunction.evaluate( value, navigator );
98 if (text != null && text.length() > 0)
99 {
100 return findLocale( text );
101 }
102 }
103 return null;
104 }
105
106 /***
107 * Tries to find a Locale instance by name using
108 * <a href="http://www.ietf.org/rfc/rfc3066.txt" target="_top">RFC 3066</a>
109 * language tags such as 'en', 'en-US', 'en-US-Brooklyn'.
110 *
111 * @param localeText the RFC 3066 language tag
112 * @return the locale for the given text or null if one could not
113 * be found
114 */
115 protected Locale findLocale(String localeText) {
116 StringTokenizer tokens = new StringTokenizer( localeText, "-" );
117 if (tokens.hasMoreTokens())
118 {
119 String language = tokens.nextToken();
120 if (! tokens.hasMoreTokens())
121 {
122 return findLocaleForLanguage(language);
123 }
124 else
125 {
126 String country = tokens.nextToken();
127 if (! tokens.hasMoreTokens())
128 {
129 return new Locale(language, country);
130 }
131 else
132 {
133 String variant = tokens.nextToken();
134 return new Locale(language, country, variant);
135 }
136 }
137 }
138 return null;
139 }
140
141 /***
142 * Finds the locale with the given language name with no country
143 * or variant, such as Locale.ENGLISH or Locale.FRENCH
144 *
145 * @param language the language code to look for
146 * @return the locale for the given language or null if one could not
147 * be found
148 */
149 protected Locale findLocaleForLanguage(String language) {
150 Locale[] locales = Locale.getAvailableLocales();
151 for ( int i = 0, size = locales.length; i < size; i++ )
152 {
153 Locale locale = locales[i];
154 if ( language.equals( locale.getLanguage() ) )
155 {
156 String country = locale.getCountry();
157 if ( country == null || country.length() == 0 )
158 {
159 String variant = locale.getVariant();
160 if ( variant == null || variant.length() == 0 )
161 {
162 return locale;
163 }
164 }
165 }
166 }
167 return null;
168 }
169 }