Skip to content

Commit cf79290

Browse files
authored
Merge pull request #176 from graphql-java/make-dataloader-options-immutable
Making DataLoaderOptions immutable
2 parents 2036771 + a65cf34 commit cf79290

File tree

3 files changed

+396
-50
lines changed

3 files changed

+396
-50
lines changed

src/main/java/org/dataloader/DataLoaderOptions.java

+190-50
Original file line numberDiff line numberDiff line change
@@ -17,37 +17,41 @@
1717
package org.dataloader;
1818

1919
import org.dataloader.annotations.PublicApi;
20-
import org.dataloader.impl.Assertions;
2120
import org.dataloader.scheduler.BatchLoaderScheduler;
2221
import org.dataloader.stats.NoOpStatisticsCollector;
2322
import org.dataloader.stats.StatisticsCollector;
2423

24+
import java.util.Objects;
2525
import java.util.Optional;
26+
import java.util.function.Consumer;
2627
import java.util.function.Supplier;
2728

2829
import static org.dataloader.impl.Assertions.nonNull;
2930

3031
/**
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
3638
public class DataLoaderOptions {
3739

3840
private 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;
5155

5256
/**
5357
* Creates a new data loader options with default settings.
@@ -56,13 +60,30 @@ public DataLoaderOptions() {
5660
batchingEnabled = true;
5761
cachingEnabled = true;
5862
cachingExceptionsEnabled = true;
63+
cacheKeyFunction = null;
64+
cacheMap = null;
65+
valueCache = null;
5966
maxBatchSize = -1;
60-
statisticsCollector = NoOpStatisticsCollector::new;
67+
statisticsCollector = NOOP_COLLECTOR;
6168
environmentProvider = NULL_PROVIDER;
62-
valueCacheOptions = ValueCacheOptions.newOptions();
69+
valueCacheOptions = DEFAULT_VALUE_CACHE_OPTIONS;
6370
batchLoaderScheduler = null;
6471
}
6572

73+
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() {
90111
return new DataLoaderOptions();
91112
}
92113

114+
/**
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
*/
109174
public DataLoaderOptions setBatchingEnabled(boolean batchingEnabled) {
110-
this.batchingEnabled = batchingEnabled;
111-
return this;
175+
return builder().setBatchingEnabled(batchingEnabled).build();
112176
}
113177

114178
/**
@@ -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
*/
130193
public DataLoaderOptions setCachingEnabled(boolean cachingEnabled) {
131-
this.cachingEnabled = cachingEnabled;
132-
return this;
194+
return builder().setCachingEnabled(cachingEnabled).build();
133195
}
134196

135197
/**
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
*/
156217
public DataLoaderOptions setCachingExceptionsEnabled(boolean cachingExceptionsEnabled) {
157-
this.cachingExceptionsEnabled = cachingExceptionsEnabled;
158-
return this;
218+
return builder().setCachingExceptionsEnabled(cachingExceptionsEnabled).build();
159219
}
160220

161221
/**
@@ -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
*/
179238
public DataLoaderOptions setCacheKeyFunction(CacheKey<?> cacheKeyFunction) {
180-
this.cacheKeyFunction = cacheKeyFunction;
181-
return this;
239+
return builder().setCacheKeyFunction(cacheKeyFunction).build();
182240
}
183241

184242
/**
@@ -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
*/
202259
public DataLoaderOptions setCacheMap(CacheMap<?, ?> cacheMap) {
203-
this.cacheMap = cacheMap;
204-
return this;
260+
return builder().setCacheMap(cacheMap).build();
205261
}
206262

207263
/**
@@ -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
*/
225280
public DataLoaderOptions setMaxBatchSize(int maxBatchSize) {
226-
this.maxBatchSize = maxBatchSize;
227-
return this;
281+
return builder().setMaxBatchSize(maxBatchSize).build();
228282
}
229283

230284
/**
@@ -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
*/
246299
public DataLoaderOptions setStatisticsCollector(Supplier<StatisticsCollector> statisticsCollector) {
247-
this.statisticsCollector = nonNull(statisticsCollector);
248-
return this;
300+
return builder().setStatisticsCollector(nonNull(statisticsCollector)).build();
249301
}
250302

251303
/**
@@ -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
*/
265316
public DataLoaderOptions setBatchLoaderContextProvider(BatchLoaderContextProvider contextProvider) {
266-
this.environmentProvider = nonNull(contextProvider);
267-
return this;
317+
return builder().setBatchLoaderContextProvider(nonNull(contextProvider)).build();
268318
}
269319

270320
/**
@@ -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
*/
288337
public DataLoaderOptions setValueCache(ValueCache<?, ?> valueCache) {
289-
this.valueCache = valueCache;
290-
return this;
338+
return builder().setValueCache(valueCache).build();
291339
}
292340

293341
/**
@@ -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
*/
307354
public DataLoaderOptions setValueCacheOptions(ValueCacheOptions valueCacheOptions) {
308-
this.valueCacheOptions = Assertions.nonNull(valueCacheOptions);
309-
return this;
355+
return builder().setValueCacheOptions(nonNull(valueCacheOptions)).build();
310356
}
311357

312358
/**
@@ -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
*/
327372
public 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
}

0 commit comments

Comments
 (0)