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} < {@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 * 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