This project has retired. For details please refer to its Attic page.
PostfixedApplicationResource xref
View Javadoc

1   /*
2    * $Id$
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package org.apache.tiles.request.locale;
23  
24  import java.util.Arrays;
25  import java.util.HashSet;
26  import java.util.List;
27  import java.util.Set;
28  import java.util.Locale;
29  import org.apache.tiles.request.ApplicationResource;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  
33  /**
34   * An ApplicationResource whose localization is managed by postfixing the file name.
35   * The various localizations are file sitting next to each other, with the locale identified in the postfix.
36   *
37   * For instance:
38   * <pre>
39   * /WEB-INF/tiles.xml
40   * /WEB-INF/tiles_fr.xml
41   * /WEB-INF/tiles_it.xml
42   * /WEB-INF/tiles_it_IT.xml
43   * </pre>
44   *
45   * Two PostfixedApplicationResources are equals if they share the same localized path and the same class.
46   *
47   * @version $Rev$ $Date$
48   */
49  public abstract class PostfixedApplicationResource implements ApplicationResource {
50  
51      private static final Logger LOG = LoggerFactory.getLogger(PostfixedApplicationResource.class);
52  
53      /** The path without its suffix and its locale postfix. */
54      private String pathPrefix;
55      /** The suffix. */
56      private String suffix;
57      /** The Locale. */
58      private Locale locale;
59  
60      /**
61       * Create a new PostfixedApplicationResource for the specified path.
62       * @param localePath the path including localization.
63       */
64      protected PostfixedApplicationResource(String localePath) {
65          int prefixIndex = localePath.indexOf('_', localePath.lastIndexOf("/"));
66          int suffixIndex = localePath.lastIndexOf('.');
67          if (suffixIndex < 0) {
68              suffix = "";
69              suffixIndex = localePath.length();
70          } else {
71              suffix = localePath.substring(suffixIndex);
72          }
73          if (prefixIndex < 0) {
74              pathPrefix = localePath.substring(0, suffixIndex);
75              locale = Locale.ROOT;
76          } else {
77              pathPrefix = localePath.substring(0, prefixIndex);
78              String localeString = localePath.substring(prefixIndex + 1, suffixIndex);
79              Locale found = localeFrom(localeString);
80              locale = validateLocale(found);
81              if (Locale.ROOT.equals(locale)) {
82                  pathPrefix = suffixIndex < 0 ? localePath : localePath.substring(0, suffixIndex);
83  
84                  LOG.warn("No supported matching language for locale \"" + localeString + "\". Using "
85                          + getPath() + " as a non-localized resource path. see TILES-571");
86  
87              } else if (!localeString.equalsIgnoreCase(getPostfix(locale).substring(1))) {
88                  LOG.warn("For resource " + localePath
89                          + " the closest supported matching locale to \"" + localeString + "\" is \"" + locale
90                          + "\". Using " + getPath() + " as resource path. see TILES-571");
91              }
92          }
93      }
94  
95      /**
96       * Create a new PostfixedApplicationResource for the specified path.
97       * @param path the path excluding localization.
98       * @param locale the Locale.
99       */
100     protected PostfixedApplicationResource(String path, Locale locale) {
101         int suffixIndex = path.lastIndexOf('.');
102         if (suffixIndex < 0) {
103             suffix = "";
104             pathPrefix = path;
105         } else {
106             pathPrefix = path.substring(0, suffixIndex);
107             suffix = path.substring(suffixIndex);
108         }
109         this.locale = locale;
110     }
111 
112     /** {@inheritDoc} */
113     @Override
114     public final String getLocalePath() {
115         return getLocalePath(locale);
116     }
117 
118     /** {@inheritDoc} */
119     @Override
120     public final String getPath() {
121         return pathPrefix + suffix;
122     }
123 
124     /** {@inheritDoc} */
125     @Override
126     public final String getLocalePath(Locale newLocale) {
127         return pathPrefix + getPostfix(newLocale) + suffix;
128     }
129 
130     /**
131      * Get the postfix for that Locale.
132      * @param locale a locale.
133      * @return the matching postfix.
134      */
135     private static final String getPostfix(Locale locale) {
136         if (locale == null) {
137             return "";
138         }
139 
140         StringBuilder builder = new StringBuilder();
141         String language = locale.getLanguage();
142         String country = locale.getCountry();
143         String variant = locale.getVariant();
144         if (!"".equals(language)) {
145             builder.append("_");
146             builder.append(language);
147             if (!"".equals(country)) {
148                 builder.append("_");
149                 builder.append(country);
150                 if (!"".equals(variant)) {
151                     builder.append("_");
152                     builder.append(variant);
153                 }
154             }
155         }
156         return builder.toString();
157     }
158 
159     /** {@inheritDoc} */
160     @Override
161     public final Locale getLocale() {
162         return locale;
163     }
164 
165     /** {@inheritDoc} */
166     @Override
167     public int hashCode() {
168         final int prime = 31;
169         int result = 1;
170         result = prime * result + ((locale == null) ? 0 : locale.hashCode());
171         result = prime * result + ((pathPrefix == null) ? 0 : pathPrefix.hashCode());
172         result = prime * result + ((suffix == null) ? 0 : suffix.hashCode());
173         return result;
174     }
175 
176     /** {@inheritDoc} */
177     @Override
178     public boolean equals(Object obj) {
179         if (this == obj)
180             return true;
181         if (obj == null)
182             return false;
183         if (getClass() != obj.getClass())
184             return false;
185         PostfixedApplicationResource other = (PostfixedApplicationResource) obj;
186         if (locale == null) {
187             if (other.locale != null)
188                 return false;
189         } else if (!locale.equals(other.locale))
190             return false;
191         if (pathPrefix == null) {
192             if (other.pathPrefix != null)
193                 return false;
194         } else if (!pathPrefix.equals(other.pathPrefix))
195             return false;
196         if (suffix == null) {
197             if (other.suffix != null)
198                 return false;
199         } else if (!suffix.equals(other.suffix))
200             return false;
201         return true;
202     }
203 
204     private static Locale localeFrom(String localeString) {
205         Locale result;
206         int countryIndex = localeString.indexOf('_');
207         if (countryIndex < 0) {
208             result = new Locale(localeString);
209         } else {
210             int variantIndex = localeString.indexOf('_', countryIndex + 1);
211             if (variantIndex < 0) {
212                 result = new Locale(
213                         localeString.substring(0, countryIndex),
214                         localeString.substring(countryIndex + 1));
215             } else {
216                 result = new Locale(
217                         localeString.substring(0, countryIndex),
218                         localeString.substring(countryIndex + 1, variantIndex),
219                         localeString.substring(variantIndex + 1));
220             }
221         }
222         return result;
223     }
224     /*
225     private static Locale java7_localeFrom(String localeString) {
226         Locale.Builder builder = new Locale.Builder();
227         try {
228             int countryIndex = localeString.indexOf('_');
229             if (countryIndex < 0) {
230                 builder.setLanguage(localeString);
231             } else {
232                 int variantIndex = localeString.indexOf('_', countryIndex + 1);
233                 builder.setLanguage(localeString.substring(0, countryIndex));
234                 if (variantIndex < 0) {
235                     builder.setRegion(localeString.substring(countryIndex + 1));
236                 } else {
237                     builder.setRegion(localeString.substring(countryIndex + 1, variantIndex));
238                     builder.setVariant(localeString.substring(variantIndex + 1));
239                 }
240             }
241         } catch (IllformedLocaleException ex) {
242             LOG.debug(localeString + " is an ill-formed locale", ex);
243         }
244         return builder.build();
245     }
246     */
247 
248     private static Set<Locale> availableLocales = new HashSet<Locale>(Arrays.asList(Locale.getAvailableLocales()));
249 
250     private static Locale validateLocale(Locale locale) {
251         Locale withoutVariant = locale.getVariant().isEmpty()
252                 ? locale
253                 : new Locale(locale.getLanguage(), locale.getCountry());
254 
255         Locale result = locale;
256         if (!availableLocales.contains(withoutVariant)) {
257             if (!result.getCountry().isEmpty()) {
258                 result = new Locale(result.getLanguage());
259             }
260             if (!availableLocales.contains(result)) {
261                 result = Locale.ROOT;
262             }
263         }
264         return result;
265     }
266 }