001/* 002 * Configurate 003 * Copyright (C) zml and Configurate contributors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.spongepowered.configurate.reference; 018 019import io.leangen.geantyref.TypeToken; 020import org.checkerframework.checker.nullness.qual.Nullable; 021import org.spongepowered.configurate.ConfigurateException; 022import org.spongepowered.configurate.ConfigurationNode; 023import org.spongepowered.configurate.NodePath; 024import org.spongepowered.configurate.ScopedConfigurationNode; 025import org.spongepowered.configurate.loader.ConfigurationLoader; 026import org.spongepowered.configurate.reactive.Publisher; 027import org.spongepowered.configurate.reactive.TransactionalSubscriber; 028import org.spongepowered.configurate.serialize.SerializationException; 029 030import java.nio.file.Path; 031import java.util.Map; 032import java.util.concurrent.ForkJoinPool; 033import java.util.function.Function; 034 035/** 036 * An updating reference to a base configuration node. 037 * 038 * @param <N> the type of node to work with 039 * @since 4.0.0 040 */ 041public interface ConfigurationReference<N extends ConfigurationNode> extends AutoCloseable { 042 043 /** 044 * Create a new configuration reference that will only update when loaded. 045 * 046 * @param loader the loader to load and save from 047 * @param <N> the type of node 048 * @return the newly created reference, with an initial load performed 049 * @throws ConfigurateException if the configuration contained fails to load 050 * @since 4.0.0 051 */ 052 static <N extends ScopedConfigurationNode<N>> ConfigurationReference<N> 053 fixed(ConfigurationLoader<? extends N> loader) throws ConfigurateException { 054 final ConfigurationReference<N> ret = new ManualConfigurationReference<>(loader, ForkJoinPool.commonPool()); 055 ret.load(); 056 return ret; 057 } 058 059 /** 060 * Create a new configuration reference that will automatically update when 061 * triggered by the provided {@link WatchServiceListener}. 062 * 063 * @param loaderCreator a function that can create a {@link ConfigurationLoader} 064 * @param file the file to load this configuration from 065 * @param listener the watch service listener that will receive events 066 * @param <T> the node type 067 * @return the created reference 068 * @throws ConfigurateException if the underlying loader fails to load 069 * a configuration 070 * @see WatchServiceListener#listenToConfiguration(Function, Path) 071 * @since 4.0.0 072 */ 073 static <T extends ScopedConfigurationNode<T>> ConfigurationReference<T> 074 watching(Function<Path, ConfigurationLoader<? extends T>> loaderCreator, Path file, WatchServiceListener listener) 075 throws ConfigurateException { 076 final WatchingConfigurationReference<T> ret = new WatchingConfigurationReference<>(loaderCreator.apply(file), listener.taskExecutor); 077 ret.load(); 078 ret.disposable(listener.listenToFile(file, ret)); 079 080 return ret; 081 } 082 083 /** 084 * Reload a configuration using the provided loader. 085 * 086 * <p>If the load fails, this reference will continue pointing to old 087 * configuration values. 088 * 089 * @throws ConfigurateException when an error occurs 090 * @since 4.0.0 091 */ 092 void load() throws ConfigurateException; 093 094 /** 095 * Save this configuration using the provided loader. 096 * 097 * @throws ConfigurateException when an error occurs in the underlying IO 098 * @since 4.0.0 099 */ 100 void save() throws ConfigurateException; 101 102 /** 103 * Update the configuration node pointed to by this reference, and save it 104 * using the reference's loader. 105 * 106 * <p>Even if the loader fails to save this new node, the node pointed to by 107 * this reference will be updated. 108 * 109 * @param newNode the new node to save 110 * @throws ConfigurateException when an error occurs within the loader 111 * @since 4.0.0 112 */ 113 void save(ConfigurationNode newNode) throws ConfigurateException; 114 115 /** 116 * Save this configuration using the provided loader. Any errors will be 117 * submitted to subscribers of the returned publisher. 118 * 119 * @return publisher providing an event when the save is complete 120 * @since 4.0.0 121 */ 122 Publisher<N> saveAsync(); 123 124 /** 125 * Update this configuration using the provided function, returning a 126 * {@link Publisher} which will complete with the result of the operation. 127 * The update function will be called asynchronously, and will be saved 128 * to this reference's loader when complete. 129 * 130 * @param updater update function 131 * @return publisher providing an event when the update is complete 132 * @since 4.0.0 133 */ 134 Publisher<N> updateAsync(Function<N, ? extends N> updater); 135 136 /** 137 * Get the base node this reference refers to. 138 * 139 * @return the node 140 * @since 4.0.0 141 */ 142 N node(); 143 144 /** 145 * Get the loader this reference uses to load and save its node. 146 * 147 * @return the loader 148 * @since 4.0.0 149 */ 150 ConfigurationLoader<? extends N> loader(); 151 152 /** 153 * Get the node at the given path, relative to the root node. 154 * 155 * @param path the path, a series of path elements 156 * @return a child node 157 * @see ConfigurationNode#node(Object...) 158 * @since 4.0.0 159 */ 160 N get(Object... path); 161 162 /** 163 * Get the node at the given path, relative to the root node. 164 * 165 * @param path the path, a series of path elements 166 * @return a child node 167 * @see ConfigurationNode#node(Iterable) 168 * @since 4.0.0 169 */ 170 N get(Iterable<?> path); 171 172 /** 173 * Update the value of the node at the given path, using the root node as 174 * a base. 175 * 176 * @param path the path to get the child at 177 * @param value the value to set the child node to 178 * @since 4.0.0 179 */ 180 default void set(Object[] path, @Nullable Object value) throws SerializationException { 181 node().node(path).set(value); 182 } 183 184 /** 185 * Set the value of the node at {@code path} to the given value. 186 * 187 * <p>This uses the appropriate 188 * {@link org.spongepowered.configurate.serialize.TypeSerializer} to 189 * serialize the data if it's not directly supported by the 190 * provided configuration.</p> 191 * 192 * @param path the path to set the value at 193 * @param type the type of data to serialize 194 * @param value the value to set 195 * @param <T> the type parameter for the value 196 * @throws IllegalArgumentException if a raw type is provided 197 * @throws SerializationException if thrown by the serialization mechanism 198 * @since 4.0.0 199 */ 200 default <T> void set(Object[] path, Class<T> type, @Nullable T value) throws SerializationException { 201 node().node(path).set(type, value); 202 } 203 204 /** 205 * Set the value of the node at {@code path} to the given value. 206 * 207 * <p>This uses the appropriate 208 * {@link org.spongepowered.configurate.serialize.TypeSerializer} to 209 * serialize the data if it's not directly supported by the 210 * provided configuration.</p> 211 * 212 * @param path the path to set the value at 213 * @param type the type of data to serialize 214 * @param value the value to set 215 * @param <T> the type parameter for the value 216 * @throws SerializationException if thrown by the serialization mechanism 217 * @since 4.0.0 218 */ 219 default <T> void set(Object[] path, TypeToken<T> type, @Nullable T value) throws SerializationException { 220 node().node(path).set(type, value); 221 } 222 223 /** 224 * Update the value of the node at the given path, using the root node as 225 * a base. 226 * 227 * @param path the path to get the child at 228 * @param value the value to set the child node to 229 * @since 4.0.0 230 */ 231 default void set(NodePath path, @Nullable Object value) throws SerializationException { 232 node().node(path).set(value); 233 } 234 235 /** 236 * Set the value of the node at {@code path} to the given value. 237 * 238 * <p>This uses the appropriate 239 * {@link org.spongepowered.configurate.serialize.TypeSerializer} to 240 * serialize the data if it's not directly supported by the 241 * provided configuration.</p> 242 * 243 * @param path the path to set the value at 244 * @param type the type of data to serialize 245 * @param value the value to set 246 * @param <T> the type parameter for the value 247 * @throws SerializationException if thrown by the serialization mechanism 248 * @since 4.0.0 249 */ 250 default <T> void set(NodePath path, Class<T> type, @Nullable T value) throws SerializationException { 251 node().node(path).set(type, value); 252 } 253 254 /** 255 * Set the value of the node at {@code path} to the given value. 256 * 257 * <p>This uses the appropriate 258 * {@link org.spongepowered.configurate.serialize.TypeSerializer} to 259 * serialize the data if it's not directly supported by the 260 * provided configuration.</p> 261 * 262 * @param path the path to set the value at 263 * @param type the type of data to serialize 264 * @param value the value to set 265 * @param <T> the type parameter for the value 266 * @throws SerializationException if thrown by the serialization mechanism 267 * @since 4.0.0 268 */ 269 default <T> void set(NodePath path, TypeToken<T> type, @Nullable T value) throws SerializationException { 270 node().node(path).set(type, value); 271 } 272 273 /** 274 * Create a reference to the node at the provided path. The value will be 275 * deserialized according to the provided TypeToken. 276 * 277 * <p>The returned reference will update with reloads of and changes to the 278 * value of the provided configuration. Any serialization errors encountered 279 * will be submitted to the {@link #errors()} stream. 280 * 281 * @param type the value's type 282 * @param path the path from the root node to the node containing the value 283 * @param <T> the value type 284 * @return a deserializing reference to the node at the given path 285 * @throws SerializationException if a type serializer could not be found 286 * for the provided type 287 * @since 4.0.0 288 */ 289 default <T> ValueReference<T, N> referenceTo(TypeToken<T> type, Object... path) throws SerializationException { 290 return referenceTo(type, NodePath.of(path)); 291 } 292 293 /** 294 * Create a reference to the node at the provided path. The value will be 295 * deserialized according to type of the provided {@link Class}. 296 * 297 * <p>The returned reference will update with reloads of and changes to the 298 * value of the provided configuration. Any serialization errors encountered 299 * will be submitted to the {@link #errors()} stream. 300 * 301 * @param type the value's type 302 * @param path the path from the root node to the node containing the value 303 * @param <T> the value type 304 * @return a deserializing reference to the node at the given path 305 * @throws SerializationException if a type serializer could not be found 306 * for the provided type 307 * @since 4.0.0 308 */ 309 default <T> ValueReference<T, N> referenceTo(Class<T> type, Object... path) throws SerializationException { 310 return referenceTo(type, NodePath.of(path)); 311 } 312 313 /** 314 * Create a reference to the node at the provided path. The value will be 315 * deserialized according to the provided {@link TypeToken}. 316 * 317 * <p>The returned reference will update with reloads of and changes to the 318 * value of the provided configuration. Any serialization errors encountered 319 * will be submitted to the {@link #errors()} stream. 320 * 321 * @param type the value's type 322 * @param path the path from the root node to the node containing the value 323 * @param <T> the value type 324 * @return a deserializing reference to the node at the given path 325 * @throws SerializationException if a type serializer could not be found 326 * for the provided type 327 * @since 4.0.0 328 */ 329 default <T> ValueReference<T, N> referenceTo(TypeToken<T> type, NodePath path) throws SerializationException { 330 return referenceTo(type, path, null); 331 } 332 333 /** 334 * Create a reference to the node at the provided path. The value will be 335 * deserialized according to type of the provided {@link Class}. 336 * 337 * <p>The returned reference will update with reloads of and changes to the 338 * value of the provided configuration. Any serialization errors encountered 339 * will be submitted to the {@link #errors()} stream. 340 * 341 * @param type the value's type 342 * @param path the path from the root node to the node containing the value 343 * @param <T> the value type 344 * @return a deserializing reference to the node at the given path 345 * @throws SerializationException if a type serializer could not be found 346 * for the provided type 347 * @since 4.0.0 348 */ 349 default <T> ValueReference<T, N> referenceTo(Class<T> type, NodePath path) throws SerializationException { 350 return referenceTo(type, path, null); 351 } 352 353 /** 354 * Create a reference to the node at the provided path. The value will be 355 * deserialized according to the provided {@link TypeToken}. 356 * 357 * <p>The returned reference will update with reloads of and changes to the 358 * value of the provided configuration. Any serialization errors encountered 359 * will be submitted to the {@link #errors()} stream. 360 * 361 * @param type the value's type. 362 * @param path the path from the root node to the node containing the value 363 * @param defaultValue the value to use when there is no data present 364 * in the targeted node. 365 * @param <T> the value type 366 * @return a deserializing reference to the node at the given path 367 * @throws SerializationException if a type serializer could not be found 368 * for the provided type 369 * @since 4.0.0 370 */ 371 <T> ValueReference<T, N> referenceTo(TypeToken<T> type, NodePath path, @Nullable T defaultValue) throws SerializationException; 372 373 /** 374 * Create a reference to the node at the provided path. The value will be 375 * deserialized according to type of the provided {@link Class}. 376 * 377 * <p>The returned reference will update with reloads of and changes to the 378 * value of the provided configuration. Any serialization errors encountered 379 * will be submitted to the {@link #errors()} stream. 380 * 381 * @param type value's type 382 * @param path path from the root node to the node containing the value 383 * @param defaultValue value to use when there is no data present 384 * in the targeted node. 385 * @param <T> value type 386 * @return a deserializing reference to the node at the given path 387 * @throws SerializationException if a type serializer could not be found 388 * for the provided type 389 * @since 4.0.0 390 */ 391 <T> ValueReference<T, N> referenceTo(Class<T> type, NodePath path, @Nullable T defaultValue) throws SerializationException; 392 393 /** 394 * Access the {@link Publisher} that will broadcast update events, providing the newly created node. The returned 395 * publisher will be transaction-aware, i.e. any {@link TransactionalSubscriber} attached will progress through 396 * their phases appropriately 397 * 398 * @return the publisher 399 * @since 4.0.0 400 */ 401 Publisher<N> updates(); 402 403 /** 404 * A stream that will receive errors that occur while loading or saving to 405 * this reference. 406 * 407 * @return the publisher 408 * @since 4.0.0 409 */ 410 Publisher<Map.Entry<ErrorPhase, Throwable>> errors(); 411 412 /** 413 * {@inheritDoc} 414 */ 415 @Override 416 void close(); 417 418 /** 419 * Representing the phase where an error occurred. 420 * 421 * @since 4.0.0 422 */ 423 enum ErrorPhase { 424 LOADING, SAVING, UNKNOWN, VALUE; 425 426 } 427 428}