Skip to content

Commit

Permalink
Supported indexed properties with Env variables (#743)
Browse files Browse the repository at this point in the history
  • Loading branch information
radcortez authored Apr 7, 2022
1 parent 09d3376 commit df15eca
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,30 @@ public static String replaceNonAlphanumericByUnderscores(final String name) {

public static String toLowerCaseAndDotted(final String name) {
int length = name.length();
int beginSegment = 0;
boolean quotesOpen = false;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
char c = name.charAt(i);
if ('_' == c) {
String segment = sb.substring(beginSegment, i);
try {
Integer.parseInt(segment);
sb.replace(beginSegment - 1, beginSegment, "[").append("]");

int j = i + 1;
if (j < length) {
if ('_' == name.charAt(j)) {
sb.append(".");
i = j;
}
}

continue;
} catch (NumberFormatException e) {
// Ignore
}

int j = i + 1;
if (j < length) {
if ('_' == name.charAt(j) && !quotesOpen) {
Expand All @@ -129,6 +148,7 @@ public static String toLowerCaseAndDotted(final String name) {
} else {
sb.append(".");
}
beginSegment = j;
} else {
sb.append(Character.toLowerCase(c));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -900,12 +900,64 @@ private static Set<String> additionalMappedProperties(final Set<String> mappedPr
Set<String> additionalMappedProperties = new HashSet<>();
// Look for unmatched properties if we can find one in the Env ones and add it
for (String mappedProperty : mappedProperties) {
Set<String> matchedEnvProperties = new HashSet<>();
for (String envProperty : envProperties) {
// TODO - handled indexed.
if (envProperty.equalsIgnoreCase(replaceNonAlphanumericByUnderscores(mappedProperty))) {
additionalMappedProperties.add(mappedProperty);
matchedEnvProperties.add(envProperty);
break;
}

NameIterator ni = new NameIterator(mappedProperty);
StringBuilder sb = new StringBuilder();
while (ni.hasNext()) {
String propertySegment = ni.getNextSegment();
if (isIndexed(propertySegment)) {
// A mapped index property is represented as foo.bar[*] or foo.bar[*].baz
// The env property is represented as FOO_BAR_0_ or FOO_BAR_0__BAZ
// We need to match these somehow
int position = ni.getPosition();
int indexStart = propertySegment.indexOf("[") + position + 1;
// If the segment is indexed, we try to match all previous segments with the env candidates
if (envProperty.length() >= indexStart
&& envProperty.toLowerCase().startsWith(replaceNonAlphanumericByUnderscores(
sb + propertySegment.substring(0, indexStart - position - 1) + "_"))) {

// Search for the ending _ to retrieve the possible index
int indexEnd = -1;
for (int i = indexStart + 1; i < envProperty.length(); i++) {
if (envProperty.charAt(i) == '_') {
indexEnd = i;
break;
}
}

// Extract the index from the env property
// We don't care if this is numeric, it will be validated on the mapping retrieval
String index = envProperty.substring(indexStart + 1, indexEnd);
sb.append(propertySegment, 0, propertySegment.indexOf("[") + 1)
.append(index)
.append("]");
}
} else {
sb.append(propertySegment);
}

ni.next();

if (ni.hasNext()) {
sb.append(".");
}
}

String mappedPropertyToMatch = sb.toString();
if (envProperty.equalsIgnoreCase(replaceNonAlphanumericByUnderscores(mappedPropertyToMatch))) {
additionalMappedProperties.add(mappedPropertyToMatch);
matchedEnvProperties.add(envProperty);
// We cannot break here because if there are indexed properties they may match multiple envs
}
}
envProperties.removeAll(matchedEnvProperties);
}

return additionalMappedProperties;
Expand Down Expand Up @@ -939,6 +991,23 @@ private static String anyIfIndexed(final String propertyName) {
return builder.toString();
}

private static boolean isIndexed(final String propertyName) {
int indexStart = propertyName.indexOf("[");
int indexEnd = propertyName.indexOf("]");
if (indexStart != -1 && indexEnd != -1) {
String index = propertyName.substring(indexStart + 1, indexEnd);
if (index.equals("*")) {
return true;
}
try {
Integer.parseInt(index);
} catch (NumberFormatException e) {
return false;
}
}
return false;
}

private static boolean validateUnknown(final boolean validateUnknown, final SmallRyeConfig config) {
return config.getOptionalValue(SMALLRYE_CONFIG_MAPPING_VALIDATE_UNKNOWN, Boolean.class)
.orElse(validateUnknown);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1337,7 +1337,7 @@ interface RestClientConfig {

KeystoreConfig keystore();

//List<Endpoint> endpoints();
List<Endpoint> endpoints();

interface KeystoreConfig {
Optional<String> type();
Expand All @@ -1349,6 +1349,8 @@ interface KeystoreConfig {

interface Endpoint {
String path();

List<String> methods();
}
}
}
Expand All @@ -1360,8 +1362,9 @@ void envPropertiesWithoutDottedProperties() {
put("MY_APP_REST_CONFIG_MY_CLIENT_BASE_URI", "http://localhost:8080");
put("MY_APP_REST_CONFIG_MY_CLIENT_KEYSTORE_PATH", "config/keystores/my-keys.p12");
put("MY_APP_REST_CONFIG_MY_CLIENT_KEYSTORE_PASSWORD", "p@ssw0rd");
put("MY_APP_REST_CONFIG_MY_CLIENT_ENDPOINTS_1_PATH", "/hello");
//put("my-app.rest-config.my-client.endpoints[1].path", "/hello");
put("MY_APP_REST_CONFIG_MY_CLIENT_ENDPOINTS_0__PATH", "/hello");
put("MY_APP_REST_CONFIG_MY_CLIENT_ENDPOINTS_0__METHODS_0_", "GET");
put("MY_APP_REST_CONFIG_MY_CLIENT_ENDPOINTS_0__METHODS_1_", "POST");
}
};

Expand All @@ -1379,13 +1382,19 @@ void envPropertiesWithoutDottedProperties() {
assertTrue(properties.contains("my-app.rest-config.my-client.base-uri"));
assertTrue(properties.contains("my-app.rest-config.my-client.keystore.path"));
assertTrue(properties.contains("my-app.rest-config.my-client.keystore.password"));
assertTrue(properties.contains("my-app.rest-config.my-client.endpoints[0].path"));
assertTrue(properties.contains("my-app.rest-config.my-client.endpoints[0].methods[0]"));
assertTrue(properties.contains("my-app.rest-config.my-client.endpoints[0].methods[1]"));

MyRestClientConfig mapping = config.getConfigMapping(MyRestClientConfig.class);
assertTrue(mapping.client().isPresent());
assertEquals(URI.create("http://localhost:8080"), mapping.client().get().baseUri());
assertEquals(Paths.get("config/keystores/my-keys.p12"), mapping.client().get().keystore().path());
assertEquals("p@ssw0rd", mapping.client().get().keystore().password());
//assertFalse(mapping.client().get().endpoints().isEmpty());
assertFalse(mapping.client().get().endpoints().isEmpty());
assertEquals("/hello", mapping.client().get().endpoints().get(0).path());
assertEquals("GET", mapping.client().get().endpoints().get(0).methods().get(0));
assertEquals("POST", mapping.client().get().endpoints().get(0).methods().get(1));
}

@ConfigMapping(prefix = "optionals")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.stream.StreamSupport;

Expand Down Expand Up @@ -95,4 +98,26 @@ void ordinal() {
assertTrue(configSource instanceof EnvConfigSource);
assertEquals(configSource.getOrdinal(), 301);
}

@Test
void indexed() {
Map<String, String> env = new HashMap<String, String>() {
{
put("INDEXED_0_", "foo");
put("INDEXED_0__PROP", "bar");
put("INDEXED_0__PROPS_0_", "0");
put("INDEXED_0__PROPS_1_", "1");
}
};

EnvConfigSource envConfigSource = new EnvConfigSource(env, 300);
SmallRyeConfig config = new SmallRyeConfigBuilder()
.addDefaultInterceptors()
.withSources(envConfigSource)
.build();

assertTrue(config.getValues("indexed", String.class, ArrayList::new).contains("foo"));
assertTrue(config.getValues("indexed[0].props", String.class, ArrayList::new).contains("0"));
assertTrue(config.getValues("indexed[0].props", String.class, ArrayList::new).contains("1"));
}
}

0 comments on commit df15eca

Please sign in to comment.