1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */

15
16 package software.amazon.awssdk.services.s3.internal;
17
18 import java.util.function.Supplier;
19 import software.amazon.awssdk.annotations.SdkInternalApi;
20 import software.amazon.awssdk.utils.Lazy;
21
22 /**
23  * A helper class for setting a field's value to a default if it isn't specified, while still keeping track of whether the value
24  * was from the default or from the field.
25  *
26  * For example, a "profile name" field-with-default might be set to "null" with a default of "foo". {@link #value()} returns
27  * "foo"while {@link #isDefault()} can be used to keep track of the fact that the value was from the default.
28  */

29 @SdkInternalApi
30 public abstract class FieldWithDefault<T> {
31     private FieldWithDefault(){
32     }
33
34     /**
35      * Create a {@link FieldWithDefault} using the provided field and its default value. If the field is null, the default value
36      * will be returned by {@link #value()} and {@link #isDefault()} will return true. If the field is not null, the field value
37      * will be returned by {@link #value()} and {@link #isDefault()} will return false.
38      *
39      * @see #createLazy(Object, Supplier)
40      */

41     public static <T> FieldWithDefault<T> create(T field, T defaultValue) {
42         return new Impl<>(field, defaultValue);
43     }
44
45     /**
46      * Create a {@link FieldWithDefault} using the provided field and its default value. If the field is null, the default value
47      * will be returned by {@link #value()} and {@link #isDefault()} will return true. If the field is not null, the field value
48      * will be returned by {@link #value()} and {@link #isDefault()} will return false.
49      *
50      * <p>This differs from {@link #create(Object, Object)} in that the default value won't be resolved if the provided field is
51      * not null. The default value also won't be resolved until the first {@link #value()} call. This is useful for delaying
52      * expensive calculations until right before they're needed.
53      */

54     public static <T> FieldWithDefault<T> createLazy(T field, Supplier<T> defaultValue) {
55         return new LazyImpl<>(field, defaultValue);
56     }
57
58     /**
59      * Retrieve the value of this field.
60      */

61     public abstract T value();
62
63     /**
64      * True, if the value returned by {@link #value()} is the default value (i.e. the field is null). False otherwise.
65      */

66     public abstract boolean isDefault();
67
68     /**
69      * Return the field exactly as it was specified when the field-with-default was created. If the field was nullthis will
70      * return null. This will not resolve the default if this is a field from {@link #createLazy(Object, Supplier)}.
71      */

72     public abstract T valueOrNullIfDefault();
73
74     private static class Impl<T> extends FieldWithDefault<T> {
75         private final T value;
76         private final boolean isDefault;
77
78         private Impl(T field, T defaultValue) {
79             this.value = field != null ? field : defaultValue;
80             this.isDefault = field == null;
81         }
82
83         @Override
84         public T value() {
85             return value;
86         }
87
88         @Override
89         public boolean isDefault() {
90             return isDefault;
91         }
92
93         @Override
94         public T valueOrNullIfDefault() {
95             return isDefault ? null : value;
96         }
97     }
98
99     private static class LazyImpl<T> extends FieldWithDefault<T> {
100         private final Lazy<T> value;
101         private final boolean isDefault;
102
103         private LazyImpl(T field, Supplier<T> defaultValue) {
104             this.value = field != null ? new Lazy<>(() -> field) : new Lazy<>(defaultValue);
105             this.isDefault = field == null;
106         }
107
108         @Override
109         public T value() {
110             return value.getValue();
111         }
112
113         @Override
114         public boolean isDefault() {
115             return isDefault;
116         }
117
118         @Override
119         public T valueOrNullIfDefault() {
120             return isDefault ? null : value.getValue();
121         }
122     }
123 }
124