Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 64f5823

Browse filesBrowse files
committed
add an access layer on top of the minimal configuration API
work in progress, API looks solid though
1 parent dfec238 commit 64f5823
Copy full SHA for 64f5823

File tree

Expand file treeCollapse file tree

6 files changed

+336
-2
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

6 files changed

+336
-2
lines changed
Open diff view settings
Collapse file

‎api/src/main/java/javx/config/Config.java‎

Copy file name to clipboardExpand all lines: api/src/main/java/javx/config/Config.java
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ public interface Config {
4545
*/
4646
String getValue(String key);
4747

48+
/**
49+
* Create a {@link ConfigValue} to access the underlying configuration.
50+
*
51+
* @param key the property key
52+
*/
53+
ConfigValue<String> access(String key);
54+
4855
/**
4956
* Returns a Map of all properties from all scannable config sources. The values of the properties reflect the
5057
* values that would be obtained by a call to {@link #getValue(java.lang.String)}, that is, the value of the
Collapse file
+125Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package javx.config;
2+
3+
import javx.config.spi.Converter;
4+
5+
import java.util.concurrent.TimeUnit;
6+
7+
/**
8+
* Accessor to a configured value.
9+
* It follows a builder pattern.
10+
*
11+
* Accessing the configured value is finally done via {@link #getValue()}
12+
*
13+
* @author <a href="mailto:struberg@apache.org">Mark Struberg</a>
14+
* @author <a href="mailto:gpetracek@apache.org">Gerhard Petracek</a>
15+
*/
16+
public interface ConfigValue<T> {
17+
18+
/**
19+
* Sets the type of the configuration entry to the given class and returns this builder.
20+
* The default type of a ConfigValue is {@code String}.
21+
*
22+
* @param clazz The target type
23+
* @param <N> The target type
24+
* @return This builder as a typed ConfigValue
25+
*/
26+
<N> ConfigValue<N> as(Class<N> clazz);
27+
28+
/**
29+
* Sets the type of the configuration entry to the given class, sets the converter to the one given and
30+
* returns this builder. If a converter is provided for one of the types supported by
31+
* default (see {@link #as(Class)} then the provided converter is used instead of the built-in one.
32+
*
33+
* @param clazz The target type
34+
* @param converter The converter for the target type
35+
* @param <N> The target type
36+
* @return This builder as a typed ConfigValue
37+
*/
38+
<N> ConfigValue<N> as(Class<N> clazz, Converter<N> converter);
39+
40+
/**
41+
* Sets the default value to use in case the resolution returns null.
42+
* @param value the default value
43+
* @return This builder
44+
*/
45+
ConfigValue<T> withDefault(T value);
46+
47+
/**
48+
* Sets the default value to use in case the resolution returns null. Converts the given String to the type of
49+
* this resolver using the same method as used for the configuration entries.
50+
* @param value string value to be converted and used as default
51+
* @return This builder
52+
*/
53+
ConfigValue<T> withStringDefault(String value);
54+
55+
/**
56+
* Specify that a resolved value will get cached for a certain amount of time.
57+
* After the time expires the next {@link #getValue()} will again resolve the value
58+
* from the underlying {@link Config}.
59+
*
60+
* @param timeUnit the TimeUnit for the value
61+
* @param value the amount of the TimeUnit to wait
62+
* @return This builder
63+
*/
64+
ConfigValue<T> cacheFor(TimeUnit timeUnit, long value);
65+
66+
/**
67+
* Whether to evaluate variables in configured values.
68+
* A variable starts with '${' and ends with '}', e.g.
69+
* <pre>
70+
* mycompany.some.url=${myserver.host}/some/path
71+
* myserver.host=http://localhost:8081
72+
* </pre>
73+
* If 'evaluateVariables' is enabled, the result for the above key
74+
* {@code "mycompany.some.url"} would be:
75+
* {@code "http://localhost:8081/some/path"}
76+
* @param evaluateVariables whether to evaluate variables in values or not
77+
* @return This builder
78+
*/
79+
ConfigValue<T> evaluateVariables(boolean evaluateVariables);
80+
81+
/**
82+
* Appends the resolved value of the given property to the key of this builder.
83+
* TODO further explain.
84+
* @return This builder
85+
*/
86+
ConfigValue<T> withLookupChain(String... postfixNames);
87+
88+
/**
89+
* Whether to log picking up any value changes as INFO.
90+
*
91+
* @return This builder
92+
*/
93+
ConfigValue<T> logChanges(boolean logChanges);
94+
95+
/**
96+
* Returns the converted resolved filtered value.
97+
* @return the resolved value
98+
*/
99+
T getValue();
100+
101+
/**
102+
* Returns the key given in {@link Config#access(String)}.
103+
* @return the original key
104+
*/
105+
String getKey();
106+
107+
/**
108+
* Returns the actual key which led to successful resolution and corresponds to the resolved value. This applies
109+
* only when {@link #withLookupChain(String...)} is used.
110+
* Otherwise the resolved key should always be equal to the original key.
111+
* This method is provided for cases, when arameterized resolution is
112+
* requested but the value for such appended key is not found and some of the fallback keys is used.
113+
*
114+
* This should be called only after calling {@link #getValue()} otherwise the value is undefined (but likely
115+
* null).
116+
*/
117+
String getResolvedKey();
118+
119+
/**
120+
* Returns the default value provided by {@link #withDefault(Object)} or {@link #withStringDefault(String)}.
121+
* Returns null if no default was provided.
122+
* @return the default value or {@code null}
123+
*/
124+
T getDefaultValue();
125+
}
Collapse file
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package javx.config.spi;
2+
3+
/**
4+
* A very simple interface for conversion of configuration values from String to any Java type.
5+
*
6+
* @author <a href="mailto:struberg@apache.org">Mark Struberg</a>
7+
* @author <a href="mailto:gpetracek@apache.org">Gerhard Petracek</a>
8+
*/
9+
public interface Converter<T> {
10+
/**
11+
* Returns the converted value of the configuration entry.
12+
* @param value The String property value to convert
13+
* @return Converted value
14+
*/
15+
T convert(String value);
16+
17+
}
Collapse file

‎impl/src/main/java/org/apache/geronimo/config/ConfigImpl.java‎

Copy file name to clipboardExpand all lines: impl/src/main/java/org/apache/geronimo/config/ConfigImpl.java
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.logging.Logger;
2828

2929
import javx.config.Config;
30+
import javx.config.ConfigValue;
3031
import javx.config.spi.ConfigFilter;
3132
import javx.config.spi.ConfigSource;
3233

@@ -56,6 +57,11 @@ public String getValue(String key) {
5657
return null;
5758
}
5859

60+
@Override
61+
public ConfigValue<String> access(String key) {
62+
return null;
63+
}
64+
5965
@Override
6066
public Map<String, String> getAllProperties() {
6167
Map<String, String> result = new HashMap<String, String>();
Collapse file
+178Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package org.apache.geronimo.config;
2+
3+
import javx.config.Config;
4+
import javx.config.ConfigValue;
5+
import javx.config.spi.Converter;
6+
7+
import java.util.concurrent.TimeUnit;
8+
import java.util.logging.Level;
9+
import java.util.logging.Logger;
10+
11+
/**
12+
* @author <a href="mailto:struberg@apache.org">Mark Struberg</a>
13+
*/
14+
public class ConfigValueImpl<T> implements ConfigValue<T> {
15+
private static final Logger logger = Logger.getLogger(ConfigValueImpl.class.getName());
16+
17+
private final ConfigImpl config;
18+
19+
private String keyOriginal;
20+
21+
private String keyResolved;
22+
23+
private Class<?> configEntryType = String.class;
24+
25+
private boolean withDefault = false;
26+
private T defaultValue;
27+
28+
private String propertyParameter;
29+
30+
private String parameterValue;
31+
32+
private Converter<?> converter;
33+
34+
private boolean evaluateVariables = false;
35+
36+
private boolean logChanges = false;
37+
38+
private long cacheTimeMs = -1;
39+
private volatile long reloadAfter = -1;
40+
private T lastValue = null;
41+
42+
public ConfigValueImpl(ConfigImpl config) {
43+
this.config = config;
44+
}
45+
46+
@Override
47+
public <N> ConfigValue<N> as(Class<N> clazz) {
48+
configEntryType = clazz;
49+
this.converter = null;
50+
return (ConfigValue<N>) this;
51+
}
52+
53+
@Override
54+
public <N> ConfigValue<N> as(Class<N> clazz, Converter<N> converter) {
55+
configEntryType = clazz;
56+
this.converter = converter;
57+
return (ConfigValue<N>) this;
58+
}
59+
60+
@Override
61+
public ConfigValue<T> withDefault(T value) {
62+
defaultValue = value;
63+
withDefault = true;
64+
return this;
65+
}
66+
67+
@Override
68+
public ConfigValue<T> withStringDefault(String value) {
69+
if (value == null || value.isEmpty())
70+
{
71+
throw new RuntimeException("Empty String or null supplied as string-default value for property "
72+
+ keyOriginal);
73+
}
74+
75+
defaultValue = convert(value);
76+
withDefault = true;
77+
return this;
78+
}
79+
80+
@Override
81+
public ConfigValue<T> cacheFor(TimeUnit timeUnit, long value) {
82+
this.cacheTimeMs = timeUnit.toMillis(value);
83+
return this;
84+
}
85+
86+
@Override
87+
public ConfigValue<T> evaluateVariables(boolean evaluateVariables) {
88+
this.evaluateVariables = evaluateVariables;
89+
return this;
90+
}
91+
92+
@Override
93+
public ConfigValue<T> withLookupChain(String... postfixNames) {
94+
//X TODO
95+
return null;
96+
}
97+
98+
@Override
99+
public ConfigValue<T> logChanges(boolean logChanges) {
100+
this.logChanges = logChanges;
101+
return this;
102+
}
103+
104+
@Override
105+
public T getValue() {
106+
long now = -1;
107+
if (cacheTimeMs > 0)
108+
{
109+
now = System.currentTimeMillis();
110+
if (now <= reloadAfter)
111+
{
112+
return lastValue;
113+
}
114+
}
115+
116+
String valueStr = resolveStringValue();
117+
T value = convert(valueStr);
118+
119+
if (withDefault)
120+
{
121+
value = fallbackToDefaultIfEmpty(keyResolved, value, defaultValue);
122+
}
123+
124+
if (logChanges && (value != null && !value.equals(lastValue) || (value == null && lastValue != null)) )
125+
{
126+
logger.log(Level.INFO, "New value {0} for key {1}.",
127+
new Object[]{config.filterConfigValueForLog(keyOriginal, valueStr), keyOriginal});
128+
}
129+
130+
lastValue = value;
131+
132+
if (cacheTimeMs > 0)
133+
{
134+
reloadAfter = now + cacheTimeMs;
135+
}
136+
137+
return value;
138+
}
139+
140+
private String resolveStringValue() {
141+
//X TODO implement lookupChain
142+
143+
return config.getValue(keyOriginal);
144+
}
145+
146+
@Override
147+
public String getKey() {
148+
return keyOriginal;
149+
}
150+
151+
@Override
152+
public String getResolvedKey() {
153+
return keyResolved;
154+
}
155+
156+
@Override
157+
public T getDefaultValue() {
158+
return defaultValue;
159+
}
160+
161+
private T convert(String value) {
162+
//X TODO
163+
return null;
164+
}
165+
166+
private T fallbackToDefaultIfEmpty(String key, T value, T defaultValue) {
167+
if (value == null || (value instanceof String && ((String)value).isEmpty()))
168+
{
169+
logger.log(Level.FINE, "no configured value found for key {0}, using default value {1}.",
170+
new Object[]{key, defaultValue});
171+
172+
return defaultValue;
173+
}
174+
175+
return value;
176+
}
177+
178+
}
Collapse file

‎impl/src/main/java/org/apache/geronimo/config/DefaultConfigProvider.java‎

Copy file name to clipboardExpand all lines: impl/src/main/java/org/apache/geronimo/config/DefaultConfigProvider.java
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
*/
4343
public class DefaultConfigProvider implements ConfigProvider.SPI {
4444

45-
protected static Map<ClassLoader, WeakReference<Config>> configs = Collections.synchronizedMap(new WeakHashMap<ClassLoader, WeakReference<Config>>());
45+
protected static Map<ClassLoader, WeakReference<Config>> configs
46+
= Collections.synchronizedMap(new WeakHashMap<ClassLoader, WeakReference<Config>>());
4647

4748

4849
@Override
@@ -127,7 +128,7 @@ private Collection<? extends ConfigSource> getCustomPropertyFiles(ClassLoader fo
127128

128129
private void registerConfig(Config config, ClassLoader forClassLoader) {
129130
synchronized (DefaultConfigProvider.class) {
130-
configs.put(forClassLoader, new WeakReference<Config>(config));
131+
configs.put(forClassLoader, new WeakReference<>(config));
131132
}
132133
}
133134

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.