EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.value]

COVERAGE SUMMARY FOR SOURCE FILE [CompareMode.java]

nameclass, %method, %block, %line, %
CompareMode.java100% (1/1)100% (14/14)93%  (328/351)90%  (73.9/82)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class CompareMode100% (1/1)100% (14/14)93%  (328/351)90%  (73.9/82)
<static initializer> 100% (1/1)33%  (4/12)43%  (3/7)
equals (Object): boolean 100% (1/1)84%  (31/37)75%  (9/12)
getInstance (String, int, boolean): CompareMode 100% (1/1)89%  (68/76)94%  (15/16)
hashCode (): int 100% (1/1)93%  (13/14)92%  (0.9/1)
CompareMode (String, int, boolean): void 100% (1/1)100% (12/12)100% (5/5)
compareLocaleNames (Locale, String): boolean 100% (1/1)100% (14/14)100% (1/1)
compareString (String, String, boolean): int 100% (1/1)100% (10/10)100% (3/3)
equalsChars (String, int, String, int, boolean): boolean 100% (1/1)100% (23/23)100% (6/6)
getCollator (String): Collator 100% (1/1)100% (103/103)100% (23/23)
getInstance (String, int): CompareMode 100% (1/1)100% (5/5)100% (1/1)
getName (): String 100% (1/1)100% (8/8)100% (1/1)
getName (Locale): String 100% (1/1)100% (31/31)100% (4/4)
getStrength (): int 100% (1/1)100% (3/3)100% (1/1)
isBinaryUnsigned (): boolean 100% (1/1)100% (3/3)100% (1/1)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.value;
7 
8import java.text.Collator;
9import java.util.Locale;
10 
11import org.h2.engine.SysProperties;
12import org.h2.util.StringUtils;
13 
14/**
15 * Instances of this class can compare strings. Case sensitive and case
16 * insensitive comparison is supported, and comparison using a collator.
17 */
18public class CompareMode {
19 
20    /**
21     * This constant means there is no collator set, and the default string
22     * comparison is to be used.
23     */
24    public static final String OFF = "OFF";
25 
26    /**
27     * This constant means the default collator should be used, even if ICU4J is
28     * in the classpath.
29     */
30    public static final String DEFAULT = "DEFAULT_";
31 
32    /**
33     * This constant means ICU4J should be used (this will fail if it is not in
34     * the classpath).
35     */
36    public static final String ICU4J = "ICU4J_";
37 
38    /**
39     * This constant means that the BINARY columns are sorted as if the bytes
40     * were signed.
41     */
42    public static final String SIGNED = "SIGNED";
43 
44    /**
45     * This constant means that the BINARY columns are sorted as if the bytes
46     * were unsigned.
47     */
48    public static final String UNSIGNED = "UNSIGNED";
49 
50    private static CompareMode lastUsed;
51 
52    private static final boolean CAN_USE_ICU4J;
53 
54    static {
55        boolean b = false;
56        try {
57            Class.forName("com.ibm.icu.text.Collator");
58            b = true;
59        } catch (Exception e) {
60            // ignore
61        }
62        CAN_USE_ICU4J = b;
63    }
64 
65    private final String name;
66    private final int strength;
67 
68    /**
69     * If true, sort BINARY columns as if they contain unsigned bytes.
70     */
71    private final boolean binaryUnsigned;
72 
73    protected CompareMode(String name, int strength, boolean binaryUnsigned) {
74        this.name = name;
75        this.strength = strength;
76        this.binaryUnsigned = binaryUnsigned;
77    }
78 
79    /**
80     * Create a new compare mode with the given collator and strength. If
81     * required, a new CompareMode is created, or if possible the last one is
82     * returned. A cache is used to speed up comparison when using a collator;
83     * CollationKey objects are cached.
84     *
85     * @param name the collation name or null
86     * @param strength the collation strength
87     * @return the compare mode
88     */
89    public static synchronized CompareMode getInstance(String name,
90            int strength) {
91        return getInstance(name, strength, SysProperties.SORT_BINARY_UNSIGNED);
92    }
93 
94    /**
95     * Create a new compare mode with the given collator and strength. If
96     * required, a new CompareMode is created, or if possible the last one is
97     * returned. A cache is used to speed up comparison when using a collator;
98     * CollationKey objects are cached.
99     *
100     * @param name the collation name or null
101     * @param strength the collation strength
102     * @param binaryUnsigned whether to compare binaries as unsigned
103     * @return the compare mode
104     */
105    public static synchronized CompareMode getInstance(String name,
106            int strength, boolean binaryUnsigned) {
107        if (lastUsed != null) {
108            if (StringUtils.equals(lastUsed.name, name) &&
109                    lastUsed.strength == strength &&
110                    lastUsed.binaryUnsigned == binaryUnsigned) {
111                return lastUsed;
112            }
113        }
114        if (name == null || name.equals(OFF)) {
115            lastUsed = new CompareMode(name, strength, binaryUnsigned);
116        } else {
117            boolean useICU4J;
118            if (name.startsWith(ICU4J)) {
119                useICU4J = true;
120                name = name.substring(ICU4J.length());
121            } else if (name.startsWith(DEFAULT)) {
122                useICU4J = false;
123                name = name.substring(DEFAULT.length());
124            } else {
125                useICU4J = CAN_USE_ICU4J;
126            }
127            if (useICU4J) {
128                lastUsed = new CompareModeIcu4J(name, strength, binaryUnsigned);
129            } else {
130                lastUsed = new CompareModeDefault(name, strength, binaryUnsigned);
131            }
132        }
133        return lastUsed;
134    }
135 
136    /**
137     * Compare two characters in a string.
138     *
139     * @param a the first string
140     * @param ai the character index in the first string
141     * @param b the second string
142     * @param bi the character index in the second string
143     * @param ignoreCase true if a case-insensitive comparison should be made
144     * @return true if the characters are equals
145     */
146    public boolean equalsChars(String a, int ai, String b, int bi,
147            boolean ignoreCase) {
148        char ca = a.charAt(ai);
149        char cb = b.charAt(bi);
150        if (ignoreCase) {
151            ca = Character.toUpperCase(ca);
152            cb = Character.toUpperCase(cb);
153        }
154        return ca == cb;
155    }
156 
157    /**
158     * Compare two strings.
159     *
160     * @param a the first string
161     * @param b the second string
162     * @param ignoreCase true if a case-insensitive comparison should be made
163     * @return -1 if the first string is 'smaller', 1 if the second string is
164     *         smaller, and 0 if they are equal
165     */
166    public int compareString(String a, String b, boolean ignoreCase) {
167        if (ignoreCase) {
168            return a.compareToIgnoreCase(b);
169        }
170        return a.compareTo(b);
171    }
172 
173    /**
174     * Get the collation name.
175     *
176     * @param l the locale
177     * @return the name of the collation
178     */
179    public static String getName(Locale l) {
180        Locale english = Locale.ENGLISH;
181        String name = l.getDisplayLanguage(english) + ' ' +
182                l.getDisplayCountry(english) + ' ' + l.getVariant();
183        name = StringUtils.toUpperEnglish(name.trim().replace(' ', '_'));
184        return name;
185    }
186 
187    /**
188     * Compare name name of the locale with the given name. The case of the name
189     * is ignored.
190     *
191     * @param locale the locale
192     * @param name the name
193     * @return true if they match
194     */
195    static boolean compareLocaleNames(Locale locale, String name) {
196        return name.equalsIgnoreCase(locale.toString()) ||
197                name.equalsIgnoreCase(getName(locale));
198    }
199 
200    /**
201     * Get the collator object for the given language name or language / country
202     * combination.
203     *
204     * @param name the language name
205     * @return the collator
206     */
207    public static Collator getCollator(String name) {
208        Collator result = null;
209        if (name.startsWith(ICU4J)) {
210            name = name.substring(ICU4J.length());
211        } else if (name.startsWith(DEFAULT)) {
212            name = name.substring(DEFAULT.length());
213        }
214        if (name.length() == 2) {
215            Locale locale = new Locale(StringUtils.toLowerEnglish(name), "");
216            if (compareLocaleNames(locale, name)) {
217                result = Collator.getInstance(locale);
218            }
219        } else if (name.length() == 5) {
220            // LL_CC (language_country)
221            int idx = name.indexOf('_');
222            if (idx >= 0) {
223                String language = StringUtils.toLowerEnglish(name.substring(0, idx));
224                String country = name.substring(idx + 1);
225                Locale locale = new Locale(language, country);
226                if (compareLocaleNames(locale, name)) {
227                    result = Collator.getInstance(locale);
228                }
229            }
230        }
231        if (result == null) {
232            for (Locale locale : Collator.getAvailableLocales()) {
233                if (compareLocaleNames(locale, name)) {
234                    result = Collator.getInstance(locale);
235                    break;
236                }
237            }
238        }
239        return result;
240    }
241 
242    public String getName() {
243        return name == null ? OFF : name;
244    }
245 
246    public int getStrength() {
247        return strength;
248    }
249 
250    public boolean isBinaryUnsigned() {
251        return binaryUnsigned;
252    }
253 
254    @Override
255    public boolean equals(Object obj) {
256        if (obj == this) {
257            return true;
258        } else if (!(obj instanceof CompareMode)) {
259            return false;
260        }
261        CompareMode o = (CompareMode) obj;
262        if (!getName().equals(o.getName())) {
263            return false;
264        }
265        if (strength != o.strength) {
266            return false;
267        }
268        if (binaryUnsigned != o.binaryUnsigned) {
269            return false;
270        }
271        return true;
272    }
273 
274    @Override
275    public int hashCode() {
276        return getName().hashCode() ^ strength ^ (binaryUnsigned ? -1 : 0);
277    }
278 
279}

[all classes][org.h2.value]
EMMA 2.0.5312 (C) Vladimir Roubtsov