• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.util;
2 
3 import java.io.File;
4 import java.io.FilenameFilter;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Comparator;
8 import java.util.HashSet;
9 import java.util.LinkedHashSet;
10 import java.util.List;
11 import java.util.Locale;
12 import java.util.Map;
13 import java.util.Properties;
14 import java.util.Set;
15 import java.util.concurrent.ConcurrentHashMap;
16 
17 import org.unicode.cldr.test.CheckCLDR.Phase;
18 
19 import com.google.common.cache.CacheBuilder;
20 import com.google.common.cache.CacheLoader;
21 import com.google.common.cache.LoadingCache;
22 import com.google.common.collect.ImmutableSet;
23 import com.ibm.icu.dev.test.TestFmwk;
24 import com.ibm.icu.dev.test.TestLog;
25 import com.ibm.icu.text.Collator;
26 import com.ibm.icu.text.RuleBasedCollator;
27 import com.ibm.icu.util.ULocale;
28 import com.ibm.icu.util.VersionInfo;
29 
30 /**
31  * Basic information about the CLDR environment.
32  * Use CLDRConfig.getInstance() to create your instance.
33  *
34  * Special notes:
35  * - Within the Survey Tool, a special subclass of this class named CLDRConfigImpl is used instead,
36  * which see.
37  * - Within unit tests, -DCLDR_ENVIRONMENT=UNITTEST is set, which prevents the use of CLDRConfigImpl
38  */
39 public class CLDRConfig extends Properties {
40     public static boolean SKIP_SEED = System.getProperty("CLDR_SKIP_SEED") != null;
41     private static final long serialVersionUID = -2605254975303398336L;
42     public static boolean DEBUG = false;
43     /**
44      * This is the special implementation which will be used, i.e. CLDRConfigImpl
45      */
46     public static final String SUBCLASS = CLDRConfig.class.getName() + "Impl";
47 
48     /**
49      * What environment is CLDR in?
50      */
51     public enum Environment {
52         LOCAL, // < == unknown.
53         SMOKETEST, // staging (SurveyTool) area
54         PRODUCTION, // production (SurveyTool) server!
55         UNITTEST // unit test setting
56     }
57 
58     public static final class CLDRConfigHelper {
make()59         private static CLDRConfig make() {
60             CLDRConfig instance = null;
61             final String env = System.getProperty("CLDR_ENVIRONMENT");
62             if (env != null && env.equals(Environment.UNITTEST.name())) {
63                 // For unittests, skip the following
64                 if (DEBUG) {
65                     System.err.println("-DCLDR_ENVIRONMENT=" + env + " - not loading " + SUBCLASS);
66                 }
67             } else {
68                 // This is the branch for SurveyTool
69                 try {
70                     // System.err.println("Attempting to new up a " + SUBCLASS);
71                     instance = (CLDRConfig) (Class.forName(SUBCLASS).newInstance());
72 
73                     if (instance != null) {
74                         System.err.println("Using CLDRConfig: " + instance.toString() + " - "
75                             + instance.getClass().getName());
76                     } else {
77                         if (DEBUG) {
78                             // Probably occurred because ( config.getEnvironment() == Environment.UNITTEST )
79                             // see CLDRConfigImpl
80                             System.err.println("Note: CLDRConfig Subclass " +
81                                 SUBCLASS + ".newInstance() returned NULL " +
82                                 "( this is OK if we aren't inside the SurveyTool's web server )");
83                         }
84                     }
85                 } catch (ClassNotFoundException e) {
86                     // Expected - when not under cldr-apps, this class doesn't exist.
87                 } catch (InstantiationException | IllegalAccessException e) {
88                     // TODO: log a useful message
89                 }
90             }
91             if (instance == null) {
92                 // this is the "normal" branch for tools and such
93                 instance = new CLDRConfig();
94                 CldrUtility.checkValidDirectory(instance.getProperty("CLDR_DIR"),
95                     "You have to set -DCLDR_DIR=<validdirectory>");
96             }
97             return instance;
98         }
99 
100         static final CLDRConfig SINGLETON = make();
101     }
102 
103     /**
104      * Main getter for the singleton CLDRConfig.
105      * @return
106      */
getInstance()107     public static CLDRConfig getInstance() {
108         return CLDRConfigHelper.SINGLETON;
109     }
110 
111     String initStack = null;
112 
CLDRConfig()113     protected CLDRConfig() {
114         initStack = StackTracker.currentStack();
115     }
116 
117     /**
118      * This returns the stacktrace of the first caller to getInstance(), for debugging.
119      * @return
120      */
getInitStack()121     public String getInitStack() {
122         return initStack;
123     }
124 
125     private Phase phase = null; // default
126 
127     private LoadingCache<String, CLDRFile> cldrFileResolvedCache = CacheBuilder.newBuilder()
128         .maximumSize(200)
129         .build(
130             new CacheLoader<String, CLDRFile>() {
131                 @Override
132                 public CLDRFile load(String locale) {
133                     return getFullCldrFactory().make(locale, true);
134                 }
135             });
136 
137     // Unresolved CLDRFiles are smaller than resolved, so we can cache more of them safely.
138     private LoadingCache<String, CLDRFile> cldrFileUnresolvedCache = CacheBuilder.newBuilder()
139         .maximumSize(1000)
140         .build(
141             new CacheLoader<String, CLDRFile>() {
142                 @Override
143                 public CLDRFile load(String locale) {
144                     return getFullCldrFactory().make(locale, false);
145                 }
146             });
147     private TestLog testLog = null;
148 
149     // base level
setTestLog(TestLog log)150     public TestLog setTestLog(TestLog log) {
151         testLog = log;
152         return log;
153     }
154 
155     // for calling "run"
setTestLog(TestFmwk log)156     public TestFmwk setTestLog(TestFmwk log) {
157         testLog = log;
158         return log;
159     }
160 
logln(String msg)161     protected void logln(String msg) {
162         if (testLog != null) {
163             testLog.logln(msg);
164         } else {
165             System.out.println(msg);
166             System.out.flush();
167         }
168     }
169 
170     private static final class SupplementalDataInfoHelper {
171         static final SupplementalDataInfo SINGLETON = SupplementalDataInfo.getInstance(CLDRPaths.DEFAULT_SUPPLEMENTAL_DIRECTORY);
172     }
173 
getSupplementalDataInfo()174     public SupplementalDataInfo getSupplementalDataInfo() {
175         // Note: overridden in subclass.
176         return SupplementalDataInfoHelper.SINGLETON;
177     }
178 
179     private static final class CoverageInfoHelper {
180         static final CoverageInfo SINGLETON = new CoverageInfo(getInstance().getSupplementalDataInfo());
181     }
182 
getCoverageInfo()183     public final CoverageInfo getCoverageInfo() {
184         return CoverageInfoHelper.SINGLETON;
185     }
186 
187     private static final class CldrFactoryHelper {
188         static final Factory SINGLETON = Factory.make(CLDRPaths.MAIN_DIRECTORY, ".*");
189     }
190 
getCldrFactory()191     public final Factory getCldrFactory() {
192         return CldrFactoryHelper.SINGLETON;
193     }
194 
195     private static final class ExemplarsFactoryHelper {
196         static final Factory SINGLETON = Factory.make(CLDRPaths.EXEMPLARS_DIRECTORY, ".*");
197     }
198 
getExemplarsFactory()199     public final Factory getExemplarsFactory() {
200         return ExemplarsFactoryHelper.SINGLETON;
201     }
202 
203     private static final class CollationFactoryHelper {
204         static final Factory SINGLETON = Factory.make(CLDRPaths.COLLATION_DIRECTORY, ".*");
205     }
206 
getCollationFactory()207     public final Factory getCollationFactory() {
208         return CollationFactoryHelper.SINGLETON;
209     }
210 
211     private static final class RBNFFactoryHelper {
212         static final Factory SINGLETON = Factory.make(CLDRPaths.RBNF_DIRECTORY, ".*");
213     }
214 
getRBNFFactory()215     public final Factory getRBNFFactory() {
216         return RBNFFactoryHelper.SINGLETON;
217     }
218 
219     private static final class AnnotationsFactoryHelper {
220         static final Factory SINGLETON = Factory.make(CLDRPaths.ANNOTATIONS_DIRECTORY, ".*");
221     }
222 
getAnnotationsFactory()223     public Factory getAnnotationsFactory() {
224         return AnnotationsFactoryHelper.SINGLETON;
225     }
226 
227     private static final class SubdivisionsFactoryHelper {
228         static final Factory SINGLETON = Factory.make(CLDRPaths.SUBDIVISIONS_DIRECTORY, ".*");
229     }
230 
getSubdivisionFactory()231     public final Factory getSubdivisionFactory() {
232         return SubdivisionsFactoryHelper.SINGLETON;
233     }
234 
235     private static final class MainAndAnnotationsFactoryHelper {
236         private static final File[] paths = {
237             new File(CLDRPaths.MAIN_DIRECTORY),
238             new File(CLDRPaths.ANNOTATIONS_DIRECTORY) };
239         static final Factory SINGLETON = SimpleFactory.make(paths, ".*");
240     }
241 
getMainAndAnnotationsFactory()242     public final Factory getMainAndAnnotationsFactory() {
243         return MainAndAnnotationsFactoryHelper.SINGLETON;
244     }
245 
246     private static final class CommonSeedExemplarsFactoryHelper {
247         static final Factory SINGLETON = SimpleFactory.make(getInstance().addStandardSubdirectories(CLDR_DATA_DIRECTORIES), ".*");
248     }
249 
getCommonSeedExemplarsFactory()250     public final Factory getCommonSeedExemplarsFactory() {
251         return CommonSeedExemplarsFactoryHelper.SINGLETON;
252     }
253 
254     private static final class CommonAndSeedAndMainAndAnnotationsFactoryHelper {
255         private static final File[] paths = {
256             new File(CLDRPaths.MAIN_DIRECTORY),
257             new File(CLDRPaths.ANNOTATIONS_DIRECTORY),
258             SKIP_SEED ? null : new File(CLDRPaths.SEED_DIRECTORY),
259                 SKIP_SEED ? null : new File(CLDRPaths.SEED_ANNOTATIONS_DIRECTORY)
260         };
261         static final Factory SINGLETON = SimpleFactory.make(paths, ".*");
262     }
263 
getCommonAndSeedAndMainAndAnnotationsFactory()264     public final Factory getCommonAndSeedAndMainAndAnnotationsFactory() {
265         return CommonAndSeedAndMainAndAnnotationsFactoryHelper.SINGLETON;
266     }
267 
268     private static final class FullCldrFactoryHelper {
269         private static final File[] paths = {
270             new File(CLDRPaths.MAIN_DIRECTORY),
271             SKIP_SEED ? null : new File(CLDRPaths.SEED_DIRECTORY)};
272         static final Factory SINGLETON = SimpleFactory.make(paths, ".*");
273     }
274 
getFullCldrFactory()275     public final Factory getFullCldrFactory() {
276         return FullCldrFactoryHelper.SINGLETON;
277     }
278 
279     private static final class SupplementalFactoryHelper {
280         static final Factory SINGLETON = Factory.make(CLDRPaths.DEFAULT_SUPPLEMENTAL_DIRECTORY, ".*");
281     }
282 
getSupplementalFactory()283     public final Factory getSupplementalFactory() {
284         return SupplementalFactoryHelper.SINGLETON;
285     }
286 
getEnglish()287     public CLDRFile getEnglish() {
288         return getCLDRFile("en", true);
289     }
290 
getCLDRFile(String locale, boolean resolved)291     public CLDRFile getCLDRFile(String locale, boolean resolved) {
292         return resolved ? cldrFileResolvedCache.getUnchecked(locale) : cldrFileUnresolvedCache.getUnchecked(locale);
293     }
294 
getRoot()295     public CLDRFile getRoot() {
296         return getCLDRFile("root", true);
297     }
298 
299     private static final class CollatorRootHelper {
300         static final RuleBasedCollator SINGLETON = make();
301 
make()302         private static final RuleBasedCollator make() {
303             RuleBasedCollator colRoot;
304 
305             CLDRFile root = getInstance().getCollationFactory().make("root", false);
306             String rules = root.getStringValue("//ldml/collations/collation[@type=\"emoji\"][@visibility=\"external\"]/cr");
307             try {
308                 colRoot = new RuleBasedCollator(rules);
309             } catch (Exception e) {
310                 colRoot = (RuleBasedCollator) getInstance().getCollator();
311                 return colRoot;
312             }
313             colRoot.setStrength(Collator.IDENTICAL);
314             colRoot.setNumericCollation(true);
315             colRoot.freeze();
316             return colRoot;
317         }
318     }
getCollatorRoot()319     public final Collator getCollatorRoot() {
320         return CollatorRootHelper.SINGLETON;
321     }
322 
323     @SuppressWarnings("unchecked")
getComparatorRoot()324     public final Comparator<String> getComparatorRoot() {
325         return (Comparator)(getCollatorRoot());
326     }
327 
328     private static final class CollatorHelper {
329         static final Collator EMOJI_COLLATOR = makeEmojiCollator();
makeEmojiCollator()330         private static final Collator makeEmojiCollator() {
331             final RuleBasedCollator col = (RuleBasedCollator) Collator.getInstance(ULocale.forLanguageTag("en-u-co-emoji"));
332             col.setStrength(Collator.IDENTICAL);
333             col.setNumericCollation(true);
334             col.freeze();
335             return col;
336         }
337 
338         static final Collator ROOT_NUMERIC = makeRootNumeric();
339 
makeRootNumeric()340         private static final Collator makeRootNumeric() {
341             RuleBasedCollator _ROOT_COL = (RuleBasedCollator) Collator.getInstance(ULocale.ENGLISH);
342             _ROOT_COL.setNumericCollation(true);
343             _ROOT_COL.freeze();
344             return _ROOT_COL;
345         }
346     }
getCollator()347     public Collator getCollator() {
348         return CollatorHelper.EMOJI_COLLATOR;
349     }
350 
getRootNumeric()351     public Collator getRootNumeric() {
352         return CollatorHelper.ROOT_NUMERIC;
353     }
354 
getPhase()355     public synchronized Phase getPhase() {
356         if (phase == null) {
357             if (getEnvironment() == Environment.UNITTEST) {
358                 phase = Phase.BUILD;
359             } else {
360                 phase = Phase.SUBMISSION;
361             }
362         }
363         return phase;
364     }
365 
366     @Override
getProperty(String key, String d)367     public String getProperty(String key, String d) {
368         String result = getProperty(key);
369         if (result == null) return d;
370         return result;
371     }
372 
373     private Set<String> shown = new HashSet<>();
374 
375     private Map<String, String> localSet = null;
376 
377     @Override
get(Object key)378     public String get(Object key) {
379         return getProperty(key.toString());
380     }
381 
382     @Override
getProperty(String key)383     public String getProperty(String key) {
384         String result = null;
385         if (localSet != null) {
386             result = localSet.get(key);
387         }
388         if (result == null) {
389             result = System.getProperty(key);
390         }
391         if (result == null) {
392             result = System.getProperty(key.toUpperCase(Locale.ENGLISH));
393         }
394         if (result == null) {
395             result = System.getProperty(key.toLowerCase(Locale.ENGLISH));
396         }
397         if (result == null) {
398             result = System.getenv(key);
399         }
400         if (DEBUG && !shown.contains(key)) {
401             logln("-D" + key + "=" + result);
402             shown.add(key);
403         }
404         return result;
405     }
406 
407     private Environment curEnvironment = null;
408 
getEnvironment()409     public Environment getEnvironment() {
410         if (curEnvironment == null) {
411             String envString = getProperty("CLDR_ENVIRONMENT");
412             if (envString != null) {
413                 curEnvironment = Environment.valueOf(envString.trim());
414             }
415             if (curEnvironment == null) {
416                 curEnvironment = getDefaultEnvironment();
417             }
418         }
419         return curEnvironment;
420     }
421 
422     /**
423      * If no environment is defined, what is the default?
424      * @return
425      */
getDefaultEnvironment()426     protected Environment getDefaultEnvironment() {
427         return Environment.LOCAL;
428     }
429 
setEnvironment(Environment environment)430     public void setEnvironment(Environment environment) {
431         curEnvironment = environment;
432     }
433 
434     /**
435      * For test use only. Will throw an exception in non test environments.
436      * @param k
437      * @param v
438      * @return
439      */
440     @Override
setProperty(String k, String v)441     public Object setProperty(String k, String v) {
442         if (getEnvironment() != Environment.UNITTEST) {
443             throw new InternalError("setProperty() only valid in UNITTEST Environment.");
444         }
445         if (localSet == null) {
446             localSet = new ConcurrentHashMap<>();
447         }
448         shown.remove(k); // show it again with -D
449         return localSet.put(k, v);
450     }
451 
452     @Override
put(Object k, Object v)453     public Object put(Object k, Object v) {
454         return setProperty(k.toString(), v.toString());
455     }
456 
457     /**
458      * Return true if the value indicates 'true'
459      * @param k key
460      * @param defVal default value
461      * @return
462      */
getProperty(String k, boolean defVal)463     public boolean getProperty(String k, boolean defVal) {
464         String val = getProperty(k, defVal ? "true" : null);
465         if (val == null) {
466             return false;
467         } else {
468             val = val.trim().toLowerCase();
469             return (val.equals("true") || val.equals("t") || val.equals("yes") || val.equals("y"));
470         }
471     }
472 
473     /**
474      * Return a numeric property
475      * @param k key
476      * @param defVal default value
477      * @return
478      */
getProperty(String k, int defVal)479     public int getProperty(String k, int defVal) {
480         String val = getProperty(k, Integer.toString(defVal));
481         if (val == null) {
482             return defVal;
483         } else {
484             try {
485                 return Integer.parseInt(val);
486             } catch (NumberFormatException nfe) {
487                 return defVal;
488             }
489         }
490     }
491 
492     private static class FileWrapper {
493         private File cldrDir = null;
FileWrapper()494         private FileWrapper() {
495             String dir = getInstance().getProperty("CLDR_DIR", null);
496             if (dir != null) {
497                 cldrDir = new File(dir);
498             } else {
499                 cldrDir = null;
500             }
501         }
getCldrDir()502         public File getCldrDir() {
503             return this.cldrDir;
504         }
505         // singleton
506         private static FileWrapper fileWrapperInstance = new FileWrapper();
getFileWrapperInstance()507         public static FileWrapper getFileWrapperInstance() {
508             return fileWrapperInstance;
509         }
510     }
511 
getCldrBaseDirectory()512     public File getCldrBaseDirectory() {
513         return FileWrapper.getFileWrapperInstance().getCldrDir();
514     }
515 
516     /**
517      * Get all CLDR XML files in the CLDR base directory.
518      * @return
519      */
getAllCLDRFilesEndingWith(final String suffix)520     public Set<File> getAllCLDRFilesEndingWith(final String suffix) {
521         FilenameFilter filter = new FilenameFilter() {
522             @Override
523             public boolean accept(File dir, String name) {
524                 return name.endsWith(suffix) && !isJunkFile(name); // skip junk and backup files
525             }
526         };
527         final File dir = getCldrBaseDirectory();
528         Set<File> list;
529         list = getCLDRFilesMatching(filter, dir);
530         return list;
531     }
532 
533     /**
534      * Return all CLDR data files matching this filter
535      * @param filter matching filter
536      * @param baseDir base directory, see {@link #getCldrBaseDirectory()}
537      * @return set of files
538      */
getCLDRFilesMatching(FilenameFilter filter, final File baseDir)539     public Set<File> getCLDRFilesMatching(FilenameFilter filter, final File baseDir) {
540         Set<File> list;
541         list = new LinkedHashSet<>();
542         for (String subdir : getCLDRDataDirectories()) {
543             getFilesRecursively(new File(baseDir, subdir), filter, list);
544         }
545         return list;
546     }
547 
548     /**
549      * TODO: better place for these constants?
550      */
551     private static final String COMMON_DIR = "common";
552     /**
553      * TODO: better place for these constants?
554      */
555     private static final String EXEMPLARS_DIR = "exemplars";
556     /**
557      * TODO: better place for these constants?
558      */
559     private static final String SEED_DIR = "seed";
560     /**
561      * TODO: better place for these constants?
562      */
563     private static final String KEYBOARDS_DIR = "keyboards";
564     private static final String MAIN_DIR = "main";
565     private static final String ANNOTATIONS_DIR = "annotations";
566     private static final String SUBDIVISIONS_DIR = "subdivisions";
567 
568     /**
569      * TODO: better place for these constants?
570      */
571     private static final String CLDR_DATA_DIRECTORIES[] = { COMMON_DIR, SEED_DIR, KEYBOARDS_DIR, EXEMPLARS_DIR };
572     private static final ImmutableSet<String> STANDARD_SUBDIRS = ImmutableSet.of(MAIN_DIR, ANNOTATIONS_DIR, SUBDIVISIONS_DIR);
573 
574     /**
575      * Get a list of CLDR directories containing actual data
576      * @return an iterable containing the names of all CLDR data subdirectories
577      */
getCLDRDataDirectories()578     public static Iterable<String> getCLDRDataDirectories() {
579         return Arrays.asList(CLDR_DATA_DIRECTORIES);
580     }
581 
582     /**
583      * Given comma separated list "common" or "common,main" return a list of actual files.
584      * Adds subdirectories in STANDARD_SUBDIRS as necessary.
585      */
getCLDRDataDirectories(String list)586     public File[] getCLDRDataDirectories(String list) {
587         final File dir = getCldrBaseDirectory();
588         String stubs[] = list.split(",");
589         File[] ret = new File[stubs.length];
590         for (int i = 0; i < stubs.length; i++) {
591             ret[i] = new File(dir, stubs[i]);
592         }
593         return ret;
594     }
595 
596     /**
597      * Add subdirectories to file list as needed, from STANDARD_SUBDIRS.
598      * <ul><li>map "common","seed" -> "common/main", "seed/main"
599      * <li>but common/main -> common/main
600      * </ul>
601      */
addStandardSubdirectories(String... base)602     public File[] addStandardSubdirectories(String... base) {
603         return addStandardSubdirectories(fileArrayFromStringArray(getCldrBaseDirectory(), base));
604     }
605 
addStandardSubdirectories(File... base)606     public File[] addStandardSubdirectories(File... base) {
607         List<File> ret = new ArrayList<>();
608         //File[] ret = new File[base.length * 2];
609         for (int i = 0; i < base.length; i++) {
610             File baseFile = base[i];
611             String name = baseFile.getName();
612             if (STANDARD_SUBDIRS.contains(name)) {
613                 ret.add(baseFile);
614             } else {
615                 for (String sub : STANDARD_SUBDIRS) {
616                     addIfExists(ret, baseFile, sub);
617                 }
618             }
619         }
620         return ret.toArray(new File[ret.size()]);
621     }
622 
fileArrayFromStringArray(File dir, String... subdirNames)623     public static File[] fileArrayFromStringArray(File dir, String... subdirNames) {
624         File[] fileList = new File[subdirNames.length];
625         int i = 0;
626         for (String item : subdirNames) {
627             fileList[i++] = new File(dir, item);
628         }
629         return fileList;
630     }
631 
addIfExists(List<File> ret, File baseFile, String sub)632     private static void addIfExists(List<File> ret, File baseFile, String sub) {
633         File file = new File(baseFile, sub);
634         if (file.exists()) {
635             ret.add(file);
636         }
637     }
638 
639     /**
640      * Utility function. Recursively add to a list of files. Skips ".svn" and junk directories.
641      * @param directory base directory
642      * @param filter filter to restrict files added
643      * @param toAddTo set to add to
644      * @return returns toAddTo.
645      */
getFilesRecursively(File directory, FilenameFilter filter, Set<File> toAddTo)646     public Set<File> getFilesRecursively(File directory, FilenameFilter filter, Set<File> toAddTo) {
647         File files[] = directory.listFiles();
648         if (files != null) {
649             for (File subfile : files) {
650                 if (subfile.isDirectory()) {
651                     if (!isJunkFile(subfile.getName())) {
652                         getFilesRecursively(subfile, filter, toAddTo);
653                     }
654                 } else if (filter.accept(directory, subfile.getName())) {
655                     toAddTo.add(subfile);
656                 }
657             }
658         }
659         return toAddTo;
660     }
661 
662     /**
663      * Is the filename junk?  (subversion, backup, etc)
664      * @param name
665      * @return
666      */
isJunkFile(String name)667     public static final boolean isJunkFile(String name) {
668         return name.startsWith(".") || (name.startsWith("#")); // Skip:  .svn, .BACKUP,  #backup# files.
669     }
670 
671     /**
672      * Get the value of the debug setting for the calling class; assuming that no debugging is wanted if the property
673      * value cannot be found
674      * @param callingClass
675      * @return
676      * @see {@link #getDebugSettingsFor(Class, boolean)}
677      */
getDebugSettingsFor(Class<?> callingClass)678     public boolean getDebugSettingsFor(Class<?> callingClass) {
679         return getDebugSettingsFor(callingClass, false);
680     }
681 
682     /**
683      * Get the debug settings (whether debugging is enabled for the calling class; This will look for a property corresponding
684      * to the canonical classname +".debug"; if that property cannot be found, the default value will be returned.
685      * @param callingClass
686      * @param defaultValue
687      * @return
688      */
getDebugSettingsFor(Class<?> callingClass, boolean defaultValue)689     public boolean getDebugSettingsFor(Class<?> callingClass, boolean defaultValue) {
690         // avoid NPE
691         if (callingClass == null) {
692             return defaultValue;
693         }
694         return getProperty(callingClass.getCanonicalName() + ".debug", defaultValue);
695     }
696 
697     /**
698      * Get the URL generator for "general purpose" (non chart) use.
699      * @return
700      */
urls()701     public CLDRURLS urls() {
702         if (urls == null) {
703             synchronized (this) {
704                 urls = internalGetUrls();
705             }
706         }
707         return urls;
708     }
709 
710     /**
711      * Get the URL generator for "absolute" (chart, email) use.
712      * By default, this is the same as urls.
713      */
absoluteUrls()714     public CLDRURLS absoluteUrls() {
715         if (absoluteUrls == null) {
716             synchronized (this) {
717                 absoluteUrls = internalGetAbsoluteUrls();
718             }
719         }
720         return absoluteUrls;
721     }
722 
723     /**
724      * Probably would not need to override this.
725      */
internalGetAbsoluteUrls()726     protected CLDRURLS internalGetAbsoluteUrls() {
727         return new StaticCLDRURLS(this.getProperty(CLDRURLS.CLDR_SURVEY_BASE, CLDRURLS.DEFAULT_BASE));
728     }
729 
730     /**
731      * Override this to provide a different URL source for non-absolute URLs.
732      */
internalGetUrls()733     protected CLDRURLS internalGetUrls() {
734         return absoluteUrls();
735     }
736 
737     private CLDRURLS urls = null;
738     private CLDRURLS absoluteUrls = null;
739 
isCldrVersionBefore(int... version)740     public boolean isCldrVersionBefore(int... version) {
741         return getEnglish().getDtdVersionInfo()
742             .compareTo(getVersion(version)) < 0;
743     }
744 
getVersion(int... versionInput)745     public static VersionInfo getVersion(int... versionInput) {
746         int[] version = new int[4];
747         for (int i = 0; i < versionInput.length; ++i) {
748             version[i] = versionInput[i];
749         }
750         return VersionInfo.getInstance(version[0], version[1], version[2],
751             version[3]);
752     }
753 }
754