001// Licensed under the Apache License, Version 2.0 (the "License");
002// you may not use this file except in compliance with the License.
003// You may obtain a copy of the License at
004//
005//     http://www.apache.org/licenses/LICENSE-2.0
006//
007// Unless required by applicable law or agreed to in writing, software
008// distributed under the License is distributed on an "AS IS" BASIS,
009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010// See the License for the specific language governing permissions and
011// limitations under the License.
012
013package org.apache.tapestry5.internal.util;
014
015import java.util.Locale;
016
017/**
018 * Contains code borrowed from <a href="http://commons.apache.org/lang/">commons-lang</a>.
019 */
020public class LocaleUtils
021{
022    /**
023     * Converts a String to a Locale.  This method takes the string format of a locale and creates the
024     * locale object from it.
025     * <pre>
026     *   LocaleUtils.toLocale("en")         = new Locale("en", "")
027     *   LocaleUtils.toLocale("en_GB")      = new Locale("en", "GB")
028     *   LocaleUtils.toLocale("en_GB_xxx")  = new Locale("en", "GB", "xxx")   (#)
029     * </pre>
030     *  (#) The behaviour of the JDK variant constructor changed between JDK1.3 and JDK1.4. In JDK1.3, the
031     * constructor upper cases the variant, in JDK1.4, it doesn't. Thus, the result from getVariant() may vary depending
032     * on your JDK.  This method validates the input strictly. The language code must be lowercase. The
033     * country code must be uppercase. The separator must be an underscore. The length must be correct.
034     *
035     * @param input the locale String to convert, null returns null
036     * @return a Locale, null if null input
037     * @throws IllegalArgumentException if the string is an invalid format
038     */
039    public static Locale toLocale(String input)
040    {
041        if (input == null)
042            return null;
043
044        int len = input.length();
045        if (len != 2 && len != 5 && len < 7)
046            fail(input);
047
048        char ch0 = input.charAt(0);
049        char ch1 = input.charAt(1);
050
051        if (ch0 < 'a' || ch0 > 'z' || ch1 < 'a' || ch1 > 'z')
052            fail(input);
053
054        if (len == 2)
055            return new Locale(input, "");
056
057        if (input.charAt(2) != '_')
058            fail(input);
059
060        char ch3 = input.charAt(3);
061        if (ch3 == '_')
062            return new Locale(input.substring(0, 2), "", input.substring(4));
063
064        char ch4 = input.charAt(4);
065        if (ch3 < 'A' || ch3 > 'Z' || ch4 < 'A' || ch4 > 'Z')
066            fail(input);
067
068        if (len == 5)
069            return new Locale(input.substring(0, 2), input.substring(3, 5));
070
071        if (input.charAt(5) != '_')
072            fail(input);
073
074        return new Locale(input.substring(0, 2), input.substring(3, 5), input.substring(6));
075    }
076
077    private static void fail(String input)
078    {
079        throw new IllegalArgumentException(String.format("Unable to convert '%s' to a Locale instance.", input));
080    }
081
082}