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