66import org .slf4j .LoggerFactory ;
77
88import java .lang .reflect .Method ;
9- import java .util .Collections ;
109import java .util .HashMap ;
1110import java .util .List ;
1211import java .util .Map ;
@@ -40,7 +39,7 @@ public abstract class ReloadableClientConfig implements IClientConfig {
4039
4140 // Map of raw property names (without namespace or client name) to values. All values are non-null and properly
4241 // typed to match the key type
43- private final Map <IClientConfigKey , Optional <Object >> internalProperties = new ConcurrentHashMap <>();
42+ private final Map <IClientConfigKey , Optional <? >> internalProperties = new ConcurrentHashMap <>();
4443
4544 private final Map <IClientConfigKey , ReloadableProperty <?>> dynamicProperties = new ConcurrentHashMap <>();
4645
@@ -52,31 +51,13 @@ public abstract class ReloadableClientConfig implements IClientConfig {
5251
5352 private final PropertyResolver resolver ;
5453
55- private String clientName ;
54+ private String clientName = DEFAULT_CLIENT_NAME ;
5655
5756 private String namespace = DEFAULT_NAMESPACE ;
5857
5958 private boolean isLoaded = false ;
6059
61- /**
62- * @deprecated Use {@link #ReloadableClientConfig(PropertyResolver, String, String)}
63- */
64- @ Deprecated
6560 protected ReloadableClientConfig (PropertyResolver resolver ) {
66- this (resolver , DEFAULT_CLIENT_NAME );
67- }
68-
69- /**
70- * @deprecated Use {@link #ReloadableClientConfig(PropertyResolver, String, String)}
71- */
72- @ Deprecated
73- protected ReloadableClientConfig (PropertyResolver resolver , String clientName ) {
74- this (resolver , DEFAULT_NAMESPACE , DEFAULT_CLIENT_NAME );
75- }
76-
77- protected ReloadableClientConfig (PropertyResolver resolver , String namespace , String clientName ) {
78- this .namespace = namespace ;
79- this .clientName = clientName ;
8061 this .resolver = resolver ;
8162 }
8263
@@ -119,10 +100,14 @@ public final void setNameSpace(String nameSpace) {
119100 @ Override
120101 public void loadProperties (String clientName ) {
121102 Preconditions .checkState (!isLoaded , "Config '{}' can only be loaded once" , clientName );
103+
104+ LOG .info ("Loading config for `{}`" , clientName );
122105 this .clientName = clientName ;
123106 this .isLoaded = true ;
124107 loadDefaultValues ();
125108 resolver .onChange (this ::reload );
109+
110+ internalProperties .forEach ((key , value ) -> LOG .info ("{} : {} -> {}" , clientName , key , value .orElse (null )));
126111 }
127112
128113 /**
@@ -146,27 +131,29 @@ public void forEach(BiConsumer<IClientConfigKey<?>, Object> consumer) {
146131 }
147132
148133 /**
149- * Create an action that will refresh the cached value for key. Uses the current value as a reference and will
134+ * Register an action that will refresh the cached value for key. Uses the current value as a reference and will
150135 * update from the dynamic property source to either delete or set a new value.
151136 *
152137 * @param key - Property key without client name or namespace
153- * @param valueSupplier - Strategy for generating the value. Could potentially ready multiple property names, such
154- * as default and client specific
155138 */
156- private <T > Runnable createAutoRefreshAction (final IClientConfigKey <T > key , final Supplier <Optional <T >> valueSupplier ) {
157- final AtomicReference <Optional <T >> current = new AtomicReference <>(valueSupplier .get ());
158- return () -> {
159- final Optional <T > next = valueSupplier .get ();
160- if (!next .equals (current .get ())) {
161- LOG .debug ("New value {}: {} -> {}" , key .key (), current .get (), next );
162- current .set (next );
163- if (next .isPresent ()) {
164- internalProperties .put (key , (Optional <Object >) next );
165- } else {
166- internalProperties .put (key , Optional .empty ());
167- }
139+ private <T > void autoRefreshFromPropertyResolver (final IClientConfigKey <T > key ) {
140+ changeActions .computeIfAbsent (key , ignore -> {
141+ final Supplier <Optional <T >> valueSupplier = () -> resolveFromPropertyResolver (key );
142+ final Optional <T > current = valueSupplier .get ();
143+ if (current .isPresent ()) {
144+ internalProperties .put (key , current );
168145 }
169- };
146+
147+ final AtomicReference <Optional <T >> previous = new AtomicReference <>(current );
148+ return () -> {
149+ final Optional <T > next = valueSupplier .get ();
150+ if (!next .equals (previous .get ())) {
151+ LOG .info ("New value {}: {} -> {}" , key .key (), previous .get (), next );
152+ previous .set (next );
153+ internalProperties .put (key , next );
154+ }
155+ };
156+ });
170157 }
171158
172159 interface ReloadableProperty <T > extends Property <T > {
@@ -221,8 +208,12 @@ public String toString() {
221208 public final <T > T get (IClientConfigKey <T > key ) {
222209 Optional <T > value = (Optional <T >)internalProperties .get (key );
223210 if (value == null ) {
224- set (key , null );
225- value = (Optional <T >)internalProperties .get (key );
211+ if (!isLoaded ) {
212+ return null ;
213+ } else {
214+ set (key , null );
215+ value = (Optional <T >) internalProperties .get (key );
216+ }
226217 }
227218
228219 return value .orElse (null );
@@ -242,21 +233,13 @@ public final <T> Property<T> getGlobalProperty(IClientConfigKey<T> key) {
242233 public final <T > Property <T > getDynamicProperty (IClientConfigKey <T > key ) {
243234 LOG .debug ("Get dynamic property key={} ns={} client={}" , key .key (), getNameSpace (), clientName );
244235
245- get (key );
246-
247- return getOrCreateProperty (
248- key ,
249- () -> (Optional <T >)internalProperties .get (key ),
250- key ::defaultValue );
251- }
252-
253- @ Override
254- public <T > Property <T > getScopedProperty (IClientConfigKey <T > key ) {
255- LOG .debug ("Get dynamic property key={} ns={} client={}" , key .key (), getNameSpace (), clientName );
236+ if (isLoaded ) {
237+ autoRefreshFromPropertyResolver (key );
238+ }
256239
257240 return getOrCreateProperty (
258241 key ,
259- () -> resolverScopedProperty ( key ),
242+ () -> ( Optional < T >) internalProperties . getOrDefault ( key , Optional . empty () ),
260243 key ::defaultValue );
261244 }
262245
@@ -280,7 +263,7 @@ public <T> Property<T> getPrefixMappedProperty(IClientConfigKey<T> key) {
280263 * @param <T>
281264 * @return
282265 */
283- private <T > Optional <T > resolveFinalProperty (IClientConfigKey <T > key ) {
266+ private <T > Optional <T > resolveFromPropertyResolver (IClientConfigKey <T > key ) {
284267 Optional <T > value ;
285268 if (!StringUtils .isEmpty (clientName )) {
286269 value = resolver .get (clientName + "." + getNameSpace () + "." + key .key (), key .type ());
@@ -292,28 +275,9 @@ private <T> Optional<T> resolveFinalProperty(IClientConfigKey<T> key) {
292275 return resolver .get (getNameSpace () + "." + key .key (), key .type ());
293276 }
294277
295- /**
296- * Resolve a p
297- * @param key
298- * @param <T>
299- * @return
300- */
301- private <T > Optional <T > resolverScopedProperty (IClientConfigKey <T > key ) {
302- Optional <T > value = resolver .get (clientName + "." + getNameSpace () + "." + key .key (), key .type ());
303- if (value .isPresent ()) {
304- return value ;
305- }
306-
307- return getIfSet (key );
308- }
309-
310278 @ Override
311279 public <T > Optional <T > getIfSet (IClientConfigKey <T > key ) {
312- Optional <T > value = (Optional <T >)internalProperties .get (key );
313- if (value == null ) {
314- return Optional .empty ();
315- }
316- return value ;
280+ return (Optional <T >)internalProperties .getOrDefault (key , Optional .empty ());
317281 }
318282
319283 private <T > T resolveValueToType (IClientConfigKey <T > key , Object value ) {
@@ -343,11 +307,11 @@ private <T> T resolveValueToType(IClientConfigKey<T> key, Object value) {
343307 } else if (TimeUnit .class .equals (type )) {
344308 return (T ) TimeUnit .valueOf (strValue );
345309 } else {
346- return PropertyResolver .resolveWithValueOf (type , strValue )
310+ return PropertyUtils .resolveWithValueOf (type , strValue )
347311 .orElseThrow (() -> new IllegalArgumentException ("Unsupported value type `" + type + "'" ));
348312 }
349313 } else {
350- return PropertyResolver .resolveWithValueOf (type , value .toString ())
314+ return PropertyUtils .resolveWithValueOf (type , value .toString ())
351315 .orElseThrow (() -> new IllegalArgumentException ("Incompatible value type `" + value .getClass () + "` while expecting '" + type + "`" ));
352316 }
353317 } catch (Exception e ) {
@@ -390,23 +354,15 @@ public final <T> T get(IClientConfigKey<T> key, T defaultValue) {
390354 }
391355
392356 @ Override
393- public final <T > IClientConfig set (IClientConfigKey <T > key , T value ) {
357+ public <T > IClientConfig set (IClientConfigKey <T > key , T value ) {
394358 Preconditions .checkArgument (key != null , "key cannot be null" );
395359
396- // Make sure the value is property typed.
397360 value = resolveValueToType (key , value );
398-
399- // Check if there's a dynamic config override available
400- value = resolveFinalProperty (key ).orElse (value );
401-
402- // Cache the new value
403- internalProperties .put (key , Optional .ofNullable (value ));
404-
405- // If this is the first time a property is seen and a client name has been specified then make sure
406- // we have the necessary refresh to pick up new values from dynamic config
407361 if (isLoaded ) {
408- changeActions .computeIfAbsent (key , ignore -> createAutoRefreshAction (key , () -> resolveFinalProperty (key )))
409- .run ();
362+ internalProperties .put (key , Optional .ofNullable (resolveFromPropertyResolver (key ).orElse (value )));
363+ autoRefreshFromPropertyResolver (key );
364+ } else {
365+ internalProperties .put (key , Optional .ofNullable (value ));
410366 }
411367 cachedToString = null ;
412368
0 commit comments