Skip to content

Commit 7ddb68a

Browse files
committed
Aggregated parameter implementation
1 parent c4fd199 commit 7ddb68a

File tree

10 files changed

+125
-0
lines changed

10 files changed

+125
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.github.joschi.jadconfig;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
/**
9+
* This annotation is intended to collect all configuration properties starting with the same prefix.
10+
* Think opensearch.path.repo and opensearch.node.roles values aggregated as a {@code Map<String,String>}
11+
*/
12+
@Retention(RetentionPolicy.RUNTIME)
13+
@Target(ElementType.FIELD)
14+
public @interface AggregatedParameter {
15+
/**
16+
* The prefix that will be used to match configuration properties. There is no preprocessing and it will be used
17+
* as defined. So if you want to match opensearch.path.repo and opensearch.node.roles, your prefix should be
18+
* {@code opensearch.}
19+
*/
20+
String prefix();
21+
}

src/main/java/com/github/joschi/jadconfig/JadConfig.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Map;
2121
import java.util.Objects;
2222
import java.util.Optional;
23+
import java.util.function.Function;
2324
import java.util.stream.Collectors;
2425

2526

@@ -202,6 +203,27 @@ private void processClassField(Object configurationBean, Field field) throws Val
202203
throw new ParameterException("Couldn't set field " + field.getName(), e);
203204
}
204205
}
206+
207+
processPrefixParameter(configurationBean, field);
208+
}
209+
210+
private void processPrefixParameter(Object configurationBean, Field field) {
211+
AggregatedParameter parameter = field.getAnnotation(AggregatedParameter.class);
212+
if (parameter != null) {
213+
LOG.debug("Processing prefixed field {}", field);
214+
final Map<String, String> params = repositories.stream().flatMap(r -> collectPrefixedParams(r, parameter.prefix()).entrySet().stream()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
215+
try {
216+
field.setAccessible(true);
217+
field.set(configurationBean, params);
218+
} catch (IllegalAccessException e) {
219+
throw new ParameterException("Couldn't set field " + field.getName(), e);
220+
}
221+
}
222+
}
223+
224+
private Map<String, String> collectPrefixedParams(Repository repository, String prefix) {
225+
final Collection<String> names = repository.readNames(prefix);
226+
return names.stream().collect(Collectors.toMap(Function.identity(), repository::read));
205227
}
206228

207229
private String lookupFallbackParameter(Parameter parameter) {

src/main/java/com/github/joschi/jadconfig/Repository.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.github.joschi.jadconfig;
22

3+
import java.util.Collection;
4+
35
/**
46
* Interface for configuration repositories
57
* <p>A configuration repository can be any data source containing configuration data,
@@ -25,6 +27,8 @@ public interface Repository {
2527
*/
2628
String read(String name);
2729

30+
Collection<String> readNames(String prefix);
31+
2832
/**
2933
* Closes the underlying data source when it isn't require any more.
3034
*

src/main/java/com/github/joschi/jadconfig/repositories/EnvironmentRepository.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import com.github.joschi.jadconfig.Repository;
44
import com.github.joschi.jadconfig.RepositoryException;
55

6+
import java.util.Collection;
7+
import java.util.stream.Collectors;
8+
69
/**
710
* {@link Repository} class providing access to environment variables.
811
* <p/>
@@ -75,6 +78,20 @@ public String read(final String name) {
7578
return System.getenv(envName);
7679
}
7780

81+
@Override
82+
public Collection<String> readNames(String namePrefix) {
83+
84+
final String envName;
85+
86+
if (upperCase) {
87+
envName = (prefix + namePrefix).toUpperCase();
88+
} else {
89+
envName = prefix + namePrefix;
90+
}
91+
92+
return System.getenv().keySet().stream().filter(e -> e.startsWith(envName)).collect(Collectors.toSet());
93+
}
94+
7895
@Override
7996
public void close() throws RepositoryException {
8097
// NOP

src/main/java/com/github/joschi/jadconfig/repositories/InMemoryRepository.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import com.github.joschi.jadconfig.Repository;
44
import com.github.joschi.jadconfig.RepositoryException;
55

6+
import java.util.Collection;
67
import java.util.HashMap;
78
import java.util.Map;
9+
import java.util.stream.Collectors;
810

911
/**
1012
* {@link Repository} class providing access to a simple configuration repository backed by {@link HashMap}
@@ -42,6 +44,11 @@ public String read(String name) {
4244
return properties.get(name);
4345
}
4446

47+
@Override
48+
public Collection<String> readNames(String prefix) {
49+
return properties.keySet().stream().filter(key -> key.startsWith(prefix)).collect(Collectors.toSet());
50+
}
51+
4552
@Override
4653
public void close() throws RepositoryException {
4754

src/main/java/com/github/joschi/jadconfig/repositories/PropertiesRepository.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
import java.io.FileReader;
88
import java.io.IOException;
99
import java.io.Reader;
10+
import java.util.Collection;
1011
import java.util.Properties;
12+
import java.util.stream.Collectors;
1113

1214
/**
1315
* {@link Repository} class providing access to a configuration repository backed by {@link Properties} files
@@ -100,6 +102,11 @@ public String read(String name) {
100102
return PROPERTIES.getProperty(name);
101103
}
102104

105+
@Override
106+
public Collection<String> readNames(String prefix) {
107+
return PROPERTIES.stringPropertyNames().stream().filter(name -> name.startsWith(prefix)).collect(Collectors.toSet());
108+
}
109+
103110
/**
104111
* Close the underlying properties file.
105112
*

src/main/java/com/github/joschi/jadconfig/repositories/SystemPropertiesRepository.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import com.github.joschi.jadconfig.Repository;
44
import com.github.joschi.jadconfig.RepositoryException;
55

6+
import java.util.Collection;
7+
import java.util.stream.Collectors;
8+
69
/**
710
* {@link Repository} class providing access to System properties.
811
* <p/>
@@ -46,6 +49,11 @@ public String read(String name) {
4649
return System.getProperty(prefix + name);
4750
}
4851

52+
@Override
53+
public Collection<String> readNames(String prefix) {
54+
return System.getProperties().stringPropertyNames().stream().filter(key -> key.startsWith(prefix)).collect(Collectors.toSet());
55+
}
56+
4957
@Override
5058
public void close() throws RepositoryException {
5159

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.github.joschi.jadconfig;
2+
3+
import com.github.joschi.jadconfig.repositories.PropertiesRepository;
4+
import com.github.joschi.jadconfig.testbeans.SimpleConfigurationBean;
5+
import org.junit.Assert;
6+
import org.junit.Test;
7+
8+
public class AggregatedPropertiesTest {
9+
10+
private static final String PROPERTIES_FILE = PropertiesRepository.class.getResource("/testConfiguration.properties").getFile();
11+
12+
@Test
13+
public void testPrefixProperties() throws ValidationException, RepositoryException {
14+
final PropertiesRepository repository = new PropertiesRepository(PROPERTIES_FILE);
15+
16+
final SimpleConfigurationBean configurationBean = new SimpleConfigurationBean();
17+
final JadConfig jadConfig = new JadConfig(repository, configurationBean);
18+
jadConfig.process();
19+
20+
Assert.assertNotNull(configurationBean.getOpensearchProperties());
21+
Assert.assertEquals(3, configurationBean.getOpensearchProperties().size());
22+
23+
Assert.assertEquals("search,cluster_manager", configurationBean.getOpensearchProperties().get("opensearch.node.roles"));
24+
Assert.assertEquals("10gb", configurationBean.getOpensearchProperties().get("opensearch.node.search.cache.size"));
25+
Assert.assertEquals("/tmp", configurationBean.getOpensearchProperties().get("opensearch.path.repo"));
26+
}
27+
}

src/test/java/com/github/joschi/jadconfig/testbeans/SimpleConfigurationBean.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package com.github.joschi.jadconfig.testbeans;
22

33
import com.github.joschi.jadconfig.Parameter;
4+
import com.github.joschi.jadconfig.AggregatedParameter;
45
import com.github.joschi.jadconfig.converters.StringListConverter;
56

67
import java.io.File;
78
import java.net.URI;
89
import java.nio.file.Path;
910
import java.util.List;
11+
import java.util.Map;
1012

1113
public class SimpleConfigurationBean {
1214

@@ -58,6 +60,9 @@ public class SimpleConfigurationBean {
5860
@Parameter(value = "test.Nonexistent3", fallbackPropertyName = "test.fallback.secondary")
5961
private String myHardcodedDefaultString = "foobar";
6062

63+
@AggregatedParameter(prefix = "opensearch.")
64+
private Map<String, String> opensearchProperties;
65+
6166
public String getMyString() {
6267
return myString;
6368
}
@@ -121,4 +126,8 @@ public String getMyNonexistentString() {
121126
public String getMyHardcodedDefaultString() {
122127
return myHardcodedDefaultString;
123128
}
129+
130+
public Map<String, String> getOpensearchProperties() {
131+
return opensearchProperties;
132+
}
124133
}

src/test/resources/testConfiguration.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@ test.file=testConfiguration.properties
1616
test.path=testConfiguration.properties
1717
test.fallback.primary=prim
1818
test.fallback.secondary=sec
19+
opensearch.node.roles=search,cluster_manager
20+
opensearch.node.search.cache.size=10gb
21+
opensearch.path.repo=/tmp

0 commit comments

Comments
 (0)