Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tree structure support (API). #21

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 71 additions & 19 deletions api/src/main/java/jakarta/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@
package jakarta.config;

import java.util.Optional;

import jakarta.config.spi.ConfigSource;
import jakarta.config.spi.Converter;
import java.util.function.Function;

/**
* Access to configuration values.
Expand All @@ -30,27 +28,81 @@
*/
public interface Config {
/**
* Return all the currently registered {@link jakarta.config.spi.ConfigSource sources} for this configuration.
* Context related to the root configuration instance.
*
* @return configuration context
*/
ConfigContext context();

/**
* Fully qualified key of this config node (such as {@code server.port}).
* Returns an empty String for root config.
*
* @return key of this config
*/
String getKey();

/**
* Name of this node - the last element of a fully qualified key.
* <p>
* The returned sources will be sorted by priority and name, which can be iterated in a thread-safe
* manner. The {@link java.lang.Iterable Iterable} contains a fixed number of {@link jakarta.config.spi.ConfigSource
* configuration
* sources}, determined at application start time, and the config sources themselves may be static or dynamic.
* For example for key {@code server.port} this method would return {@code port}.
*
* @return the configuration sources
* @return name of this node
*/
Iterable<ConfigSource> getConfigSources();
String getName();

/**
* Return the {@link jakarta.config.spi.Converter} used by this instance to produce instances of the specified type from
* string values.
* Single sub-node for the specified sub-key.
* For example if requested for key {@code server}, this method would return a config
* representing the {@code server} node, which would have for example a child {@code port}.
* The sub-key can return more than one level of nesting (e.g. using {@code server.tls} would
* return a node that contains the TLS configuration under {@code server} node).
*
* @param <T>
* the conversion type
* @param forType
* the type to be produced by the converter
* @return an {@link java.util.Optional} containing the converter, or empty if no converter is available for the specified
* type
* @param key sub-key to retrieve nested node.
* @return sub node, never null
*/
Config get(String key);

/**
* Typed value created using a converter function.
* The converter is called only if this config node exists.
*
* @param converter to create an instance from config node
* @param <T> type of the object
* @return converted value of this node, or an empty optional if this node does not exist
* @throws java.lang.IllegalArgumentException if this config node cannot be converted to the desired type
*/
<T> Optional<T> as(Function<Config, T> converter);

/**
* Typed value created using a discovered/built-in converter.
*
* @param type class to convert to
* @param <T> type of the object
* @return converted value of this node, or an empty optional if this node does not exist
* @throws java.lang.IllegalArgumentException if this config node cannot be converted to the desired type
*/
<T> Optional<T> as(Class<T> type);

/**
* Direct value of this node used for string converters.
*
* @return value of this node
*/
Optional<String> asString();

/**
* Config value associated with this tree node (if any).
* If this node represents a value obtained from a config source, this method must return a non-empty value.
*
* @return config value of this node, or empty if this node does not represent a direct value
*/
Optional<ConfigValue> getConfigValue();

/*
* Shortcut helper methods
*/
<T> Optional<Converter<T>> getConverter(Class<T> forType);
default Optional<Integer> asInt() {
return as(Integer.class);
}
}
71 changes: 71 additions & 0 deletions api/src/main/java/jakarta/config/ConfigContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2021 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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 jakarta.config;

import java.util.Optional;

import jakarta.config.spi.ConfigSource;
import jakarta.config.spi.Converter;
import jakarta.config.spi.StringConverter;

