• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.util;
2 
3 import java.io.File;
4 import java.util.ArrayList;
5 import java.util.Collections;
6 import java.util.Iterator;
7 import java.util.List;
8 import java.util.Set;
9 import java.util.TreeSet;
10 
11 import org.unicode.cldr.util.CLDRFile.DraftStatus;
12 import org.unicode.cldr.util.CLDRLocale.SublocaleProvider;
13 import org.unicode.cldr.util.XMLSource.ResolvingSource;
14 
15 /**
16  * A factory is the normal method to produce a set of CLDRFiles from a directory of XML files.
17  * See SimpleFactory for a concrete subclass.
18  */
19 public abstract class Factory implements SublocaleProvider {
20     private boolean ignoreExplicitParentLocale = false;
21 
22     /**
23      * Whether to ignore explicit parent locale / fallback script behavior
24      * with a resolving source.
25      *
26      * Long story short, call setIgnoreExplictParentLocale(true) for collation trees.
27      */
setIgnoreExplicitParentLocale(boolean newIgnore)28     public Factory setIgnoreExplicitParentLocale(boolean newIgnore) {
29         ignoreExplicitParentLocale = newIgnore;
30         return this;
31     }
32 
33     /**
34      * Flag to set more verbose output in makeServolingSource
35      */
36     private static final boolean DEBUG_FACTORY = false;
37 
38     private File supplementalDirectory = null;
39 
40     /**
41      * Note, the source director(ies) may be a list (seed/common). Therefore, this function is deprecated
42      *
43      * @deprecated
44      * @return the first directory
45      */
46     @Deprecated
getSourceDirectory()47     public String getSourceDirectory() {
48         return getSourceDirectories()[0].getAbsolutePath();
49     }
50 
51     /**
52      * Note, the source director(ies) may be a list (seed/common).
53      *
54      * @return the first directory
55      */
getSourceDirectories()56     public abstract File[] getSourceDirectories();
57 
58     /**
59      * Which source directory does this particular localeID belong to?
60      *
61      * @param localeID
62      * @return
63      */
64     @Deprecated
getSourceDirectoryForLocale(String localeID)65     public final File getSourceDirectoryForLocale(String localeID) {
66         List<File> temp = getSourceDirectoriesForLocale(localeID);
67         return temp == null ? null : temp.get(0);
68     }
69 
70     /**
71      * Classify the tree according to type (maturity)
72      *
73      * @author srl
74      *
75      */
76     public enum SourceTreeType {
77         common, seed, other
78     }
79 
80     /**
81      * Returns the source tree type of either an XML file or its parent directory.
82      *
83      * @param fileOrDir
84      * @return
85      */
getSourceTreeType(File fileOrDir)86     public static final SourceTreeType getSourceTreeType(File fileOrDir) {
87         if (fileOrDir == null) return null;
88         File parentDir = fileOrDir.isFile() ? fileOrDir.getParentFile() : fileOrDir;
89         File grandparentDir = parentDir.getParentFile();
90 
91         try {
92             return SourceTreeType.valueOf(grandparentDir.getName());
93         } catch (IllegalArgumentException iae) {
94             try {
95                 return SourceTreeType.valueOf(parentDir.getName());
96             } catch (IllegalArgumentException iae2) {
97                 return SourceTreeType.other;
98             }
99         }
100     }
101 
102     public enum DirectoryType {
103         main, supplemental, bcp47, casing, collation, dtd, rbnf, segments, transforms, other
104     }
105 
getDirectoryType(File fileOrDir)106     public static final DirectoryType getDirectoryType(File fileOrDir) {
107         if (fileOrDir == null) return null;
108         File parentDir = fileOrDir.isFile() ? fileOrDir.getParentFile() : fileOrDir;
109 
110         try {
111             return DirectoryType.valueOf(parentDir.getName());
112         } catch (IllegalArgumentException iae2) {
113             return DirectoryType.other;
114         }
115     }
116 
handleMake(String localeID, boolean resolved, DraftStatus madeWithMinimalDraftStatus)117     protected abstract CLDRFile handleMake(String localeID, boolean resolved, DraftStatus madeWithMinimalDraftStatus);
118 
make(String localeID, boolean resolved, DraftStatus madeWithMinimalDraftStatus)119     public CLDRFile make(String localeID, boolean resolved, DraftStatus madeWithMinimalDraftStatus) {
120         return handleMake(localeID, resolved, madeWithMinimalDraftStatus)
121             .setSupplementalDirectory(getSupplementalDirectory());
122     }
123 
make(String localeID, boolean resolved, boolean includeDraft)124     public CLDRFile make(String localeID, boolean resolved, boolean includeDraft) {
125         return make(localeID, resolved, includeDraft ? DraftStatus.unconfirmed : DraftStatus.approved);
126     }
127 
make(String localeID, boolean resolved)128     public CLDRFile make(String localeID, boolean resolved) {
129         return make(localeID, resolved, getMinimalDraftStatus());
130     }
131 
makeWithFallback(String localeID)132     public CLDRFile makeWithFallback(String localeID) {
133         return makeWithFallback(localeID, getMinimalDraftStatus());
134     }
135 
makeWithFallback(String localeID, DraftStatus madeWithMinimalDraftStatus)136     public CLDRFile makeWithFallback(String localeID, DraftStatus madeWithMinimalDraftStatus) {
137         String currentLocaleID = localeID;
138         Set<String> availableLocales = this.getAvailable();
139         while (!availableLocales.contains(currentLocaleID) && !"root".equals(currentLocaleID)) {
140             currentLocaleID = LocaleIDParser.getParent(currentLocaleID, ignoreExplicitParentLocale);
141         }
142         return make(currentLocaleID, true, madeWithMinimalDraftStatus);
143     }
144 
makeResolvingSource(List<XMLSource> sources)145     public static XMLSource makeResolvingSource(List<XMLSource> sources) {
146         return new ResolvingSource(sources);
147     }
148 
149     /**
150      * Temporary wrapper for creating an XMLSource. This is a hack and should
151      * only be used in the Survey Tool for now.
152      *
153      * @param localeID
154      * @return
155      */
makeSource(String localeID)156     public final XMLSource makeSource(String localeID) {
157         return make(localeID, false).dataSource;
158     }
159 
160     /**
161      * Creates a resolving source for the given locale ID.
162      *
163      * @param localeID
164      * @param madeWithMinimalDraftStatus
165      * @return
166      */
makeResolvingSource(String localeID, DraftStatus madeWithMinimalDraftStatus)167     protected ResolvingSource makeResolvingSource(String localeID, DraftStatus madeWithMinimalDraftStatus) {
168         List<XMLSource> sourceList = new ArrayList<>();
169         String curLocale = localeID;
170         while (curLocale != null) {
171             if (DEBUG_FACTORY) {
172                 System.out.println("Factory.makeResolvingSource: calling handleMake for locale " +
173                     curLocale + " and MimimalDraftStatus " + madeWithMinimalDraftStatus);
174             }
175             CLDRFile file = handleMake(curLocale, false, madeWithMinimalDraftStatus);
176             if (file == null) {
177                 throw new NullPointerException(this + ".handleMake returned a null CLDRFile for " + curLocale);
178             }
179             XMLSource source = file.dataSource;
180             sourceList.add(source);
181             curLocale = LocaleIDParser.getParent(curLocale, ignoreExplicitParentLocale);
182         }
183         return new ResolvingSource(sourceList);
184     }
185 
getMinimalDraftStatus()186     public abstract DraftStatus getMinimalDraftStatus();
187 
188     /**
189      * Convenience static
190      *
191      * @param path
192      * @param string
193      * @return
194      */
make(String path, String string)195     public static Factory make(String path, String string) {
196         try {
197             return SimpleFactory.make(path, string);
198         } catch (Exception e) {
199             throw new IllegalArgumentException("path: " + path + "; string: " + string, e);
200         }
201     }
202 
203     /**
204      * Convenience static
205      *
206      * @param mainDirectory
207      * @param string
208      * @param approved
209      * @return
210      */
make(String mainDirectory, String string, DraftStatus approved)211     public static Factory make(String mainDirectory, String string, DraftStatus approved) {
212         return SimpleFactory.make(mainDirectory, string, approved);
213     }
214 
215     /**
216      * Get a set of the available locales for the factory.
217      */
getAvailable()218     public Set<String> getAvailable() {
219         return Collections.unmodifiableSet(handleGetAvailable());
220     }
221 
handleGetAvailable()222     protected abstract Set<String> handleGetAvailable();
223 
224     /**
225      * Get a set of the available language locales (according to isLanguage).
226      */
getAvailableLanguages()227     public Set<String> getAvailableLanguages() {
228         Set<String> result = new TreeSet<>();
229         for (Iterator<String> it = handleGetAvailable().iterator(); it.hasNext();) {
230             String s = it.next();
231             if (XPathParts.isLanguage(s)) result.add(s);
232         }
233         return result;
234     }
235 
236     /**
237      * Get a set of the locales that have the given parent (according to isSubLocale())
238      *
239      * @param isProper
240      *            if false, then parent itself will match
241      */
getAvailableWithParent(String parent, boolean isProper)242     public Set<String> getAvailableWithParent(String parent, boolean isProper) {
243         Set<String> result = new TreeSet<>();
244 
245         for (Iterator<String> it = handleGetAvailable().iterator(); it.hasNext();) {
246             String s = it.next();
247             int relation = XPathParts.isSubLocale(parent, s);
248             if (relation >= 0 && !(isProper && relation == 0)) result.add(s);
249         }
250         return result;
251     }
252 
getSupplementalDirectory()253     public File getSupplementalDirectory() {
254         return supplementalDirectory;
255     }
256 
257     /**
258      * Sets the supplemental directory to be used by this Factory and CLDRFiles
259      * created by this Factory.
260      *
261      * @param supplementalDirectory
262      * @return
263      */
setSupplementalDirectory(File supplementalDirectory)264     public Factory setSupplementalDirectory(File supplementalDirectory) {
265         this.supplementalDirectory = supplementalDirectory;
266         return this;
267     }
268 
269     // TODO(jchye): Clean this up.
getSupplementalData()270     public CLDRFile getSupplementalData() {
271         try {
272             return make("supplementalData", false);
273         } catch (RuntimeException e) {
274             return Factory.make(getSupplementalDirectory().getPath(), ".*").make("supplementalData", false);
275         }
276     }
277 
getSupplementalMetadata()278     public CLDRFile getSupplementalMetadata() {
279         try {
280             return make("supplementalMetadata", false);
281         } catch (RuntimeException e) {
282             return Factory.make(getSupplementalDirectory().getPath(), ".*").make("supplementalMetadata", false);
283         }
284     }
285 
286     /**
287      * These factory implementations don't do any caching.
288      */
289     @Override
subLocalesOf(CLDRLocale forLocale)290     public Set<CLDRLocale> subLocalesOf(CLDRLocale forLocale) {
291         return calculateSubLocalesOf(forLocale, getAvailableCLDRLocales());
292     }
293 
294     /**
295      * Helper function.
296      *
297      * @return
298      */
getAvailableCLDRLocales()299     public Set<CLDRLocale> getAvailableCLDRLocales() {
300         return CLDRLocale.getInstance(getAvailable());
301     }
302 
303     /**
304      * Helper function. Does not cache.
305      *
306      * @param locale
307      * @param available
308      * @return
309      */
calculateSubLocalesOf(CLDRLocale locale, Set<CLDRLocale> available)310     public Set<CLDRLocale> calculateSubLocalesOf(CLDRLocale locale, Set<CLDRLocale> available) {
311         Set<CLDRLocale> sub = new TreeSet<>();
312         for (CLDRLocale l : available) {
313             if (l.getParent() == locale) {
314                 sub.add(l);
315             }
316         }
317         return sub;
318     }
319 
320     /**
321      * Get all of the files in the source directories that match localeName (which is really xml file name).
322      * @param localeName
323      * @return
324      */
getSourceDirectoriesForLocale(String localeName)325     public abstract List<File> getSourceDirectoriesForLocale(String localeName);
326 }
327