001package org.apache.turbine.util;
002
003import java.nio.charset.Charset;
004import java.nio.charset.IllegalCharsetNameException;
005import java.nio.charset.StandardCharsets;
006import java.nio.charset.UnsupportedCharsetException;
007
008/*
009 * Licensed to the Apache Software Foundation (ASF) under one
010 * or more contributor license agreements.  See the NOTICE file
011 * distributed with this work for additional information
012 * regarding copyright ownership.  The ASF licenses this file
013 * to you under the Apache License, Version 2.0 (the
014 * "License"); you may not use this file except in compliance
015 * with the License.  You may obtain a copy of the License at
016 *
017 *   http://www.apache.org/licenses/LICENSE-2.0
018 *
019 * Unless required by applicable law or agreed to in writing,
020 * software distributed under the License is distributed on an
021 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
022 * KIND, either express or implied.  See the License for the
023 * specific language governing permissions and limitations
024 * under the License.
025 */
026
027import java.util.Locale;
028
029import org.apache.commons.lang3.StringUtils;
030import org.apache.fulcrum.mimetype.MimeTypeService;
031import org.apache.logging.log4j.LogManager;
032import org.apache.logging.log4j.Logger;
033import org.apache.turbine.Turbine;
034import org.apache.turbine.TurbineConstants;
035import org.apache.turbine.services.ServiceManager;
036import org.apache.turbine.services.TurbineServices;
037/*
038 * Licensed to the Apache Software Foundation (ASF) under one
039 * or more contributor license agreements.  See the NOTICE file
040 * distributed with this work for additional information
041 * regarding copyright ownership.  The ASF licenses this file
042 * to you under the Apache License, Version 2.0 (the
043 * "License"); you may not use this file except in compliance
044 * with the License.  You may obtain a copy of the License at
045 *
046 *   http://www.apache.org/licenses/LICENSE-2.0
047 *
048 * Unless required by applicable law or agreed to in writing,
049 * software distributed under the License is distributed on an
050 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
051 * KIND, either express or implied.  See the License for the
052 * specific language governing permissions and limitations
053 * under the License.
054 */
055
056/**
057 * This class provides utilities for handling locales and charsets
058 *
059 * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
060 */
061public class LocaleUtils
062{
063    /** Logging */
064    private static final Logger log = LogManager.getLogger(LocaleUtils.class);
065
066    /** The default locale. */
067    private static Locale defaultLocale = null;
068
069    /** The default charset. */
070    private static Charset defaultCharSet = null;
071
072    /**
073     * Returns the default input encoding for the servlet.
074     *
075     * @return the default input encoding.
076     */
077    public static String getDefaultInputEncoding()
078    {
079        // Get the default input defaultEncoding
080        String inputEncoding = Turbine.getConfiguration()
081                .getString(TurbineConstants.PARAMETER_ENCODING_KEY,
082                        TurbineConstants.PARAMETER_ENCODING_DEFAULT);
083
084        log.debug("Input Encoding has been set to {}", inputEncoding);
085
086        return inputEncoding;
087    }
088
089    /**
090     * Gets the default locale defined by properties named "locale.default.lang"
091     * and "locale.default.country".
092     *
093     * This changed from earlier Turbine versions that you can rely on
094     * getDefaultLocale() to never return null.
095     *
096     * @return A Locale object.
097     */
098    public static Locale getDefaultLocale()
099    {
100        if (defaultLocale == null)
101        {
102            /* Get the default locale and cache it in a static variable. */
103            String lang = Turbine.getConfiguration()
104                    .getString(TurbineConstants.LOCALE_DEFAULT_LANGUAGE_KEY,
105                            TurbineConstants.LOCALE_DEFAULT_LANGUAGE_DEFAULT);
106
107            String country = Turbine.getConfiguration()
108                    .getString(TurbineConstants.LOCALE_DEFAULT_COUNTRY_KEY,
109                            TurbineConstants.LOCALE_DEFAULT_COUNTRY_DEFAULT);
110
111            // We ensure that lang and country is never null
112            defaultLocale = new Locale(lang, country);
113        }
114
115        return defaultLocale;
116    }
117
118    /**
119     * Gets the default charset defined by a property named
120     * "locale.default.charset"
121     *
122     * @return the name of the default charset or null.
123     */
124    @Deprecated
125    public static String getDefaultCharSet()
126    {
127        return getDefaultCharset().name();
128    }
129
130    /**
131     * Gets the default charset defined by a property named
132     * "locale.default.charset"
133     *
134     * @return the default charset, never null.
135     */
136    public static Charset getDefaultCharset()
137    {
138        if (defaultCharSet == null)
139        {
140            /* Get the default charset and cache it in a static variable. */
141            String charSet = Turbine.getConfiguration()
142                    .getString(TurbineConstants.LOCALE_DEFAULT_CHARSET_KEY,
143                            TurbineConstants.LOCALE_DEFAULT_CHARSET_DEFAULT);
144
145            if (StringUtils.isNotEmpty(charSet))
146            {
147                defaultCharSet = charSetForName(charSet);
148                log.debug("defaultCharSet = {} (From Properties)", defaultCharSet);
149            }
150        }
151
152        Charset charset = defaultCharSet;
153
154        if (charset == null) // can happen if set explicitly in the configuration
155        {
156            log.debug("Default charset is empty!");
157            /* Default charset isn't specified, get the locale specific one. */
158            Locale locale = getDefaultLocale();
159            log.debug("Locale is {}", locale);
160
161            if (!locale.equals(Locale.US))
162            {
163                log.debug("We don't have US Locale!");
164                ServiceManager serviceManager = TurbineServices.getInstance();
165                if (serviceManager.isRegistered(MimeTypeService.ROLE))
166                {
167                    try
168                    {
169                        MimeTypeService mimeTypeService = (MimeTypeService) serviceManager.getService(MimeTypeService.ROLE);
170                        charset = charSetForName(mimeTypeService.getCharSet(locale));
171                    }
172                    catch (Exception e)
173                    {
174                        throw new RuntimeException(e);
175                    }
176
177                    log.debug("Charset now {}", charset);
178                }
179            }
180
181            // The fallback to end all fallbacks
182            if (charset == null)
183            {
184                charset = StandardCharsets.ISO_8859_1;
185            }
186        }
187
188        log.debug("Returning default Charset of {}", charset);
189        return charset;
190    }
191
192    /**
193     * Gets the charset defined by a property named "locale.override.charset"
194     * This property has no default. If it exists, the output charset is always
195     * set to its value
196     *
197     * @return the name of the override charset or null.
198     */
199    @Deprecated
200    public static String getOverrideCharSet()
201    {
202        return Turbine.getConfiguration()
203                .getString(TurbineConstants.LOCALE_OVERRIDE_CHARSET_KEY);
204    }
205
206    /**
207     * Gets the charset defined by a property named "locale.override.charset"
208     * This property has no default. If it exists, the output charset is always
209     * set to its value
210     *
211     * @return the override charset or null.
212     */
213    public static Charset getOverrideCharset()
214    {
215        String charset = Turbine.getConfiguration()
216                .getString(TurbineConstants.LOCALE_OVERRIDE_CHARSET_KEY);
217
218        if (StringUtils.isEmpty(charset))
219        {
220            return null;
221        }
222
223        return charSetForName(charset);
224    }
225
226    /**
227     * Get a Charset object for a given name
228     * This method does not throw exceptions on illegal input but returns null.
229     *
230     * @param charSet the charset name
231     *
232     * @return the Charset or null if it does not exist
233     */
234    private static Charset charSetForName(String charSet)
235    {
236        try
237        {
238            return Charset.forName(charSet);
239        }
240        catch (IllegalCharsetNameException | UnsupportedCharsetException e)
241        {
242            log.error("Illegal default charset {}", charSet);
243        }
244
245        return null;
246    }
247
248}