• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.api;
2 
3 import java.util.function.Consumer;
4 
5 /**
6  * An immutable, reusable CLDR data instance on which visitors can be accepted to process paths
7  * and values, or for which values can be looked up by their corresponding distinguishing path.
8  */
9 public interface CldrData {
10     /**
11      * Accepts the given visitor over all path/value pairs of this CLDR data instance. Note
12      * that value visitors only visit complete "leaf" paths which have associated values, and
13      * never see partial prefix paths.
14      *
15      * <p>Since a value visitor never sees partial path prefixes, a value visitor can never
16      * defer to a prefix visitor (since there's nothing "below" the paths that a value
17      * visitor visits).
18      *
19      * @param order the order in which visitation should occur.
20      * @param visitor the visitor to process CLDR data.
21      */
accept(PathOrder order, ValueVisitor visitor)22     void accept(PathOrder order, ValueVisitor visitor);
23 
24     /**
25      * Accepts the given visitor over all partial path prefixes of this CLDR data instance.
26      * Note that, on its own, this visitor will never see CDLR values, or even complete paths.
27      * It only sees the prefix paths under which values can exist.
28      *
29      * <p>Typically an instance of a {@link PrefixVisitor} would by used to identify a specific
30      * sub-hierarchy of data based on the prefix path, and then defer to a {@link ValueVisitor
31      * value visitor} or another {@link PrefixVisitor prefix visitor} to handle it.
32      *
33      * <p>Since {@link PrefixVisitor} requires that paths are visited in at least {@link
34      * PathOrder#NESTED_GROUPING nested grouping} order, the actual order of visitation may be
35      * more strict than the specified value.
36      *
37      * @param order the order in which visitation should occur.
38      * @param visitor the visitor to process CLDR data.
39      */
accept(PathOrder order, PrefixVisitor visitor)40     default void accept(PathOrder order, PrefixVisitor visitor) {
41         PrefixVisitorHost.accept(this::accept, order, visitor);
42     }
43 
44     /**
45      * Returns a {@link CldrValue} for a given distinguishing path.
46      *
47      * @param path the complete distinguishing path associated with a CLDR value.
48      * @return the CldrValue for the given path, if it exists, or else {@code null}.
49      */
get(CldrPath path)50     /* @Nullable */ CldrValue get(CldrPath path);
51 
52     /** Ordering options for path visitation. */
53     // TODO (CLDR-13275): Remove PathOrder and stabilize tools to use only DTD order.
54     enum PathOrder {
55         /**
56          * Visits {@code CldrPath}s in an arbitrary, potentially unstable, order. Only use this
57          * ordering if your visitation code is completely robust against changes to visitation
58          * ordering. This is expected to be the fastest ordering option, but may change over time.
59          *
60          * <p>Note that if this value is specified for a method which requires a stricter ordering
61          * for correctness, then the stricter ordering will be used. Note also that the ordering of
62          * visitation may change between visitations if a more strictly ordered visitation was
63          * required in the meantime (since paths may be re-ordered and cached).
64          */
65         ARBITRARY,
66 
67         /**
68          * Visits {@code CldrPath}s in an order which enforces the grouping of nested sub-paths.
69          * With this ordering, all common "parent" path prefixes will be visited consecutively,
70          * grouping together all "child" paths. However it is important to note that no other
71          * promises are made and this ordering is still unstable and can change over time.
72          *
73          * <p>This ordering is useful for constructing nested visitors over some subset of paths
74          * (e.g. processing all paths with a certain prefix consecutively).
75          *
76          * <p>For example, using {@code NESTED_GROUPING} the paths {@code //a/b/c/d},
77          * {@code //a/b/e/f}, {@code //a/x/y/z} could be ordered like any of the following:
78          * <ul>
79          * <li>{@code //a/b/c/d} &lt; {@code //a/b/e/f} &lt; {@code //a/x/y/z}
80          * <li>{@code //a/b/e/f} &lt; {@code //a/b/c/d} &lt; {@code //a/x/y/z}
81          * <li>{@code //a/x/y/z} &lt; {@code //a/b/c/d} &lt; {@code //a/b/e/f}
82          * <li>{@code //a/x/y/z} &lt; {@code //a/b/e/f} &lt; {@code //a/b/c/d}
83          * </ul>
84          * The only disallowed ordering here is one in which {@code //a/x/y/z} lies between the
85          * other paths.
86          */
87         NESTED_GROUPING,
88 
89         /**
90          * Visits {@code CldrPath}s in the order defined by the CLDR DTD declaration. This ordering
91          * naturally enforces "nested grouping" of paths but additionally sorts paths so they are
92          * visited in the order defined by the DTD of the {@link CldrDataType}.
93          *
94          * <p>This ordering is more stable than {@link PathOrder#NESTED_GROUPING}, but may still
95          * change between different DTD versions.
96          */
97         DTD
98     }
99 
100     /** A visitor for complete "leaf" paths and their associated values. */
101     interface ValueVisitor {
102         /** Callback method invoked for each value encountered by this visitor. */
visit(CldrValue value)103         void visit(CldrValue value);
104     }
105 
106     /** A visitor for partial path prefixes. */
107     @SuppressWarnings("unused") // For unused arguments in no-op default methods.
108     interface PrefixVisitor {
109         /**
110          * A controller API for allow prefix visitors to delegate sub-hierarchy visitation. A
111          * context is passed into the {@link #visitPrefixStart(CldrPath, Context)} method in order
112          * to allow the visitor to "install" a new visitor to handle the sub-hierarchy root at the
113          * current path prefix.
114          */
115         interface Context {
116             /**
117              * Installs a value visitor at the current point in the visitation. The given visitor
118              * will be called for all the values below this point in the path hierarchy, and the
119              * current visitor will be automatically restored once visitation is complete.
120              *
121              * @param visitor a visitor to process the CLDR data sub-hierarchy rooted at the
122              *                current path prefix.
123              */
install(ValueVisitor visitor)124             default void install(ValueVisitor visitor) {
125                 install(visitor, v -> {});
126             }
127 
128             /**
129              * Installs a value visitor at the current point in the visitation. The given visitor
130              * will be called for all the values below this point in the path hierarchy, and the
131              * current visitor will be automatically restored once visitation is complete.
132              *
133              * @param visitor a visitor to process the CLDR data sub-hierarchy rooted at the
134              *                current path prefix.
135              * @param doneHandler a handler invoked just before the visitor is uninstalled.
136              */
install(T visitor, Consumer<T> doneHandler)137             <T extends ValueVisitor> void install(T visitor, Consumer<T> doneHandler);
138 
139             /**
140              * Installs a prefix visitor at the current point in the visitation. The given visitor
141              * will be called for all the start/end events below this point in the path hierarchy,
142              * and the current visitor will be automatically restored once visitation is complete.
143              *
144              * @param visitor a visitor to process the CLDR data sub-hierarchy rooted at the
145              *                current path prefix.
146              */
install(PrefixVisitor visitor)147             default void install(PrefixVisitor visitor) {
148                 install(visitor, v -> {});
149             }
150 
151             /**
152              * Installs a prefix visitor at the current point in the visitation. The given visitor
153              * will be called for all the start/end events below this point in the path hierarchy,
154              * and the current visitor will be automatically restored once visitation is complete.
155              *
156              * @param visitor a visitor to process the CLDR data sub-hierarchy rooted at the
157              *                current path prefix.
158              * @param doneHandler a handler invoked just before the visitor is uninstalled.
159              */
install(T visitor, Consumer<T> doneHandler)160             <T extends PrefixVisitor> void install(T visitor, Consumer<T> doneHandler);
161         }
162 
163         /**
164          * Callback method invoked for each partial path prefix encountered by this visitor.
165          *
166          * <p>A typical implementation of this method would test the given path to see if it's the
167          * root of a desired sub-hierarchy and (if it matches) begin some sub-hierarchy processing,
168          * which would often include installing a new visitor via the given context.
169          *
170          * @param prefix a path prefix processed as part of some visitation over CLDR data.
171          * @param context a mechanism for installing sub-hierarchy visitors rooted at this point in
172          *                the visitation.
173          */
visitPrefixStart(CldrPath prefix, Context context)174         default void visitPrefixStart(CldrPath prefix, Context context) {}
175 
176         /**
177          * Callback method invoked to signal the end of some sub-hierarchy visitation. This method
178          * is invoked exactly once for each call to {@link #visitPrefixStart(CldrPath, Context)},
179          * in the opposite "stack" order with the same path prefix. This means that if this visitor
180          * installs a sub-visitor during a call to {@code visitPrefixStart()} then the next
181          * callback made to this visitor will be a call to {@code visitPrefixEnd()} with the same
182          * path prefix.
183          *
184          * <p>A typical implementation of this method would detect the end of some expected
185          * sub-visitation and do post-processing on the data.
186          *
187          * @param prefix a path prefix corresponding to the end of some previously started
188          *               sub-hierarchy visitation.
189          */
visitPrefixEnd(CldrPath prefix)190         default void visitPrefixEnd(CldrPath prefix) {}
191 
192         /**
193          * Callback method invoked for each value encountered by this visitor. This is equivalent
194          * to the {@link ValueVisitor#visit(CldrValue)} method but is not normally needed for
195          * prefix visitors (which are expected to delegate to a separate ValueVisitor). This
196          * method is useful for implementing visitors with full coverage of all paths and values
197          * in the {@link CldrData} hierarchy.
198          */
visitValue(CldrValue value)199         default void visitValue(CldrValue value) {}
200     }
201 }
202