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 | */ |
6 | package org.h2.value; |
7 | |
8 | import java.lang.reflect.Method; |
9 | import java.util.Comparator; |
10 | import java.util.Locale; |
11 | |
12 | import org.h2.message.DbException; |
13 | import org.h2.util.JdbcUtils; |
14 | import org.h2.util.StringUtils; |
15 | |
16 | /** |
17 | * An implementation of CompareMode that uses the ICU4J Collator. |
18 | */ |
19 | public class CompareModeIcu4J extends CompareMode { |
20 | |
21 | private final Comparator<String> collator; |
22 | |
23 | protected CompareModeIcu4J(String name, int strength, boolean binaryUnsigned) { |
24 | super(name, strength, binaryUnsigned); |
25 | collator = getIcu4jCollator(name, strength); |
26 | } |
27 | |
28 | @Override |
29 | public int compareString(String a, String b, boolean ignoreCase) { |
30 | if (ignoreCase) { |
31 | a = a.toUpperCase(); |
32 | b = b.toUpperCase(); |
33 | } |
34 | return collator.compare(a, b); |
35 | } |
36 | |
37 | @Override |
38 | public boolean equalsChars(String a, int ai, String b, int bi, |
39 | boolean ignoreCase) { |
40 | return compareString(a.substring(ai, ai + 1), b.substring(bi, bi + 1), |
41 | ignoreCase) == 0; |
42 | } |
43 | |
44 | @SuppressWarnings("unchecked") |
45 | private static Comparator<String> getIcu4jCollator(String name, int strength) { |
46 | try { |
47 | Comparator<String> result = null; |
48 | Class<?> collatorClass = JdbcUtils.loadUserClass( |
49 | "com.ibm.icu.text.Collator"); |
50 | Method getInstanceMethod = collatorClass.getMethod( |
51 | "getInstance", Locale.class); |
52 | if (name.length() == 2) { |
53 | Locale locale = new Locale(StringUtils.toLowerEnglish(name), ""); |
54 | if (compareLocaleNames(locale, name)) { |
55 | result = (Comparator<String>) getInstanceMethod.invoke(null, locale); |
56 | } |
57 | } else if (name.length() == 5) { |
58 | // LL_CC (language_country) |
59 | int idx = name.indexOf('_'); |
60 | if (idx >= 0) { |
61 | String language = StringUtils.toLowerEnglish(name.substring(0, idx)); |
62 | String country = name.substring(idx + 1); |
63 | Locale locale = new Locale(language, country); |
64 | if (compareLocaleNames(locale, name)) { |
65 | result = (Comparator<String>) getInstanceMethod.invoke(null, locale); |
66 | } |
67 | } |
68 | } |
69 | if (result == null) { |
70 | for (Locale locale : (Locale[]) collatorClass.getMethod( |
71 | "getAvailableLocales").invoke(null)) { |
72 | if (compareLocaleNames(locale, name)) { |
73 | result = (Comparator<String>) getInstanceMethod.invoke(null, locale); |
74 | break; |
75 | } |
76 | } |
77 | } |
78 | if (result == null) { |
79 | throw DbException.getInvalidValueException("collator", name); |
80 | } |
81 | collatorClass.getMethod("setStrength", int.class).invoke(result, strength); |
82 | return result; |
83 | } catch (Exception e) { |
84 | throw DbException.convert(e); |
85 | } |
86 | } |
87 | |
88 | } |