• 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                 };
324                 commonAndSeedAndMainAndAnnotationsFactory = SimpleFactory.make(paths, ".*");
325             }
326         }
327         return commonAndSeedAndMainAndAnnotationsFactory;
328     }
329 
getFullCldrFactory()330     public Factory getFullCldrFactory() {
331         synchronized (FULL_FACTORY_SYNC) {
332             if (fullFactory == null) {
333                 File[] paths = { new File(CLDRPaths.MAIN_DIRECTORY), new File(CLDRPaths.SEED_DIRECTORY) };
334                 fullFactory = SimpleFactory.make(paths, ".*");
335             }
336         }
337         return fullFactory;
338     }
339 
getSupplementalFactory()340     public Factory getSupplementalFactory() {
341         synchronized (CLDR_FACTORY_SYNC) {
342             if (supplementalFactory == null) {
343                 supplementalFactory = Factory.make(CLDRPaths.DEFAULT_SUPPLEMENTAL_DIRECTORY, ".*");
344             }
345         }
346         return supplementalFactory;
347     }
348 
getEnglish()349     public CLDRFile getEnglish() {
350         return getCLDRFile("en", true);
351     }
352 
getCLDRFile(String locale, boolean resolved)353     public CLDRFile getCLDRFile(String locale, boolean resolved) {
354 
355         return resolved ? cldrFileResolvedCache.getUnchecked(locale) : cldrFileUnresolvedCache.getUnchecked(locale);
356 
357     }
358 
getRoot()359     public CLDRFile getRoot() {
360         return getCLDRFile("root", true);
361     }
362 
getCollatorRoot()363     public Collator getCollatorRoot() {
364         synchronized (GET_COLLATOR_SYNC_ROOT) {
365             if (colRoot == null) {
366                 CLDRFile root = getCollationFactory().make("root", false);
367                 String rules = root.getStringValue("//ldml/collations/collation[@type=\"emoji\"][@visibility=\"external\"]/cr");
368                 try {
369                     colRoot = new RuleBasedCollator(rules);
370                 } catch (Exception e) {
371                     colRoot = (RuleBasedCollator) getCollator();
372                     return colRoot;
373                 }
374                 colRoot.setStrength(Collator.IDENTICAL);
375                 colRoot.setNumericCollation(true);
376                 colRoot.freeze();
377             }
378         }
379         return colRoot;
380     }
381 
getCollator()382     public Collator getCollator() {
383         synchronized (GET_COLLATOR_SYNC) {
384             if (col == null) {
385                 col = (RuleBasedCollator) Collator.getInstance(ULocale.forLanguageTag("en-u-co-emoji"));
386                 col.setStrength(Collator.IDENTICAL);
387                 col.setNumericCollation(true);
388                 col.freeze();
389             }
390         }
391         return col;
392     }
393 
getPhase()394     public synchronized Phase getPhase() {
395         if (phase == null) {
396             if (getEnvironment() == Environment.UNITTEST) {
397                 phase = Phase.BUILD;
398             } else {
399                 phase = Phase.SUBMISSION;
400             }
401         }
402         return phase;
403     }
404 
405     @Override
getProperty(String key, String d)406     public String getProperty(String key, String d) {
407         String result = getProperty(key);
408         if (result == null) return d;
409         return result;
410     }
411 
412     private Set<String> shown = new HashSet<String>();
413 
414     private Map<String, String> localSet = null;
415 
416     @Override
get(Object key)417     public String get(Object key) {
418         return getProperty(key.toString());
419     }
420 
421     @Override
getProperty(String key)422     public String getProperty(String key) {
423         String result = null;
424         if (localSet != null) {
425             result = localSet.get(key);
426         }
427         if (result == null) {
428             result = System.getProperty(key);
429         }
430         if (result == null) {
431             result = System.getProperty(key.toUpperCase(Locale.ENGLISH));
432         }
433         if (result == null) {
434             result = System.getProperty(key.toLowerCase(Locale.ENGLISH));
435         }
436         if (result == null) {
437             result = System.getenv(key);
438         }
439         if (DEBUG && !shown.contains(key)) {
440             logln("-D" + key + "=" + result);
441             shown.add(key);
442         }
443         return result;
444     }
445 
446     private Environment curEnvironment = null;
447 
getEnvironment()448     public Environment getEnvironment() {
449         if (curEnvironment == null) {
450             String envString = getProperty("CLDR_ENVIRONMENT");
451             if (envString != null) {
452                 curEnvironment = Environment.valueOf(envString.trim());
453             }
454             if (curEnvironment == null) {
455                 curEnvironment = getDefaultEnvironment();
456             }
457         }
458         return curEnvironment;
459     }
460 
461     /**
462      * If no environment is defined, what is the default?
463      * @return
464      */
getDefaultEnvironment()465     protected Environment getDefaultEnvironment() {
466         return Environment.LOCAL;
467     }
468 
setEnvironment(Environment environment)469     public void setEnvironment(Environment environment) {
470         curEnvironment = environment;
471     }
472 
473     /**
474      * For test use only. Will throw an exception in non test environments.
475      * @param k
476      * @param v
477      * @return
478      */
479     @Override
setProperty(String k, String v)480     public Object setProperty(String k, String v) {
481         if (getEnvironment() != Environment.UNITTEST) {
482             throw new InternalError("setProperty() only valid in UNITTEST Environment.");
483         }
484         if (localSet == null) {
485             localSet = new ConcurrentHashMap<String, String>();
486         }
487         shown.remove(k); // show it again with -D
488         return localSet.put(k, v);
489     }
490 
491     @Override
put(Object k, Object v)492     public Object put(Object k, Object v) {
493         return setProperty(k.toString(), v.toString());
494     }
495 
496     /**
497      * Return true if the value indicates 'true'
498      * @param k key
499      * @param defVal default value
500      * @return
501      */
getProperty(String k, boolean defVal)502     public boolean getProperty(String k, boolean defVal) {
503         String val = getProperty(k, defVal ? "true" : null);
504         if (val == null) {
505             return false;
506         } else {
507             val = val.trim().toLowerCase();
508             return (val.equals("true") || val.equals("t") || val.equals("yes") || val.equals("y"));
509         }
510     }
511 
512     /**
513      * Return a numeric property
514      * @param k key
515      * @param defVal default value
516      * @return
517      */
getProperty(String k, int defVal)518     public int getProperty(String k, int defVal) {
519         String val = getProperty(k, Integer.toString(defVal));
520         if (val == null) {
521             return defVal;
522         } else {
523             try {
524                 return Integer.parseInt(val);
525             } catch (NumberFormatException nfe) {
526                 return defVal;
527             }
528         }
529     }
530 
getCldrBaseDirectory()531     public File getCldrBaseDirectory() {
532         String dir = getProperty("CLDR_DIR", null);
533         if (dir != null) {
534             return new File(dir);
535         } else {
536             return null;
537         }
538     }
539 
540     /**
541      * Get all CLDR XML files in the CLDR base directory.
542      * @return
543      */
getAllCLDRFilesEndingWith(final String suffix)544     public Set<File> getAllCLDRFilesEndingWith(final String suffix) {
545         FilenameFilter filter = new FilenameFilter() {
546             public boolean accept(File dir, String name) {
547                 return name.endsWith(suffix) && !isJunkFile(name); // skip junk and backup files
548             }
549         };
550         final File dir = getCldrBaseDirectory();
551         Set<File> list;
552         list = getCLDRFilesMatching(filter, dir);
553         return list;
554     }
555 
556     /**
557      * Return all CLDR data files matching this filter
558      * @param filter matching filter
559      * @param baseDir base directory, see {@link #getCldrBaseDirectory()}
560      * @return set of files
561      */
getCLDRFilesMatching(FilenameFilter filter, final File baseDir)562     public Set<File> getCLDRFilesMatching(FilenameFilter filter, final File baseDir) {
563         Set<File> list;
564         list = new LinkedHashSet<File>();
565         for (String subdir : getCLDRDataDirectories()) {
566             getFilesRecursively(new File(baseDir, subdir), filter, list);
567         }
568         return list;
569     }
570 
571     /**
572      * TODO: better place for these constants?
573      */
574     private static final String COMMON_DIR = "common";
575     /**
576      * TODO: better place for these constants?
577      */
578     private static final String EXEMPLARS_DIR = "exemplars";
579     /**
580      * TODO: better place for these constants?
581      */
582     private static final String SEED_DIR = "seed";
583     /**
584      * TODO: better place for these constants?
585      */
586     private static final String KEYBOARDS_DIR = "keyboards";
587     private static final String MAIN_DIR = "main";
588     private static final String ANNOTATIONS_DIR = "annotations";
589     private static final String SUBDIVISIONS_DIR = "subdivisions";
590 
591     /**
592      * TODO: better place for these constants?
593      */
594     private static final String CLDR_DATA_DIRECTORIES[] = { COMMON_DIR, SEED_DIR, KEYBOARDS_DIR, EXEMPLARS_DIR };
595     private static final ImmutableSet<String> STANDARD_SUBDIRS = ImmutableSet.of(MAIN_DIR, ANNOTATIONS_DIR, SUBDIVISIONS_DIR);
596 
597     /**
598      * Get a list of CLDR directories containing actual data
599      * @return an iterable containing the names of all CLDR data subdirectories
600      */
getCLDRDataDirectories()601     public Iterable<String> getCLDRDataDirectories() {
602         return Arrays.asList(CLDR_DATA_DIRECTORIES);
603     }
604 
605     /**
606      * Given comma separated list "common" or "common,main" return a list of actual files.
607      * Adds subdirectories in STANDARD_SUBDIRS as necessary.
608      */
getCLDRDataDirectories(String list)609     public File[] getCLDRDataDirectories(String list) {
610         final File dir = getCldrBaseDirectory();
611         String stubs[] = list.split(",");
612         File[] ret = new File[stubs.length];
613         for (int i = 0; i < stubs.length; i++) {
614             ret[i] = new File(dir, stubs[i]);
615         }
616         return ret;
617     }
618 
619     /**
620      * Add subdirectories to file list as needed, from STANDARD_SUBDIRS.
621      * <ul><li>map "common","seed" -> "common/main", "seed/main"
622      * <li>but common/main -> common/main
623      * </ul>
624      */
addStandardSubdirectories(String... base)625     public File[] addStandardSubdirectories(String... base) {
626         return addStandardSubdirectories(fileArrayFromStringArray(getCldrBaseDirectory(), base));
627     }
628 
addStandardSubdirectories(File... base)629     public File[] addStandardSubdirectories(File... base) {
630         List<File> ret = new ArrayList<>();
631         //File[] ret = new File[base.length * 2];
632         for (int i = 0; i < base.length; i++) {
633             File baseFile = base[i];
634             String name = baseFile.getName();
635             if (STANDARD_SUBDIRS.contains(name)) {
636                 ret.add(baseFile);
637             } else {
638                 for (String sub : STANDARD_SUBDIRS) {
639                     addIfExists(ret, baseFile, sub);
640                 }
641             }
642         }
643         return ret.toArray(new File[ret.size()]);
644     }
645 
fileArrayFromStringArray(File dir, String... subdirNames)646     private File[] fileArrayFromStringArray(File dir, String... subdirNames) {
647         File[] fileList = new File[subdirNames.length];
648         int i = 0;
649         for (String item : subdirNames) {
650             fileList[i++] = new File(dir, item);
651         }
652         return fileList;
653     }
654 
addIfExists(List<File> ret, File baseFile, String sub)655     private void addIfExists(List<File> ret, File baseFile, String sub) {
656         File file = new File(baseFile, sub);
657         if (file.exists()) {
658             ret.add(file);
659         }
660     }
661 
662     /**
663      * Utility function. Recursively add to a list of files. Skips ".svn" and junk directories.
664      * @param directory base directory
665      * @param filter filter to restrict files added
666      * @param toAddTo set to add to
667      * @return returns toAddTo.
668      */
getFilesRecursively(File directory, FilenameFilter filter, Set<File> toAddTo)669     public Set<File> getFilesRecursively(File directory, FilenameFilter filter, Set<File> toAddTo) {
670         File files[] = directory.listFiles();
671         if (files != null) {
672             for (File subfile : files) {
673                 if (subfile.isDirectory()) {
674                     if (!isJunkFile(subfile.getName())) {
675                         getFilesRecursively(subfile, filter, toAddTo);
676                     }
677                 } else if (filter.accept(directory, subfile.getName())) {
678                     toAddTo.add(subfile);
679                 }
680             }
681         }
682         return toAddTo;
683     }
684 
685     /**
686      * Is the filename junk?  (subversion, backup, etc)
687      * @param name
688      * @return
689      */
isJunkFile(String name)690     public static final boolean isJunkFile(String name) {
691         return name.startsWith(".") || (name.startsWith("#")); // Skip:  .svn, .BACKUP,  #backup# files.
692     }
693 
694     /**
695      * Get the value of the debug setting for the calling class; assuming that no debugging is wanted if the property
696      * value cannot be found
697      * @param callingClass
698      * @return
699      * @see {@link #getDebugSettingsFor(Class, boolean)}
700      */
getDebugSettingsFor(Class<?> callingClass)701     public boolean getDebugSettingsFor(Class<?> callingClass) {
702         return getDebugSettingsFor(callingClass, false);
703     }
704 
705     /**
706      * Get the debug settings (whether debugging is enabled for the calling class; This will look for a property corresponding
707      * to the canonical classname +".debug"; if that property cannot be found, the default value will be returned.
708      * @param callingClass
709      * @param defaultValue
710      * @return
711      */
getDebugSettingsFor(Class<?> callingClass, boolean defaultValue)712     public boolean getDebugSettingsFor(Class<?> callingClass, boolean defaultValue) {
713         // avoid NPE
714         if (callingClass == null) {
715             return defaultValue;
716         }
717         return getProperty(callingClass.getCanonicalName() + ".debug", defaultValue);
718     }
719 
720     /**
721      * Get the URL generator for "general purpose" (non chart) use.
722      * @return
723      */
urls()724     public CLDRURLS urls() {
725         if (urls == null) {
726             synchronized (this) {
727                 urls = internalGetUrls();
728             }
729         }
730         return urls;
731     }
732 
733     /**
734      * Get the URL generator for "absolute" (chart, email) use.
735      * By default, this is the same as urls.
736      */
absoluteUrls()737     public CLDRURLS absoluteUrls() {
738         if (absoluteUrls == null) {
739             synchronized (this) {
740                 absoluteUrls = internalGetAbsoluteUrls();
741             }
742         }
743         return absoluteUrls;
744     }
745 
746     /**
747      * Probably would not need to override this.
748      */
internalGetAbsoluteUrls()749     protected CLDRURLS internalGetAbsoluteUrls() {
750         return new StaticCLDRURLS(this.getProperty(CLDRURLS.CLDR_SURVEY_BASE, CLDRURLS.DEFAULT_BASE));
751     }
752 
753     /**
754      * Override this to provide a different URL source for non-absolute URLs.
755      */
internalGetUrls()756     protected CLDRURLS internalGetUrls() {
757         return absoluteUrls();
758     }
759 
760     private CLDRURLS urls = null;
761     private CLDRURLS absoluteUrls = null;
762 
isCldrVersionBefore(int... version)763     public boolean isCldrVersionBefore(int... version) {
764         return getEnglish().getDtdVersionInfo()
765             .compareTo(getVersion(version)) < 0;
766     }
767 
getVersion(int... versionInput)768     public static VersionInfo getVersion(int... versionInput) {
769         int[] version = new int[4];
770         for (int i = 0; i < versionInput.length; ++i) {
771             version[i] = versionInput[i];
772         }
773         return VersionInfo.getInstance(version[0], version[1], version[2],
774             version[3]);
775     }
776 }
777