1 /*
2 * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.util.locale.provider;
27
28 import java.text.spi.BreakIteratorProvider;
29 import java.text.spi.CollatorProvider;
30 import java.text.spi.DateFormatProvider;
31 import java.text.spi.DateFormatSymbolsProvider;
32 import java.text.spi.DecimalFormatSymbolsProvider;
33 import java.text.spi.NumberFormatProvider;
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.List;
37 import java.util.Locale;
38 import java.util.Map;
39 import java.util.ResourceBundle;
40 import java.util.Set;
41 import java.util.concurrent.ConcurrentHashMap;
42 import java.util.concurrent.ConcurrentMap;
43 import java.util.spi.CalendarDataProvider;
44 import java.util.spi.CalendarNameProvider;
45 import java.util.spi.CurrencyNameProvider;
46 import java.util.spi.LocaleNameProvider;
47 import java.util.spi.LocaleServiceProvider;
48 import java.util.spi.TimeZoneNameProvider;
49 import sun.security.action.GetPropertyAction;
50 import sun.text.spi.JavaTimeDateTimePatternProvider;
51 import sun.util.spi.CalendarProvider;
52
53 /**
54 * The LocaleProviderAdapter abstract class.
55 *
56 * @author Naoto Sato
57 * @author Masayoshi Okutsu
58 */
59 public abstract class LocaleProviderAdapter {
60 /**
61 * Adapter type.
62 */
63 public static enum Type {
64 JRE("sun.util.locale.provider.JRELocaleProviderAdapter", "sun.util.resources", "sun.text.resources"),
65 CLDR("sun.util.cldr.CLDRLocaleProviderAdapter", "sun.util.resources.cldr", "sun.text.resources.cldr"),
66 SPI("sun.util.locale.provider.SPILocaleProviderAdapter"),
67 HOST("sun.util.locale.provider.HostLocaleProviderAdapter"),
68 FALLBACK("sun.util.locale.provider.FallbackLocaleProviderAdapter", "sun.util.resources", "sun.text.resources");
69
70 private final String CLASSNAME;
71 private final String UTIL_RESOURCES_PACKAGE;
72 private final String TEXT_RESOURCES_PACKAGE;
73
74 private Type(String className) {
75 this(className, null, null);
76 }
77
78 private Type(String className, String util, String text) {
79 CLASSNAME = className;
80 UTIL_RESOURCES_PACKAGE = util;
81 TEXT_RESOURCES_PACKAGE = text;
82 }
83
84 public String getAdapterClassName() {
85 return CLASSNAME;
86 }
87
88 public String getUtilResourcesPackage() {
89 return UTIL_RESOURCES_PACKAGE;
90 }
91
92 public String getTextResourcesPackage() {
93 return TEXT_RESOURCES_PACKAGE;
94 }
95 }
96
97 /**
98 * LocaleProviderAdapter preference list.
99 */
100 private static final List<Type> adapterPreference;
101
102 /**
103 * LocaleProviderAdapter instances
104 */
105 private static final Map<Type, LocaleProviderAdapter> adapterInstances = new ConcurrentHashMap<>();
106
107 /**
108 * Default fallback adapter type, which should return something meaningful in any case.
109 * This is either CLDR or FALLBACK.
110 */
111 static volatile LocaleProviderAdapter.Type defaultLocaleProviderAdapter;
112
113 /**
114 * Adapter lookup cache.
115 */
116 private static ConcurrentMap<Class<? extends LocaleServiceProvider>, ConcurrentMap<Locale, LocaleProviderAdapter>>
117 adapterCache = new ConcurrentHashMap<>();
118
119 static {
120 String order = GetPropertyAction.privilegedGetProperty("java.locale.providers");
121 List<Type> typeList = new ArrayList<>();
122
123 // Check user specified adapter preference
124 if (order != null && !order.isEmpty()) {
125 String[] types = order.split(",");
126 for (String type : types) {
127 type = type.trim().toUpperCase(Locale.ROOT);
128 if (type.equals("COMPAT")) {
129 type = "JRE";
130 }
131 try {
132 Type aType = Type.valueOf(type.trim().toUpperCase(Locale.ROOT));
133 if (!typeList.contains(aType)) {
134 typeList.add(aType);
135 }
136 } catch (IllegalArgumentException | UnsupportedOperationException e) {
137 // could be caused by the user specifying wrong
138 // provider name or format in the system property
139 LocaleServiceProviderPool.config(LocaleProviderAdapter.class, e.toString());
140 }
141 }
142 }
143
144 defaultLocaleProviderAdapter = Type.CLDR;
145 if (!typeList.isEmpty()) {
146 // bona fide preference exists
147 if (!(typeList.contains(Type.CLDR) || (typeList.contains(Type.JRE)))) {
148 // Append FALLBACK as the last resort when no ResourceBundleBasedAdapter is available.
149 typeList.add(Type.FALLBACK);
150 defaultLocaleProviderAdapter = Type.FALLBACK;
151 }
152 } else {
153 // Default preference list.
154 typeList.add(Type.CLDR);
155 typeList.add(Type.JRE);
156 }
157 adapterPreference = Collections.unmodifiableList(typeList);
158 }
159
160 /**
161 * Returns the singleton instance for each adapter type
162 */
163 public static LocaleProviderAdapter forType(Type type) {
164 switch (type) {
165 case JRE:
166 case CLDR:
167 case SPI:
168 case HOST:
169 case FALLBACK:
170 LocaleProviderAdapter adapter = null;
171 LocaleProviderAdapter cached = adapterInstances.get(type);
172 if (cached == null) {
173 try {
174 // lazily load adapters here
175 @SuppressWarnings("deprecation")
176 Object tmp = Class.forName(type.getAdapterClassName()).newInstance();
177 adapter = (LocaleProviderAdapter)tmp;
178 cached = adapterInstances.putIfAbsent(type, adapter);
179 if (cached != null) {
180 adapter = cached;
181 }
182 } catch (ClassNotFoundException |
183 IllegalAccessException |
184 InstantiationException |
185 UnsupportedOperationException e) {
186 LocaleServiceProviderPool.config(LocaleProviderAdapter.class, e.toString());
187 adapterInstances.putIfAbsent(type, NONEXISTENT_ADAPTER);
188 if (defaultLocaleProviderAdapter == type) {
189 defaultLocaleProviderAdapter = Type.FALLBACK;
190 }
191 }
192 } else if (cached != NONEXISTENT_ADAPTER) {
193 adapter = cached;
194 }
195 return adapter;
196 default:
197 throw new InternalError("unknown locale data adapter type");
198 }
199 }
200
201 public static LocaleProviderAdapter forJRE() {
202 return forType(Type.JRE);
203 }
204
205 public static LocaleProviderAdapter getResourceBundleBased() {
206 for (Type type : getAdapterPreference()) {
207 if (type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK) {
208 LocaleProviderAdapter adapter = forType(type);
209 if (adapter != null) {
210 return adapter;
211 }
212 }
213 }
214 // Shouldn't happen.
423
424 /**
425 * Returns a CalendarProvider for this LocaleProviderAdapter, or null if no
426 * CalendarProvider is available.
427 *
428 * @return a CalendarProvider
429 */
430 public abstract CalendarProvider getCalendarProvider();
431
432 /**
433 * Returns a JavaTimeDateTimePatternProvider for this LocaleProviderAdapter,
434 * or null if no JavaTimeDateTimePatternProvider is available.
435 *
436 * @return a JavaTimeDateTimePatternProvider
437 */
438 public abstract JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider();
439
440 public abstract LocaleResources getLocaleResources(Locale locale);
441
442 public abstract Locale[] getAvailableLocales();
443
444 private static final LocaleProviderAdapter NONEXISTENT_ADAPTER = new NonExistentAdapter();
445 private static final class NonExistentAdapter extends FallbackLocaleProviderAdapter {
446 @Override
447 public LocaleProviderAdapter.Type getAdapterType() {
448 return null;
449 }
450
451 private NonExistentAdapter() {};
452 }
453 }
|
1 /*
2 * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.util.locale.provider;
27
28 import java.lang.reflect.InvocationTargetException;
29 import java.text.spi.BreakIteratorProvider;
30 import java.text.spi.CollatorProvider;
31 import java.text.spi.DateFormatProvider;
32 import java.text.spi.DateFormatSymbolsProvider;
33 import java.text.spi.DecimalFormatSymbolsProvider;
34 import java.text.spi.NumberFormatProvider;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.List;
38 import java.util.Locale;
39 import java.util.Map;
40 import java.util.ResourceBundle;
41 import java.util.ServiceConfigurationError;
42 import java.util.Set;
43 import java.util.concurrent.ConcurrentHashMap;
44 import java.util.concurrent.ConcurrentMap;
45 import java.util.spi.CalendarDataProvider;
46 import java.util.spi.CalendarNameProvider;
47 import java.util.spi.CurrencyNameProvider;
48 import java.util.spi.LocaleNameProvider;
49 import java.util.spi.LocaleServiceProvider;
50 import java.util.spi.TimeZoneNameProvider;
51 import sun.security.action.GetPropertyAction;
52 import sun.text.spi.JavaTimeDateTimePatternProvider;
53 import sun.util.spi.CalendarProvider;
54
55 import static java.lang.System.*;
56
57 /**
58 * The LocaleProviderAdapter abstract class.
59 *
60 * @author Naoto Sato
61 * @author Masayoshi Okutsu
62 */
63 public abstract class LocaleProviderAdapter {
64 /**
65 * Adapter type.
66 */
67 public enum Type {
68 JRE("sun.util.locale.provider.JRELocaleProviderAdapter", "sun.util.resources", "sun.text.resources"),
69 CLDR("sun.util.cldr.CLDRLocaleProviderAdapter", "sun.util.resources.cldr", "sun.text.resources.cldr"),
70 SPI("sun.util.locale.provider.SPILocaleProviderAdapter"),
71 HOST("sun.util.locale.provider.HostLocaleProviderAdapter"),
72 FALLBACK("sun.util.locale.provider.FallbackLocaleProviderAdapter", "sun.util.resources", "sun.text.resources");
73
74 private final String CLASSNAME;
75 private final String UTIL_RESOURCES_PACKAGE;
76 private final String TEXT_RESOURCES_PACKAGE;
77
78 Type(String className) {
79 this(className, null, null);
80 }
81
82 Type(String className, String util, String text) {
83 CLASSNAME = className;
84 UTIL_RESOURCES_PACKAGE = util;
85 TEXT_RESOURCES_PACKAGE = text;
86 }
87
88 public String getAdapterClassName() {
89 return CLASSNAME;
90 }
91
92 public String getUtilResourcesPackage() {
93 return UTIL_RESOURCES_PACKAGE;
94 }
95
96 public String getTextResourcesPackage() {
97 return TEXT_RESOURCES_PACKAGE;
98 }
99 }
100
101 /**
102 * LocaleProviderAdapter preference list.
103 */
104 private static final List<Type> adapterPreference;
105
106 /**
107 * LocaleProviderAdapter instances
108 */
109 private static final Map<Type, LocaleProviderAdapter> adapterInstances = new ConcurrentHashMap<>();
110
111 /**
112 * Default fallback adapter type, which should return something meaningful in any case.
113 * This is either CLDR or FALLBACK.
114 */
115 static volatile LocaleProviderAdapter.Type defaultLocaleProviderAdapter;
116
117 /**
118 * Adapter lookup cache.
119 */
120 private static final ConcurrentMap<Class<? extends LocaleServiceProvider>, ConcurrentMap<Locale, LocaleProviderAdapter>>
121 adapterCache = new ConcurrentHashMap<>();
122
123 static {
124 String order = GetPropertyAction.privilegedGetProperty("java.locale.providers");
125 ArrayList<Type> typeList = new ArrayList<>();
126 String invalidTypeMessage = null;
127
128 // Check user specified adapter preference
129 if (order != null && !order.isEmpty()) {
130 String[] types = order.split(",");
131 for (String type : types) {
132 type = type.trim().toUpperCase(Locale.ROOT);
133 if (type.equals("COMPAT")) {
134 type = "JRE";
135 }
136 try {
137 Type aType = Type.valueOf(type.trim().toUpperCase(Locale.ROOT));
138 if (!typeList.contains(aType)) {
139 typeList.add(aType);
140 }
141 } catch (IllegalArgumentException e) {
142 // construct a log message.
143 invalidTypeMessage = "Invalid locale provider adapter \"" + type + "\" ignored.";
144 }
145 }
146 }
147
148 defaultLocaleProviderAdapter = Type.CLDR;
149 if (!typeList.isEmpty()) {
150 // bona fide preference exists
151 if (!(typeList.contains(Type.CLDR) || typeList.contains(Type.JRE))) {
152 // Append FALLBACK as the last resort when no ResourceBundleBasedAdapter is available.
153 typeList.add(Type.FALLBACK);
154 defaultLocaleProviderAdapter = Type.FALLBACK;
155 }
156 } else {
157 // Default preference list.
158 typeList.add(Type.CLDR);
159 typeList.add(Type.JRE);
160 }
161 adapterPreference = Collections.unmodifiableList(typeList);
162
163 // Emit logs, if any, after 'adapterPreference' is initialized which is needed
164 // for logging.
165 if (invalidTypeMessage != null) {
166 // could be caused by the user specifying wrong
167 // provider name or format in the system property
168 getLogger(LocaleProviderAdapter.class.getCanonicalName())
169 .log(Logger.Level.INFO, invalidTypeMessage);
170 }
171 }
172
173 /**
174 * Returns the singleton instance for each adapter type
175 */
176 public static LocaleProviderAdapter forType(Type type) {
177 switch (type) {
178 case JRE:
179 case CLDR:
180 case SPI:
181 case HOST:
182 case FALLBACK:
183 LocaleProviderAdapter adapter = adapterInstances.get(type);
184 if (adapter == null) {
185 try {
186 // lazily load adapters here
187 adapter = (LocaleProviderAdapter)Class.forName(type.getAdapterClassName())
188 .getDeclaredConstructor().newInstance();
189 LocaleProviderAdapter cached = adapterInstances.putIfAbsent(type, adapter);
190 if (cached != null) {
191 adapter = cached;
192 }
193 } catch (NoSuchMethodException |
194 InvocationTargetException |
195 ClassNotFoundException |
196 IllegalAccessException |
197 InstantiationException |
198 UnsupportedOperationException e) {
199 throw new ServiceConfigurationError("Locale provider adapter \"" +
200 type + "\"cannot be instantiated.", e);
201 }
202 }
203 return adapter;
204 default:
205 throw new InternalError("unknown locale data adapter type");
206 }
207 }
208
209 public static LocaleProviderAdapter forJRE() {
210 return forType(Type.JRE);
211 }
212
213 public static LocaleProviderAdapter getResourceBundleBased() {
214 for (Type type : getAdapterPreference()) {
215 if (type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK) {
216 LocaleProviderAdapter adapter = forType(type);
217 if (adapter != null) {
218 return adapter;
219 }
220 }
221 }
222 // Shouldn't happen.
431
432 /**
433 * Returns a CalendarProvider for this LocaleProviderAdapter, or null if no
434 * CalendarProvider is available.
435 *
436 * @return a CalendarProvider
437 */
438 public abstract CalendarProvider getCalendarProvider();
439
440 /**
441 * Returns a JavaTimeDateTimePatternProvider for this LocaleProviderAdapter,
442 * or null if no JavaTimeDateTimePatternProvider is available.
443 *
444 * @return a JavaTimeDateTimePatternProvider
445 */
446 public abstract JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider();
447
448 public abstract LocaleResources getLocaleResources(Locale locale);
449
450 public abstract Locale[] getAvailableLocales();
451 }
|