/**
* Metadata related to a config instance.
*
* @author <a href="mailto:[email protected]">Tomáš Langer</a>
*/
public interface ConfigContext {
/**
* Return all the currently registered {@link jakarta.config.spi.ConfigSource sources} for this configuration.
* <p>
* The returned sources will be sorted by priority and name, which can be iterated in a thread-safe
* manner. The {@link java.lang.Iterable Iterable} contains a fixed number of {@link jakarta.config.spi.ConfigSource
* configuration
* sources}, determined at application start time, and the config sources themselves may be static or dynamic.
*
* @return the configuration sources
*/
Iterable<ConfigSource> getConfigSources();

/**
* Return the {@link jakarta.config.spi.Converter} used by this instance to produce instances of the specified type from
* string values.
*
* @param <T>
* the conversion type
* @param forType
* the type to be produced by the converter
* @return an {@link java.util.Optional} containing the converter, or empty if no converter is available for the specified
* type
*/
<T> Optional<Converter<T>> getConverter(Class<T> forType);

/**
* Return the {@link jakarta.config.spi.StringConverter} used by this instance to produce instances of the specified type from
* string values.
* This is a helper method to provide simple conversions (such as from a default value of an annotation).
*
* @param <T>
* the conversion type
* @param forType
* the type to be produced by the converter
* @return an {@link java.util.Optional} containing the converter, or empty if no converter is available for the specified
* type
*/
<T> Optional<StringConverter<T>> getStringConverter(Class<T> forType);
}
2 changes: 1 addition & 1 deletion api/src/main/java/jakarta/config/ConfigProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public static Config getConfig() {
* <p>
* Each class loader corresponds to exactly one configuration.
*
* @param cl
* @param loader
* the Classloader used to register the configuration instance
* @return the configuration instance for the given class loader
*/
Expand Down
60 changes: 60 additions & 0 deletions api/src/main/java/jakarta/config/ConfigValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2021 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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 jakarta.config;

/**
* The ConfigValue holds additional information after the lookup of a configuration property and is itself immutable.
* <p>
* Holds information about the configuration property name, configuration value, the
* {@link jakarta.config.spi.ConfigSource} name from where the configuration property was loaded and
* the ordinal of the {@link jakarta.config.spi.ConfigSource}.
* <p>
* This is used together with {@link Config} to expose the configuration property lookup metadata.
*
* @author <a href="mailto:[email protected]">Roberto Cortez</a>
*/
public interface ConfigValue {
/**
* The key of the property.
*
* @return the name of the property.
*/
String getKey();

/**
* The value of the property lookup with transformations (expanded, etc).
*
* @return the value of the property lookup
*/
String getValue();

/**
* The value of the property lookup without any transformation (expanded , etc).
*
* @return the raw value of the property lookup
*/
String getRawValue();

/**
* The {@link jakarta.config.spi.ConfigSource} name that loaded the property lookup.
*
* @return the ConfigSource name that loaded the property lookup
*/
String getSourceName();
}
43 changes: 42 additions & 1 deletion api/src/main/java/jakarta/config/spi/ConfigSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,29 @@
*/
package jakarta.config.spi;

import java.util.Set;

/**
* A <em>configuration source</em> which provides configuration values from a specific place.
* <p>
* The underlying source is abstracted by this SPI to provide unified access for any source type.
* The following rules must be honored by all config sources:
* <ul>
* <li>The configuration key points to a specific {@code leaf} value, if a key is resolved into a tree node that is
* not a leaf value, it should be considered as not found</li>
* <li>Keys use a dot ({@code .}) separator notation - each dot MAY be a tree node separator</li>
* <li>Values are always returned as {@link java.lang.String}, see {@link jakarta.config.spi.Converter} specification
* on how to handle conversion to String (the result must be convertible to appropriate types using built-in converters)</li>
* </ul>
*
* TODO: This javadoc must be expanded once the API is clarified
* <b>Examples of dot notation</b>
* <p>
* {@code server.host}:
* <ul>
* <li>In flat config sources (flat config source is a map of keys to values), the key is {@code server.host}</li>
* <li>In tree config sources, this would be resolved to node {@code host} first, and then to child node {@code port}
* of the {@code host} node, or to an exact match {@code server.host}.</li>
* </ul>
*/
public interface ConfigSource {
/**
Expand All @@ -33,4 +52,26 @@ public interface ConfigSource {
* @return the name of the configuration source
*/
String getName();

/**
* Return the value for the specified key in this configuration source.
*
* @param key
* the property key
* @return the property value, or {@code null} if the property is not present
*/
String getValue(String key);

/**
* Gets all property keys known to this configuration source, potentially without evaluating the values. The
* returned property keys may be a subset of the keys of the total set of retrievable properties in this config
* source.
* <p>
* The returned set is not required to allow concurrent or multi-threaded iteration; however, if the same set is
* returned by multiple calls to this method, then the implementation must support concurrent and multi-threaded
* iteration of that set.
*
* @return a set of property keys that are known to this configuration source
*/
Set<String> getKeys();
}
12 changes: 7 additions & 5 deletions api/src/main/java/jakarta/config/spi/Converter.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*/
package jakarta.config.spi;

import jakarta.config.Config;

/**
* A mechanism for converting configured values from {@link String} to any Java type.
*
Expand Down Expand Up @@ -129,16 +131,16 @@
*/
public interface Converter<T> {
/**
* Convert the given string value to a specified type. Callers <em>must not</em> pass in {@code null} for
* Convert the given config node to a specified type. Callers <em>must not</em> pass in {@code null} for
* {@code value}; doing so may result in a {@code NullPointerException} being thrown.
*
* @param value
* the string representation of a property value (must not be {@code null})
* @return the converted value, or {@code null} if the value is empty
* @param node
* the config node to convert (must not be {@code null})
* @return the converted value, may be {@code null} to represent a missing value
* @throws IllegalArgumentException
* if the value cannot be converted to the specified type
* @throws NullPointerException
* if the given value was {@code null}
*/
T convert(String value) throws IllegalArgumentException, NullPointerException;
T convert(Config node) throws IllegalArgumentException, NullPointerException;
}
55 changes: 55 additions & 0 deletions api/src/main/java/jakarta/config/spi/StringConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2021 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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 jakarta.config.spi;

import jakarta.config.Config;

/**
* A mechanism for converting configured values from {@link String} to any Java type.
*
* This is a helper interface to support direct {@link String} conversion, for a generic
* conversion from nodes, please see {@link jakarta.config.spi.Converter}.
*
* @author <a href="mailto:[email protected]">Ron Smeral</a>
* @author <a href="mailto:[email protected]">Mark Struberg</a>
* @author <a href="mailto:[email protected]">Emily Jiang</a>
* @author <a href="mailto:[email protected]">John D. Ament</a>
*/
public interface StringConverter<T> extends Converter<T> {
/**
* Convert the given string value to a specified type. Callers <em>must not</em> pass in {@code null} for
* {@code value}; doing so may result in a {@code NullPointerException} being thrown.
*
* @param value
* the string representation of a property value (must not be {@code null})
* @return the converted value, or {@code null} if the value is empty
* @throws IllegalArgumentException
* if the value cannot be converted to the specified type
* @throws NullPointerException
* if the given value was {@code null}
*/
T convert(String value) throws IllegalArgumentException, NullPointerException;

@Override
default T convert(Config node) throws IllegalArgumentException, NullPointerException {
return node.asString()
.map(this::convert)
.orElse(null);
}
}
Loading