Skip to content

Commit

Permalink
MP Config fixes (#1721)
Browse files Browse the repository at this point in the history
MP Config implementation to correctly support mutable config sources.
  • Loading branch information
tomas-langer authored May 6, 2020
1 parent b842c91 commit 7d2f708
Show file tree
Hide file tree
Showing 122 changed files with 3,572 additions and 1,818 deletions.
5 changes: 5 additions & 0 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@
<artifactId>helidon-config-object-mapping</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.config</groupId>
<artifactId>helidon-config-mp</artifactId>
<version>${helidon.version}</version>
</dependency>
<!-- security -->
<dependency>
<groupId>io.helidon.security</groupId>
Expand Down
7 changes: 0 additions & 7 deletions common/metrics/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,7 @@
<dependency>
<groupId>org.eclipse.microprofile.metrics</groupId>
<artifactId>microprofile-metrics-api</artifactId>
<version>${version.lib.microprofile-metrics-api}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.annotation.versioning</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -89,12 +89,26 @@ public static void sort(List<? extends Prioritized> list) {
* @param defaultPriority default priority for elements that do not have it
*/
public static void sort(List<?> list, int defaultPriority) {
list.sort(Comparator.comparingInt(it -> {
list.sort(priorityComparator(defaultPriority));
}

/**
* Returns a comparator for two objects, the classes for which are implementations of
* {@link io.helidon.common.Prioritized}, and/or optionally annotated with {@link javax.annotation.Priority}
* and which applies a specified default priority if either or both classes lack the annotation.
*
* @param <S> type of object being compared
* @param defaultPriority used if the classes for either or both objects
* lack the {@code Priority} annotation
* @return comparator
*/
public static <S> Comparator<S> priorityComparator(int defaultPriority) {
return Comparator.comparingInt(it -> {
if (it instanceof Class) {
return find((Class<?>) it, defaultPriority);
} else {
return find(it, defaultPriority);
}
}));
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.common.serviceloader;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Priority;

import io.helidon.common.Prioritized;

import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

public class PrioritiesTest {
@Test
void testSort() {
List<Service> services = new ArrayList<>(5);
services.add(new DefaultPriority());
services.add(new VeryLowPriority());
services.add(new LowestPriority());
services.add(new HigherPriority());
services.add(new LowerPriority());

Priorities.sort(services, 100);

validate(services);
}

@Test
void testComparator() {
List<Service> services = new ArrayList<>(5);
// intentionally different order than in other methods, to make sure it is not working "by accident"
services.add(new LowestPriority());
services.add(new LowerPriority());
services.add(new VeryLowPriority());
services.add(new HigherPriority());
services.add(new DefaultPriority());

services.sort(Priorities.priorityComparator(100));

validate(services);
}

private void validate(List<Service> services) {
assertThat("There must be 5 services in the list", services.size(), is(5));
assertThat(services.get(0).getIt(), is(HigherPriority.IT));
assertThat(services.get(1).getIt(), is(LowerPriority.IT));
assertThat(services.get(2).getIt(), is(DefaultPriority.IT));
assertThat(services.get(3).getIt(), is(VeryLowPriority.IT));
assertThat(services.get(4).getIt(), is(LowestPriority.IT));
}

private interface Service {
String getIt();
}

@Priority(1)
private static class HigherPriority implements Service {
private static final String IT = "higher";

@Override
public String getIt() {
return IT;
}
}

@Priority(2)
private static class LowerPriority implements Service {
private static final String IT = "lower";

@Override
public String getIt() {
return IT;
}
}

private static class DefaultPriority implements Service {
private static final String IT = "default";

@Override
public String getIt() {
return IT;
}
}

@Priority(101)
private static class VeryLowPriority implements Service {
private static final String IT = "veryLow";

@Override
public String getIt() {
return IT;
}
}

private static class LowestPriority implements Service, Prioritized {
private static final String IT = "lowest";

@Override
public String getIt() {
return IT;
}

@Override
public int priority() {
return 1000;
}
}
}
35 changes: 21 additions & 14 deletions config/tests/test-mp-reference/pom.xml → config/config-mp/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,40 @@
-->

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.helidon.config.tests</groupId>
<artifactId>helidon-config-tests-project</artifactId>
<groupId>io.helidon.config</groupId>
<artifactId>helidon-config-project</artifactId>
<version>2.0.0-SNAPSHOT</version>
</parent>

<artifactId>helidon-config-test-mp-reference</artifactId>
<name>Helidon Config Tests MP Reference</name>

<description>
Integration tests of reference in MP
</description>
<artifactId>helidon-config-mp</artifactId>
<name>Helidon Config MP</name>
<description>Core of the implementation of MicroProfile Config specification</description>

<dependencies>
<dependency>
<groupId>org.eclipse.microprofile.config</groupId>
<artifactId>microprofile-config-api</artifactId>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.common</groupId>
<artifactId>helidon-common</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.common</groupId>
<artifactId>helidon-common-service-loader</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.config</groupId>
<artifactId>helidon-config</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.eclipse.microprofile.config</groupId>
<artifactId>microprofile-config-api</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
Expand Down
80 changes: 80 additions & 0 deletions config/config-mp/src/main/java/io/helidon/config/mp/MpConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.config.mp;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import io.helidon.config.ConfigSources;

import org.eclipse.microprofile.config.Config;

/**
* Utilities for Helidon MicroProfile Config implementation.
*/
public final class MpConfig {
private MpConfig() {
}

/**
* This method allows use to use Helidon Config on top of an MP config.
* There is a limitation - the converters configured with MP config will not be available, unless
* the implementation is coming from Helidon.
* <p>
* If you want to use the Helidon {@link io.helidon.config.Config} API instead of the MicroProfile
* {@link org.eclipse.microprofile.config.Config} one, this method will create a Helidon config
* instance that is based on the provided configuration instance.
*
* @param mpConfig MP Config instance
* @return a new Helidon config using only the mpConfig as its config source
*/
@SuppressWarnings("unchecked")
public static io.helidon.config.Config toHelidonConfig(Config mpConfig) {
if (mpConfig instanceof io.helidon.config.Config) {
return (io.helidon.config.Config) mpConfig;
}

io.helidon.config.Config.Builder builder = io.helidon.config.Config.builder()
.disableEnvironmentVariablesSource()
.disableSystemPropertiesSource()
.disableMapperServices()
.disableCaching()
.disableParserServices()
.disableFilterServices();

if (mpConfig instanceof MpConfigImpl) {
((MpConfigImpl) mpConfig).converters()
.forEach((clazz, converter) -> {
Class<Object> cl = (Class<Object>) clazz;
builder.addStringMapper(cl, converter::convert);
});
}

Map<String, String> allConfig = new HashMap<>();
mpConfig.getPropertyNames()
.forEach(it -> {
// covering the condition where a config key disappears between getting the property names and requesting
// the value
Optional<String> optionalValue = mpConfig.getOptionalValue(it, String.class);
optionalValue.ifPresent(value -> allConfig.put(it, value));
});

return builder.addSource(ConfigSources.create(allConfig))
.build();
}
}
Loading

0 comments on commit 7d2f708

Please sign in to comment.