Merge pull request #176 from graphql-java/make-dataloader-options-imm… · graphql-java/java-dataloader@cf79290
@@ -17,37 +17,41 @@
1717package org.dataloader;
18181919import org.dataloader.annotations.PublicApi;
20-import org.dataloader.impl.Assertions;
2120import org.dataloader.scheduler.BatchLoaderScheduler;
2221import org.dataloader.stats.NoOpStatisticsCollector;
2322import org.dataloader.stats.StatisticsCollector;
242324+import java.util.Objects;
2525import java.util.Optional;
26+import java.util.function.Consumer;
2627import java.util.function.Supplier;
27282829import static org.dataloader.impl.Assertions.nonNull;
29303031/**
31- * Configuration options for {@link DataLoader} instances.
32+ * Configuration options for {@link DataLoader} instances. This is an immutable class so each time
33+ * you change a value it returns a new object.
3234 *
3335 * @author <a href="https://github.com/aschrijver/">Arnold Schrijver</a>
3436 */
3537@PublicApi
3638public class DataLoaderOptions {
37393840private static final BatchLoaderContextProvider NULL_PROVIDER = () -> null;
39-40-private boolean batchingEnabled;
41-private boolean cachingEnabled;
42-private boolean cachingExceptionsEnabled;
43-private CacheKey<?> cacheKeyFunction;
44-private CacheMap<?, ?> cacheMap;
45-private ValueCache<?, ?> valueCache;
46-private int maxBatchSize;
47-private Supplier<StatisticsCollector> statisticsCollector;
48-private BatchLoaderContextProvider environmentProvider;
49-private ValueCacheOptions valueCacheOptions;
50-private BatchLoaderScheduler batchLoaderScheduler;
41+private static final Supplier<StatisticsCollector> NOOP_COLLECTOR = NoOpStatisticsCollector::new;
42+private static final ValueCacheOptions DEFAULT_VALUE_CACHE_OPTIONS = ValueCacheOptions.newOptions();
43+44+private final boolean batchingEnabled;
45+private final boolean cachingEnabled;
46+private final boolean cachingExceptionsEnabled;
47+private final CacheKey<?> cacheKeyFunction;
48+private final CacheMap<?, ?> cacheMap;
49+private final ValueCache<?, ?> valueCache;
50+private final int maxBatchSize;
51+private final Supplier<StatisticsCollector> statisticsCollector;
52+private final BatchLoaderContextProvider environmentProvider;
53+private final ValueCacheOptions valueCacheOptions;
54+private final BatchLoaderScheduler batchLoaderScheduler;
51555256/**
5357 * Creates a new data loader options with default settings.
@@ -56,13 +60,30 @@ public DataLoaderOptions() {
5660batchingEnabled = true;
5761cachingEnabled = true;
5862cachingExceptionsEnabled = true;
63+cacheKeyFunction = null;
64+cacheMap = null;
65+valueCache = null;
5966maxBatchSize = -1;
60-statisticsCollector = NoOpStatisticsCollector::new;
67+statisticsCollector = NOOP_COLLECTOR;
6168environmentProvider = NULL_PROVIDER;
62-valueCacheOptions = ValueCacheOptions.newOptions();
69+valueCacheOptions = DEFAULT_VALUE_CACHE_OPTIONS;
6370batchLoaderScheduler = null;
6471 }
657273+private DataLoaderOptions(Builder builder) {
74+this.batchingEnabled = builder.batchingEnabled;
75+this.cachingEnabled = builder.cachingEnabled;
76+this.cachingExceptionsEnabled = builder.cachingExceptionsEnabled;
77+this.cacheKeyFunction = builder.cacheKeyFunction;
78+this.cacheMap = builder.cacheMap;
79+this.valueCache = builder.valueCache;
80+this.maxBatchSize = builder.maxBatchSize;
81+this.statisticsCollector = builder.statisticsCollector;
82+this.environmentProvider = builder.environmentProvider;
83+this.valueCacheOptions = builder.valueCacheOptions;
84+this.batchLoaderScheduler = builder.batchLoaderScheduler;
85+ }
86+6687/**
6788 * Clones the provided data loader options.
6889 *
@@ -90,6 +111,51 @@ public static DataLoaderOptions newOptions() {
90111return new DataLoaderOptions();
91112 }
92113114+/**
115+ * @return a new default data loader options {@link Builder} that you can then customize
116+ */
117+public static DataLoaderOptions.Builder newOptionsBuilder() {
118+return new DataLoaderOptions.Builder();
119+ }
120+121+/**
122+ * @param otherOptions the options to copy
123+ * @return a new default data loader options {@link Builder} from the specified one that you can then customize
124+ */
125+public static DataLoaderOptions.Builder newDataLoaderOptions(DataLoaderOptions otherOptions) {
126+return new DataLoaderOptions.Builder(otherOptions);
127+ }
128+129+/**
130+ * Will transform the current options in to a builder ands allow you to build a new set of options
131+ *
132+ * @param builderConsumer the consumer of a builder that has this objects starting values
133+ * @return a new {@link DataLoaderOptions} object
134+ */
135+public DataLoaderOptions transform(Consumer<Builder> builderConsumer) {
136+Builder builder = newOptionsBuilder();
137+builderConsumer.accept(builder);
138+return builder.build();
139+ }
140+141+@Override
142+public boolean equals(Object o) {
143+if (o == null || getClass() != o.getClass()) return false;
144+DataLoaderOptions that = (DataLoaderOptions) o;
145+return batchingEnabled == that.batchingEnabled
146+&& cachingEnabled == that.cachingEnabled
147+&& cachingExceptionsEnabled == that.cachingExceptionsEnabled
148+&& maxBatchSize == that.maxBatchSize
149+&& Objects.equals(cacheKeyFunction, that.cacheKeyFunction) &&
150+Objects.equals(cacheMap, that.cacheMap) &&
151+Objects.equals(valueCache, that.valueCache) &&
152+Objects.equals(statisticsCollector, that.statisticsCollector) &&
153+Objects.equals(environmentProvider, that.environmentProvider) &&
154+Objects.equals(valueCacheOptions, that.valueCacheOptions) &&
155+Objects.equals(batchLoaderScheduler, that.batchLoaderScheduler);
156+ }
157+158+93159/**
94160 * Option that determines whether to use batching (the default), or not.
95161 *
@@ -103,12 +169,10 @@ public boolean batchingEnabled() {
103169 * Sets the option that determines whether batch loading is enabled.
104170 *
105171 * @param batchingEnabled {@code true} to enable batch loading, {@code false} otherwise
106- *
107172 * @return the data loader options for fluent coding
108173 */
109174public DataLoaderOptions setBatchingEnabled(boolean batchingEnabled) {
110-this.batchingEnabled = batchingEnabled;
111-return this;
175+return builder().setBatchingEnabled(batchingEnabled).build();
112176 }
113177114178/**
@@ -124,17 +188,15 @@ public boolean cachingEnabled() {
124188 * Sets the option that determines whether caching is enabled.
125189 *
126190 * @param cachingEnabled {@code true} to enable caching, {@code false} otherwise
127- *
128191 * @return the data loader options for fluent coding
129192 */
130193public DataLoaderOptions setCachingEnabled(boolean cachingEnabled) {
131-this.cachingEnabled = cachingEnabled;
132-return this;
194+return builder().setCachingEnabled(cachingEnabled).build();
133195 }
134196135197/**
136198 * Option that determines whether to cache exceptional values (the default), or not.
137- *
199+ * <p>
138200 * For short-lived caches (that is request caches) it makes sense to cache exceptions since
139201 * it's likely the key is still poisoned. However, if you have long-lived caches, then it may make
140202 * sense to set this to false since the downstream system may have recovered from its failure
@@ -150,12 +212,10 @@ public boolean cachingExceptionsEnabled() {
150212 * Sets the option that determines whether exceptional values are cache enabled.
151213 *
152214 * @param cachingExceptionsEnabled {@code true} to enable caching exceptional values, {@code false} otherwise
153- *
154215 * @return the data loader options for fluent coding
155216 */
156217public DataLoaderOptions setCachingExceptionsEnabled(boolean cachingExceptionsEnabled) {
157-this.cachingExceptionsEnabled = cachingExceptionsEnabled;
158-return this;
218+return builder().setCachingExceptionsEnabled(cachingExceptionsEnabled).build();
159219 }
160220161221/**
@@ -173,12 +233,10 @@ public Optional<CacheKey> cacheKeyFunction() {
173233 * Sets the function to use for creating the cache key, if caching is enabled.
174234 *
175235 * @param cacheKeyFunction the cache key function to use
176- *
177236 * @return the data loader options for fluent coding
178237 */
179238public DataLoaderOptions setCacheKeyFunction(CacheKey<?> cacheKeyFunction) {
180-this.cacheKeyFunction = cacheKeyFunction;
181-return this;
239+return builder().setCacheKeyFunction(cacheKeyFunction).build();
182240 }
183241184242/**
@@ -196,12 +254,10 @@ public DataLoaderOptions setCacheKeyFunction(CacheKey<?> cacheKeyFunction) {
196254 * Sets the cache map implementation to use for caching, if caching is enabled.
197255 *
198256 * @param cacheMap the cache map instance
199- *
200257 * @return the data loader options for fluent coding
201258 */
202259public DataLoaderOptions setCacheMap(CacheMap<?, ?> cacheMap) {
203-this.cacheMap = cacheMap;
204-return this;
260+return builder().setCacheMap(cacheMap).build();
205261 }
206262207263/**
@@ -219,12 +275,10 @@ public int maxBatchSize() {
219275 * before they are split into multiple class
220276 *
221277 * @param maxBatchSize the maximum batch size
222- *
223278 * @return the data loader options for fluent coding
224279 */
225280public DataLoaderOptions setMaxBatchSize(int maxBatchSize) {
226-this.maxBatchSize = maxBatchSize;
227-return this;
281+return builder().setMaxBatchSize(maxBatchSize).build();
228282 }
229283230284/**
@@ -240,12 +294,10 @@ public StatisticsCollector getStatisticsCollector() {
240294 * a common value
241295 *
242296 * @param statisticsCollector the statistics collector to use
243- *
244297 * @return the data loader options for fluent coding
245298 */
246299public DataLoaderOptions setStatisticsCollector(Supplier<StatisticsCollector> statisticsCollector) {
247-this.statisticsCollector = nonNull(statisticsCollector);
248-return this;
300+return builder().setStatisticsCollector(nonNull(statisticsCollector)).build();
249301 }
250302251303/**
@@ -259,12 +311,10 @@ public BatchLoaderContextProvider getBatchLoaderContextProvider() {
259311 * Sets the batch loader environment provider that will be used to give context to batch load functions
260312 *
261313 * @param contextProvider the batch loader context provider
262- *
263314 * @return the data loader options for fluent coding
264315 */
265316public DataLoaderOptions setBatchLoaderContextProvider(BatchLoaderContextProvider contextProvider) {
266-this.environmentProvider = nonNull(contextProvider);
267-return this;
317+return builder().setBatchLoaderContextProvider(nonNull(contextProvider)).build();
268318 }
269319270320/**
@@ -282,12 +332,10 @@ public DataLoaderOptions setBatchLoaderContextProvider(BatchLoaderContextProvide
282332 * Sets the value cache implementation to use for caching values, if caching is enabled.
283333 *
284334 * @param valueCache the value cache instance
285- *
286335 * @return the data loader options for fluent coding
287336 */
288337public DataLoaderOptions setValueCache(ValueCache<?, ?> valueCache) {
289-this.valueCache = valueCache;
290-return this;
338+return builder().setValueCache(valueCache).build();
291339 }
292340293341/**
@@ -301,12 +349,10 @@ public ValueCacheOptions getValueCacheOptions() {
301349 * Sets the {@link ValueCacheOptions} that control how the {@link ValueCache} will be used
302350 *
303351 * @param valueCacheOptions the value cache options
304- *
305352 * @return the data loader options for fluent coding
306353 */
307354public DataLoaderOptions setValueCacheOptions(ValueCacheOptions valueCacheOptions) {
308-this.valueCacheOptions = Assertions.nonNull(valueCacheOptions);
309-return this;
355+return builder().setValueCacheOptions(nonNull(valueCacheOptions)).build();
310356 }
311357312358/**
@@ -321,11 +367,105 @@ public BatchLoaderScheduler getBatchLoaderScheduler() {
321367 * to some future time.
322368 *
323369 * @param batchLoaderScheduler the scheduler
324- *
325370 * @return the data loader options for fluent coding
326371 */
327372public DataLoaderOptions setBatchLoaderScheduler(BatchLoaderScheduler batchLoaderScheduler) {
328-this.batchLoaderScheduler = batchLoaderScheduler;
329-return this;
373+return builder().setBatchLoaderScheduler(batchLoaderScheduler).build();
374+ }
375+376+private Builder builder() {
377+return new Builder(this);
378+ }
379+380+public static class Builder {
381+private boolean batchingEnabled;
382+private boolean cachingEnabled;
383+private boolean cachingExceptionsEnabled;
384+private CacheKey<?> cacheKeyFunction;
385+private CacheMap<?, ?> cacheMap;
386+private ValueCache<?, ?> valueCache;
387+private int maxBatchSize;
388+private Supplier<StatisticsCollector> statisticsCollector;
389+private BatchLoaderContextProvider environmentProvider;
390+private ValueCacheOptions valueCacheOptions;
391+private BatchLoaderScheduler batchLoaderScheduler;
392+393+public Builder() {
394+this(new DataLoaderOptions()); // use the defaults of the DataLoaderOptions for this builder
395+ }
396+397+Builder(DataLoaderOptions other) {
398+this.batchingEnabled = other.batchingEnabled;
399+this.cachingEnabled = other.cachingEnabled;
400+this.cachingExceptionsEnabled = other.cachingExceptionsEnabled;
401+this.cacheKeyFunction = other.cacheKeyFunction;
402+this.cacheMap = other.cacheMap;
403+this.valueCache = other.valueCache;
404+this.maxBatchSize = other.maxBatchSize;
405+this.statisticsCollector = other.statisticsCollector;
406+this.environmentProvider = other.environmentProvider;
407+this.valueCacheOptions = other.valueCacheOptions;
408+this.batchLoaderScheduler = other.batchLoaderScheduler;
409+ }
410+411+public Builder setBatchingEnabled(boolean batchingEnabled) {
412+this.batchingEnabled = batchingEnabled;
413+return this;
414+ }
415+416+public Builder setCachingEnabled(boolean cachingEnabled) {
417+this.cachingEnabled = cachingEnabled;
418+return this;
419+ }
420+421+public Builder setCachingExceptionsEnabled(boolean cachingExceptionsEnabled) {
422+this.cachingExceptionsEnabled = cachingExceptionsEnabled;
423+return this;
424+ }
425+426+public Builder setCacheKeyFunction(CacheKey<?> cacheKeyFunction) {
427+this.cacheKeyFunction = cacheKeyFunction;
428+return this;
429+ }
430+431+public Builder setCacheMap(CacheMap<?, ?> cacheMap) {
432+this.cacheMap = cacheMap;
433+return this;
434+ }
435+436+public Builder setValueCache(ValueCache<?, ?> valueCache) {
437+this.valueCache = valueCache;
438+return this;
439+ }
440+441+public Builder setMaxBatchSize(int maxBatchSize) {
442+this.maxBatchSize = maxBatchSize;
443+return this;
444+ }
445+446+public Builder setStatisticsCollector(Supplier<StatisticsCollector> statisticsCollector) {
447+this.statisticsCollector = statisticsCollector;
448+return this;
449+ }
450+451+public Builder setBatchLoaderContextProvider(BatchLoaderContextProvider environmentProvider) {
452+this.environmentProvider = environmentProvider;
453+return this;
454+ }
455+456+public Builder setValueCacheOptions(ValueCacheOptions valueCacheOptions) {
457+this.valueCacheOptions = valueCacheOptions;
458+return this;
459+ }
460+461+public Builder setBatchLoaderScheduler(BatchLoaderScheduler batchLoaderScheduler) {
462+this.batchLoaderScheduler = batchLoaderScheduler;
463+return this;
464+ }
465+466+public DataLoaderOptions build() {
467+return new DataLoaderOptions(this);
468+ }
469+330470 }
331471}