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