Skip to content

Commit

Permalink
Priority of REST Client Config changed to Quarkus FQN, config key, si…
Browse files Browse the repository at this point in the history
…mple name
  • Loading branch information
radcortez authored and gsmet committed Dec 10, 2024
1 parent aa5baa7 commit 79e2beb
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

import static io.smallrye.config.ConfigValue.CONFIG_SOURCE_COMPARATOR;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.OptionalInt;
import java.util.function.Function;
import java.util.function.Supplier;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

Expand All @@ -17,7 +20,6 @@
import io.smallrye.config.ConfigValue;
import io.smallrye.config.FallbackConfigSourceInterceptor;
import io.smallrye.config.Priorities;
import io.smallrye.config.RelocateConfigSourceInterceptor;
import io.smallrye.config.SmallRyeConfigBuilder;

/**
Expand Down Expand Up @@ -70,49 +72,66 @@ public SmallRyeConfigBuilder configBuilder(final SmallRyeConfigBuilder builder)

Map<String, String> quarkusFallbacks = new HashMap<>();
Map<String, String> microProfileFallbacks = new HashMap<>();
// relocates [All Combinations] -> quarkus.rest-client."FQN".*
Map<String, String> relocates = new HashMap<>();
Map<String, List<String>> relocates = new HashMap<>();

for (RegisteredRestClient restClient : restClients) {
if (runtime) {
RestClientsConfig.RestClientKeysProvider.KEYS.add(restClient.getFullName());
}

// FQN -> Simple Name
String quotedFullName = "\"" + restClient.getFullName() + "\"";
quarkusFallbacks.put(quotedFullName, restClient.getSimpleName());
relocates.put(restClient.getSimpleName(), quotedFullName);
// Simple Name -> Quoted Simple Name
String quotedSimpleName = "\"" + restClient.getSimpleName() + "\"";
quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName);
relocates.put(quotedSimpleName, quotedFullName);

String configKey = restClient.getConfigKey();

// relocates [All Combinations] -> quarkus.rest-client."FQN".*
List<String> fullNameRelocates = new ArrayList<>();
relocates.put(quotedFullName, fullNameRelocates);

if (configKey != null && !restClient.isConfigKeyEqualsNames()) {
String quotedConfigKey = "\"" + configKey + "\"";
if (!quotedConfigKey.equals(quotedFullName) && !quotedConfigKey.equals(quotedSimpleName)) {
if (restClient.isConfigKeyComposed()) {
// Quoted Simple Name -> Quoted Config Key
quarkusFallbacks.put(quotedSimpleName, quotedConfigKey);
relocates.put(quotedConfigKey, quotedFullName);
// FQN -> Quoted Config Key -> Quoted Simple Name -> Simple Name
quarkusFallbacks.put(quotedFullName, quotedConfigKey);
quarkusFallbacks.put(quotedConfigKey, restClient.getSimpleName());
quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName);
fullNameRelocates.add(quotedConfigKey);
fullNameRelocates.add(restClient.getSimpleName());
fullNameRelocates.add(quotedSimpleName);
} else {
// Quoted Simple Name -> Config Key
quarkusFallbacks.put(quotedSimpleName, configKey);
relocates.put(configKey, quotedFullName);
// Config Key -> Quoted Config Key
// FQN -> Config Key -> Quoted Config Key -> Quoted Simple Name -> Simple Name
quarkusFallbacks.put(quotedFullName, configKey);
quarkusFallbacks.put(configKey, quotedConfigKey);
relocates.put(quotedConfigKey, quotedFullName);
quarkusFallbacks.put(quotedConfigKey, restClient.getSimpleName());
quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName);
fullNameRelocates.add(configKey);
fullNameRelocates.add(quotedConfigKey);
fullNameRelocates.add(restClient.getSimpleName());
fullNameRelocates.add(quotedSimpleName);
}
} else {
// FQN -> Quoted Simple Name -> Simple Name
quarkusFallbacks.put(quotedFullName, restClient.getSimpleName());
quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName);
fullNameRelocates.add(restClient.getSimpleName());
fullNameRelocates.add(quotedSimpleName);
}
} else {
// FQN -> Quoted Simple Name -> Simple Name
quarkusFallbacks.put(quotedFullName, restClient.getSimpleName());
quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName);
fullNameRelocates.add(restClient.getSimpleName());
fullNameRelocates.add(quotedSimpleName);
}

// FQN -> FQN/mp-rest
String mpRestFullName = restClient.getFullName() + "/mp-rest/";
microProfileFallbacks.put(quotedFullName, mpRestFullName);
relocates.put(mpRestFullName, quotedFullName);
fullNameRelocates.add(mpRestFullName);
if (configKey != null && !configKey.equals(restClient.getFullName())) {
String mpConfigKey = configKey + "/mp-rest/";
microProfileFallbacks.put(mpRestFullName, mpConfigKey);
relocates.put(mpConfigKey, quotedFullName);
fullNameRelocates.add(mpConfigKey);
}
}

Expand Down Expand Up @@ -145,12 +164,7 @@ public OptionalInt getPriority() {
builder.withInterceptorFactories(new ConfigSourceInterceptorFactory() {
@Override
public ConfigSourceInterceptor getInterceptor(final ConfigSourceInterceptorContext context) {
return new RelocateConfigSourceInterceptor(new Relocates(relocates)) {
@Override
public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) {
return context.proceed(name);
}
};
return new Relocates(relocates);
}
});
return builder;
Expand Down Expand Up @@ -298,35 +312,105 @@ public String apply(final String name) {

/**
* Relocates every possible name (Quarkus and MP) to
* <code>quarkus.rest-client."[FQN of the REST Interface]".*</code>
* <code>quarkus.rest-client."[FQN of the REST Interface]".*</code>. The same <code>configKey</code> can relocate
* to many <code>quarkus.rest-client."[FQN of the REST Interface]".*</code>.
*/
private record Relocates(Map<String, String> names) implements Function<String, String> {
private static class Relocates implements ConfigSourceInterceptor {
private final Map<String, List<String>> relocates;

Relocates(final Map<String, List<String>> relocates) {
this.relocates = new HashMap<>();
// Inverts the Map to make it easier to search
for (Map.Entry<String, List<String>> entry : relocates.entrySet()) {
for (String from : entry.getValue()) {
this.relocates.putIfAbsent(from, new ArrayList<>());
this.relocates.get(from).add(entry.getKey());
}
}
}

@Override
public String apply(final String name) {
int indexOfRestClient = indexOfRestClient(name);
if (indexOfRestClient != -1) {
for (Map.Entry<String, String> entry : names.entrySet()) {
String original = entry.getKey();
String target = entry.getValue();
int endOfConfigKey = indexOfRestClient + original.length();
if (name.regionMatches(indexOfRestClient, original, 0, original.length())) {
if (name.length() > endOfConfigKey && name.charAt(endOfConfigKey) == '.') {
return REST_CLIENT_PREFIX + target + name.substring(endOfConfigKey);
public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) {
return context.proceed(name);
}

@Override
public Iterator<String> iterateNames(final ConfigSourceInterceptorContext context) {
List<String> relocatedNames = new ArrayList<>(relocates.size());
List<Supplier<Iterator<String>>> iterators = new ArrayList<>();
iterators.add(new Supplier<Iterator<String>>() {
@Override
public Iterator<String> get() {
Iterator<String> names = context.iterateNames();

return new Iterator<>() {
@Override
public boolean hasNext() {
return names.hasNext();
}
}

@Override
public String next() {
String name = names.next();
int indexOfRestClient = indexOfRestClient(name);
if (indexOfRestClient != -1) {
for (Map.Entry<String, List<String>> entry : relocates.entrySet()) {
String original = entry.getKey();
int endOfConfigKey = indexOfRestClient + original.length();
if (name.regionMatches(indexOfRestClient, original, 0, original.length())) {
if (name.length() > endOfConfigKey && name.charAt(endOfConfigKey) == '.') {
for (String relocatedName : entry.getValue()) {
relocatedNames.add(
REST_CLIENT_PREFIX + relocatedName + name.substring(endOfConfigKey));
}
return name;
}
}
}
}
int slash = name.indexOf("/");
if (slash != -1) {
if (name.regionMatches(slash + 1, "mp-rest/", 0, 8)) {
String property = name.substring(slash + 9);
if (MICROPROFILE_NAMES.containsKey(property)) {
relocatedNames.add(REST_CLIENT_PREFIX + "\"" + name.substring(0, slash) + "\"."
+ MICROPROFILE_NAMES.getOrDefault(property, property));
}
return name;
}
}
return name;
}
};
}
}
int slash = name.indexOf("/");
if (slash != -1) {
if (name.regionMatches(slash + 1, "mp-rest/", 0, 8)) {
String property = name.substring(slash + 9);
if (MICROPROFILE_NAMES.containsKey(property)) {
return REST_CLIENT_PREFIX + "\"" + name.substring(0, slash) + "\"."
+ MICROPROFILE_NAMES.getOrDefault(property, property);
});
iterators.add(new Supplier<Iterator<String>>() {
@Override
public Iterator<String> get() {
return relocatedNames.iterator();
}
});
Iterator<Supplier<Iterator<String>>> iterator = iterators.iterator();
return new Iterator<>() {
Iterator<String> names = iterator.next().get();

@Override
public boolean hasNext() {
if (names.hasNext()) {
return true;
} else {
if (iterator.hasNext()) {
names = iterator.next().get();
}
return names.hasNext();
}
}
}
return name;

@Override
public String next() {
return names.next();
}
};
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
import org.junit.jupiter.api.Test;

import io.quarkus.restclient.config.RestClientsConfig.RestClientConfig;
import io.quarkus.restclient.config.key.SharedOneConfigKeyRestClient;
import io.quarkus.restclient.config.key.SharedThreeConfigKeyRestClient;
import io.quarkus.restclient.config.key.SharedTwoConfigKeyRestClient;
import io.quarkus.runtime.configuration.ConfigUtils;
import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigBuilder;
Expand Down Expand Up @@ -233,6 +236,81 @@ public List<RegisteredRestClient> getRestClients() {
assertThat(restClientConfig.uri().get()).isEqualTo("http://localhost:8082");
}

@Test
void restClientDuplicateSimpleName() {
SmallRyeConfig config = ConfigUtils.emptyConfigBuilder()
.withMapping(RestClientsConfig.class)
.withCustomizers(new SmallRyeConfigBuilderCustomizer() {
@Override
public void configBuilder(final SmallRyeConfigBuilder builder) {
new AbstractRestClientConfigBuilder() {
@Override
public List<RegisteredRestClient> getRestClients() {
return List.of(
new RegisteredRestClient(
io.quarkus.restclient.config.simple.one.SimpleNameRestClient.class, "one"),
new RegisteredRestClient(
io.quarkus.restclient.config.simple.two.SimpleNameRestClient.class, "two"));
}
}.configBuilder(builder);
}
})
.build();
assertNotNull(config);

RestClientsConfig restClientsConfig = config.getConfigMapping(RestClientsConfig.class);
assertEquals(2, restClientsConfig.clients().size());
assertThat(restClientsConfig.getClient(io.quarkus.restclient.config.simple.one.SimpleNameRestClient.class).uri().get())
.isEqualTo("http://localhost:8081");
assertThat(restClientsConfig.getClient(io.quarkus.restclient.config.simple.two.SimpleNameRestClient.class).uri().get())
.isEqualTo("http://localhost:8082");
}

@Test
void restClientSharedConfigKey() {
SmallRyeConfig config = ConfigUtils.emptyConfigBuilder()
.withMapping(RestClientsConfig.class)
.withCustomizers(new SmallRyeConfigBuilderCustomizer() {
@Override
public void configBuilder(final SmallRyeConfigBuilder builder) {
new AbstractRestClientConfigBuilder() {
@Override
public List<RegisteredRestClient> getRestClients() {
return List.of(
new RegisteredRestClient(SharedOneConfigKeyRestClient.class, "shared"),
new RegisteredRestClient(SharedTwoConfigKeyRestClient.class, "shared"),
new RegisteredRestClient(SharedThreeConfigKeyRestClient.class, "shared"));
}
}.configBuilder(builder);
}
})
.build();
assertNotNull(config);

RestClientsConfig restClientsConfig = config.getConfigMapping(RestClientsConfig.class);
assertEquals(3, restClientsConfig.clients().size());

RestClientConfig restClientConfigOne = restClientsConfig.getClient(SharedOneConfigKeyRestClient.class);
assertThat(restClientConfigOne.uri().get()).isEqualTo("http://localhost:8081");
assertEquals(2, restClientConfigOne.headers().size());
assertEquals("one", restClientConfigOne.headers().get("two"));
assertEquals("two", restClientConfigOne.headers().get("one"));

RestClientConfig restClientConfigTwo = restClientsConfig
.getClient(SharedTwoConfigKeyRestClient.class);
assertThat(restClientConfigTwo.uri().get()).isEqualTo("http://localhost:8082");
assertEquals(2, restClientConfigTwo.headers().size());
assertEquals("one", restClientConfigTwo.headers().get("two"));
assertEquals("two", restClientConfigTwo.headers().get("one"));

RestClientConfig restClientConfigThree = restClientsConfig
.getClient(SharedThreeConfigKeyRestClient.class);
assertThat(restClientConfigThree.uri().get()).isEqualTo("http://localhost:8083");
assertEquals(2, restClientConfigThree.headers().size());
assertEquals("one", restClientConfigThree.headers().get("two"));
assertEquals("two", restClientConfigThree.headers().get("one"));
}

@Test
void buildTimeConfig() {
SmallRyeConfig config = ConfigUtils.emptyConfigBuilder()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.restclient.config.key;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(configKey = "shared")
public interface SharedOneConfigKeyRestClient {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.restclient.config.key;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(configKey = "shared")
public interface SharedThreeConfigKeyRestClient {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.restclient.config.key;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(configKey = "shared")
public interface SharedTwoConfigKeyRestClient {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.restclient.config.simple.one;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(configKey = "one")
public interface SimpleNameRestClient {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.restclient.config.simple.two;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(configKey = "two")
public interface SimpleNameRestClient {
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,12 @@ mp.key/mp-rest/proxyAddress=mp.key
mp.key/mp-rest/queryParamStyle=COMMA_SEPARATED

MPConfigKeyRestClient/mp-rest/uri=http://localhost:8082

quarkus.rest-client.one.uri=http://localhost:8081
quarkus.rest-client.two.uri=http://localhost:8082

quarkus.rest-client."io.quarkus.restclient.config.key.SharedOneConfigKeyRestClient".uri=http://localhost:8081
quarkus.rest-client."io.quarkus.restclient.config.key.SharedTwoConfigKeyRestClient".uri=http://localhost:8082
io.quarkus.restclient.config.key.SharedThreeConfigKeyRestClient/mp-rest/uri=http://localhost:8083
quarkus.rest-client.shared.headers.two=one
quarkus.rest-client.shared.headers.one=two

0 comments on commit 79e2beb

Please sign in to comment.