diff --git a/.travis.yml.disabled b/.travis.yml.disabled new file mode 100644 index 0000000..dff5f3a --- /dev/null +++ b/.travis.yml.disabled @@ -0,0 +1 @@ +language: java diff --git a/NOTICE b/NOTICE index 27e30dd..231dcfe 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,4 @@ -Apache Geronimo Configuration -Copyright 2016 The Apache Software Foundation +Copyright 2009-2017 Mark Struberg This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). +The Apache Software Foundation (http://www.apache.org/). \ No newline at end of file diff --git a/README.adoc b/README.adoc index 30bd075..e346ca3 100644 --- a/README.adoc +++ b/README.adoc @@ -1,46 +1,46 @@ -# Configuration for Java SE and EE JSR +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You 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. +// + +# Configuration for Java SE and EE ## Status -JSR proposal! +The content of this repository is OUTDATED! -== Rational +Please go to the Apache Geronimo Config project for further information. -Many project artifacts (e.g. WAR, EAR) should only be created once and then get installed at different customers, stages, etc -They need to target those different execution environments without necessity of any repackaging. -In other words: depending on the situation they need different configuration. - -This is easily achievable by having a set of default configuration values inside the project artifact. -But be able to overwrite those default values from external. +$> svn co https://svn.apache.org/repos/asf/geronimo/components/config/trunk == History -This very configuration approach has it's roots in the Apache OpenWebBeans internal SPI configuration. -In 2010 it got moved over to the Apache MyFaces CODI project and enhanced to also fit the need of customer projects by Gerhard Petracek and Mark Struberg. -In 2012 we further enhanced it while moving CODI to the Apache DeltaSpike project. - -== How it works - -A 'Configuration' consists of the information collected from the registered `javax.config.spi.ConfigSource` s. -These `ConfigSource`s get sorted according to their _ordinal_. -That way it is possible to overwrite configuration with lower importance from outside. - -By default there are 3 default ConfigSources: +This repository contains the original MicroProfile Config proposal and a Config JSR proposal based on the concepts Gerhard and I created in Apache OpenWebBeans, CODI and DeltaSpike. +See the separate branches for more info. -* `System.getenv()` (ordinal=400) -* `System.getProperties()` (ordinal=300) -* all `META-INF/java-config.properties` files on the ClassPath. (ordinal=100, separately configurable via a config_ordinal property inside each file) +== The Config API -That means that I can put my default configuration in a `META-INF/java-config.properties` anywhere on the classpath. -And I can later simply e.g set a system property to change this default configuration. +The API later got moved to the MicroProfile repository which itself later moved under the Eclipse umbrella. +It now can be found at -== Custom ConfigSources +https://github.com/eclipse/microprofile-config/ -It is possible to write and register custom `ConfigSource` s. -An example would be a ConfigSource which gets the configured values from a shared database table in a cluster. -== Building +== The Config IMPL -`$> mvn clean install` +The implementation of MicroProfile Config can be found at the Apache Geronimo Project. -After that the specification PDF can be found in `spec/target/generated-docs/config-spec.pdf` \ No newline at end of file +$> svn co https://svn.apache.org/repos/asf/geronimo/components/config/trunk + diff --git a/api/pom.xml b/api/pom.xml deleted file mode 100644 index 8dd1fe7..0000000 --- a/api/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - 4.0.0 - - - - org.apache.geronimo.config - config-parent - 0.1-SNAPSHOT - - - org.apache.geronimo.config - config-api - - - - org.apache.geronimo.specs - geronimo-annotation_1.2_spec - 1.0 - provided - - - diff --git a/api/src/main/java/javx/config/Config.java b/api/src/main/java/javx/config/Config.java deleted file mode 100644 index 5795970..0000000 --- a/api/src/main/java/javx/config/Config.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 javx.config; - -import java.util.List; -import java.util.Map; - -import javx.config.spi.ConfigFilter; -import javx.config.spi.ConfigSource; -import javx.config.spi.ConfigSourceProvider; -import javx.config.spi.Converter; - -/** - *

Resolves configured values of properties by going through the list - * of configured {@link ConfigSource}s and using the one with the highest ordinal. - * If multiple {@link ConfigSource}s have the same ordinal, their order is undefined.

- * - *

You can provide your own lookup paths by implementing and registering additional - * {@link ConfigSource}s and {@link ConfigSourceProvider} implementations.

- * - *

A configured value can be accessed with {@link #getValue(String)}.

- * - *

For accessing a coniguration in a dynamic way you can also use {@link #access(String)}. - * This method returns a builder-style {@link ConfigValue} instance for the given key. - * You can further specify a Type of the underlying configuration, a cache time, lookup paths and - * many more. - *

- * - * @author Mark Struberg - */ -public interface Config { - - /** - * Resolves the value configured for the given key. - * - * @param key the property key - * - * @return the configured property value from the {@link ConfigSource} with the highest ordinal - * or {@code null} if there is no configured value for it - */ - String getValue(String key); - - /** - * Create a {@link ConfigValue} to access the underlying configuration. - * - * @param key the property key - */ - ConfigValue access(String key); - - /** - * Returns a Map of all properties from all scannable config sources. The values of the properties reflect the - * values that would be obtained by a call to {@link #getValue(java.lang.String)}, that is, the value of the - * property from the ConfigSource with the highest ordinal. - * - * @see ConfigSource#isScannable() - */ - Map getAllProperties(); - - /** - * Filter the configured value. - * This can e.g. be used for decryption. - * @return the filtered value - */ - String filterConfigValue(String key, String value); - - /** - * Filter the configured value for logging. - * This can e.g. be used for displaying ***** instead of a real password. - * @return the filtered value - */ - String filterConfigValueForLog(String key, String value); - - /** - * This method might be useful for debugging purpose or to - * show the values of all ConfigSources in an admin page. - * - * @return all currently registered {@link ConfigSource}s - */ - ConfigSource[] getConfigSources(); - - /** - * This method can be used for programmatically adding {@link ConfigSource}s - * to this very Config. - * It is not needed for normal 'usage' by end users, but only for Extension Developers! - * - * @param configSourcesToAdd the ConfigSources to add - */ - void addConfigSources(List configSourcesToAdd); - - /** - * Add a {@link ConfigFilter} to this very Config - * - * It is not needed for normal 'usage' by end users, but only for Extension Developers! - */ - void addConfigFilter(ConfigFilter configFilterToAdd); - - /** - * Add a custom {@link Converter} - * - * @param converter - */ - void addConverter(Converter converter); -} diff --git a/api/src/main/java/javx/config/ConfigProvider.java b/api/src/main/java/javx/config/ConfigProvider.java deleted file mode 100644 index 9962096..0000000 --- a/api/src/main/java/javx/config/ConfigProvider.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 javx.config; - -import java.util.ServiceLoader; -import java.util.logging.Logger; - -import javx.config.spi.ConfigFilter; -import javx.config.spi.ConfigSource; - -/** - *

This is the central class to access a {@link Config}.

- * - *

A {@link Config} contains the configuration for a certain - * situation. That might be the configuration found in a certain ClassLoader - * or even a manually created Configuration

- * - *

The default usage is to use {@link #getConfig()} to automatically - * pick up the 'Configuration' for the Thread Context ClassLoader - * (See {@link Thread#getContextClassLoader()}).

- * - *

A 'Configuration' consists of the information collected from the registered - * {@link ConfigSource}s. These {@link ConfigSource}s - * get sorted according to their ordinal defined via {@link ConfigSource#getOrdinal()}. - * That way it is possible to overwrite configuration with lower importance from outside.

- * - *

It is also possible to register custom {@link ConfigSource}s to - * flexibly extend the configuration mechanism. An example would be to pick up configuration values - * from a database table./p> - * - * @author Mark Struberg - */ -public class ConfigProvider { - - private static final SPI instance = loadSpi(); - - /** - * Provide a {@link Config} based on all {@link ConfigSource}s - * of the current Thread Context ClassLoader (TCCL) - * - *

There is exactly a single Config instance per ClassLoader

- */ - public static Config getConfig() { - return instance.getConfig(); - } - - /** - * Provide a {@link Config} based on all {@link ConfigSource}s - * of the given ClassLoader. - * - *

There is exactly a single Config instance per ClassLoader

- */ - public static Config getConfig(ClassLoader forClassLoader) { - return instance.getConfig(forClassLoader); - } - - /** - * Create a fresh {@link Config} instance. - * This Config will initially contain no - * {@link ConfigSource} nor any {@link ConfigFilter}. - * Those have to be added manually. - * - * The ConfigProvider will not manage the Config instance internally - */ - public static Config newConfig() { - return instance.newConfig(); - } - - /** - * A {@link Config} normally gets released if the ClassLoader it represents gets destroyed. - * Invoke this method if you like to destroy the Config prematurely. - */ - public static void releaseConfig(Config config) { - instance.releaseConfig(config); - } - - - /** - * This interface gets implemented internally by the Config library. - * The implementation registers itself via {@link java.util.ServiceLoader} mechanism. - */ - public interface SPI { - Config getConfig(); - Config getConfig(ClassLoader forClassLoader); - Config newConfig(); - void releaseConfig(Config config); - } - - private static SPI loadSpi() { - ServiceLoader sl = ServiceLoader.load(SPI.class); - SPI instance = null; - for (SPI spi : sl) { - if (instance != null) { - Logger.getLogger(ConfigProvider.class.getName()).warning("Multiple ConfigResolver SPIs found. Ignoring " + spi.getClass().getName()); - } - else { - instance = spi; - } - } - if (instance == null) { - throw new IllegalStateException("No ConfigResolver SPI implementation found!"); - } - return instance; - } - - -} diff --git a/api/src/main/java/javx/config/ConfigValue.java b/api/src/main/java/javx/config/ConfigValue.java deleted file mode 100644 index 5661fed..0000000 --- a/api/src/main/java/javx/config/ConfigValue.java +++ /dev/null @@ -1,113 +0,0 @@ -package javx.config; - -import java.util.concurrent.TimeUnit; - -/** - * Accessor to a configured value. - * It follows a builder pattern. - * - * Accessing the configured value is finally done via {@link #getValue()} - * - * @author Mark Struberg - * @author Gerhard Petracek - * @author Ron Smeral - */ -public interface ConfigValue { - - /** - * Sets the type of the configuration entry to the given class and returns this builder. - * The default type of a ConfigValue is {@code String}. - * - * @param clazz The target type - * @param The target type - * @return This builder as a typed ConfigValue - */ - ConfigValue as(Class clazz); - - /** - * Sets the default value to use in case the resolution returns null. - * @param value the default value - * @return This builder - */ - ConfigValue withDefault(T value); - - /** - * Sets the default value to use in case the resolution returns null. Converts the given String to the type of - * this resolver using the same method as used for the configuration entries. - * @param value string value to be converted and used as default - * @return This builder - */ - ConfigValue withStringDefault(String value); - - /** - * Specify that a resolved value will get cached for a certain amount of time. - * After the time expires the next {@link #getValue()} will again resolve the value - * from the underlying {@link Config}. - * - * @param value the amount of the TimeUnit to wait - * @param timeUnit the TimeUnit for the value - * - * @return This builder - */ - ConfigValue cacheFor(long value, TimeUnit timeUnit); - - /** - * Whether to evaluate variables in configured values. - * A variable starts with '${' and ends with '}', e.g. - *
-     * mycompany.some.url=${myserver.host}/some/path
-     * myserver.host=http://localhost:8081
-     * 
- * If 'evaluateVariables' is enabled, the result for the above key - * {@code "mycompany.some.url"} would be: - * {@code "http://localhost:8081/some/path"} - * @param evaluateVariables whether to evaluate variables in values or not - * @return This builder - */ - ConfigValue evaluateVariables(boolean evaluateVariables); - - /** - * Appends the resolved value of the given property to the key of this builder. - * TODO further explain. - * @return This builder - */ - ConfigValue withLookupChain(String... postfixNames); - - /** - * Whether to log picking up any value changes as INFO. - * - * @return This builder - */ - ConfigValue logChanges(boolean logChanges); - - /** - * Returns the converted resolved filtered value. - * @return the resolved value - */ - T getValue(); - - /** - * Returns the key given in {@link Config#access(String)}. - * @return the original key - */ - String getKey(); - - /** - * Returns the actual key which led to successful resolution and corresponds to the resolved value. This applies - * only when {@link #withLookupChain(String...)} is used. - * Otherwise the resolved key should always be equal to the original key. - * This method is provided for cases, when arameterized resolution is - * requested but the value for such appended key is not found and some of the fallback keys is used. - * - * This should be called only after calling {@link #getValue()} otherwise the value is undefined (but likely - * null). - */ - String getResolvedKey(); - - /** - * Returns the default value provided by {@link #withDefault(Object)} or {@link #withStringDefault(String)}. - * Returns null if no default was provided. - * @return the default value or {@code null} - */ - T getDefaultValue(); -} diff --git a/api/src/main/java/javx/config/spi/ConfigFilter.java b/api/src/main/java/javx/config/spi/ConfigFilter.java deleted file mode 100644 index 0e01b51..0000000 --- a/api/src/main/java/javx/config/spi/ConfigFilter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 javx.config.spi; - -import javx.config.Config; - -/** - *

A filter which can be added to the - * {@link Config}. - * The filter can be used to decrypt config values or prepare - * values for logging.

- * - *

Registering a {@code ConfigFilter} can either be done via the - * {@code java.util.ServiceLoader} pattern or by manually adding it via - * {@link Config#addConfigFilter(ConfigFilter)}.

- * - * @author Mark Struberg - */ -public interface ConfigFilter -{ - /** - * Filter the given configuration value - * @param key - * @param value - * @return the filtered value or the original input String if no filter shall be applied - */ - String filterValue(String key, String value); - - /** - * Filter the given configuration value for usage in logs. - * This might be used to mask out passwords, etc. - * @param key - * @param value - * @return the filtered value or the original input String if no filter shall be applied - */ - String filterValueForLog(String key, String value); -} diff --git a/api/src/main/java/javx/config/spi/ConfigSource.java b/api/src/main/java/javx/config/spi/ConfigSource.java deleted file mode 100644 index 254d796..0000000 --- a/api/src/main/java/javx/config/spi/ConfigSource.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 javx.config.spi; - -import java.util.Map; - -/** - *

Implement this interfaces to provide a ConfigSource. - * A ConfigSource provides properties from a specific place, like - * JNDI configuration, a properties file, etc. - * A ConfigSource is always read-only, any potential updates of the - * configured values must be handled directly inside each ConfigSource.

- * - *

The custom implementation can be 'registered' using a - * {@link ConfigSourceProvider} or via the - * {@link java.util.ServiceLoader} mechanism. In the later case - * it must get registered via creating a - * META-INF/services/javax.config.spi.ConfigSource - * file and adding the fully qualified class name of your ConfigSource - * implementation into it.

- * - * @author Mark Struberg - * @author Gerhard Petracek - */ -public interface ConfigSource { - /** - * The default name for the ordinal field. - * Any ConfigSource might use it's own though or even return a hardcoded - * in {@link #getOrdinal()}. - */ - String CONFIG_ORDINAL = "config_ordinal"; - - - /** - * Lookup order: - * - *
    - *
  1. System properties (ordinal 400)
  2. - *
  3. Environment properties (ordinal 300)
  4. - *
  5. JNDI values (ordinal 200)
  6. - *
  7. Properties file values (/META-INF/java-config.properties) (ordinal 100)
  8. - *
- *

- *

Important Hints for custom implementations:

- *

- * If a custom implementation should be invoked before the default implementations, use a value > 400 - *

- *

- * If a custom implementation should be invoked after the default implementations, use a value < 100 - *

- *

- * - * - *

- *

- *

Reordering of the default order of the config-sources:

- *

Example: If the properties file/s should be used before the other implementations, - * you have to configure an ordinal > 400. That means, you have to add e.g. config_ordinal=401 to - * /META-INF/java-config.properties . Hint: In case of property files every file is handled as independent - * config-source, but all of them have ordinal 400 by default (and can be reordered in a fine-grained manner.

- * - * @return the 'importance' aka ordinal of the configured values. The higher, the more important. - */ - int getOrdinal(); - - /** - * Return properties contained in this config source. - * @return Properties available in this config source. - */ - Map getProperties(); - - /** - * @param key for the property - * @return configured value or null if this ConfigSource doesn't provide any value for the given key. - */ - String getPropertyValue(String key); - - /** - * The name of the config might be used for logging or analysis of configured values. - * - * @return the 'name' of the configuration source, e.g. 'property-file mylocation/myproperty.properties' - */ - String getConfigName(); - - /** - * Determines if this config source should be scanned for its list of properties. - * - * Generally, slow ConfigSources should return {@code false} here. - * - * @return {@code true} if this ConfigSource should be scanned for its list of properties, - * {@code false} if it should not be scanned. - */ - boolean isScannable(); -} diff --git a/api/src/main/java/javx/config/spi/ConfigSourceProvider.java b/api/src/main/java/javx/config/spi/ConfigSourceProvider.java deleted file mode 100644 index b3f3a46..0000000 --- a/api/src/main/java/javx/config/spi/ConfigSourceProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 javx.config.spi; - -import java.util.List; - -/** - *

Implement this interfaces to provide a ConfigSource provider which - * is able to maintain multiple ConfigSources. This is e.g. needed if - * there are multiple property files of a given name.

- * - *

If a ConfigSource like JNDI only exists once, then there is no need - * to implement it via the ConfigSourceProvider but should directly - * expose a {@link ConfigSource}.

- * - *

A ConfigSourceProvider will get picked up via the - * {@link java.util.ServiceLoader} mechanism and must get registered via - * META-INF/services/javax.config.spi.ConfigSourceProvider

- * - * @author Mark Struberg - */ -public interface ConfigSourceProvider -{ - - /** - * @param forClassLoader the classloader which should be used if any is needed - * - * @return For each e.g. property file, we return a single ConfigSource or an empty list if no ConfigSource exists. - */ - List getConfigSources(ClassLoader forClassLoader); -} diff --git a/api/src/main/java/javx/config/spi/Converter.java b/api/src/main/java/javx/config/spi/Converter.java deleted file mode 100644 index 9bac50c..0000000 --- a/api/src/main/java/javx/config/spi/Converter.java +++ /dev/null @@ -1,34 +0,0 @@ -package javx.config.spi; - -/** - *

A very simple interface for conversion of configuration values from String to any Java type.

- * - *

A Converter can specify a {@link javax.annotation.Priority}. - * If no priority is explicitly assigned, the value of 100 is assumed.

- * - *

If multiple Converter get found the one with the highest priority will be used.

- * - *

The Converter for the following types are automatically enabled: - *

    - *
  • Boolean, values for {@code true}: (case insensitive) "true", "1", "YES", "Y" "JA" "J", "OUI"
  • - *
  • Integer
  • - *
  • Long
  • - *
  • Float, a dot '.' is used to separate the fractional digits
  • - *
  • Double, a dot '.' is used to separate the fractional digits - *
- * - *

- * - * @author Mark Struberg - * @author Ron Smeral - * @author Gerhard Petracek - */ -public interface Converter { - /** - * Returns the converted value of the configuration entry. - * @param value The String property value to convert - * @return Converted value - */ - T convert(String value); - -} diff --git a/api/src/main/java/javx/config/spi/PropertyFileConfig.java b/api/src/main/java/javx/config/spi/PropertyFileConfig.java deleted file mode 100644 index 2fdf996..0000000 --- a/api/src/main/java/javx/config/spi/PropertyFileConfig.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 javx.config.spi; - -/** - *

- * If you implement this interface, the property files with the given file name will be registered as - * {@link ConfigSource}s.

- * - ** - *

Automatic pickup via {@code java.util.ServiceLoader} mechanism

- *

You need to register the PropertyFileConfig via the {@code java.util.ServiceLoader} mechanism. - * - *

The {@code ServiceLoader} mechanism requires to have a file - *

- *     META-INF/services/javax.config.spi.PropertyFileConfig
- * 
- * containing the fully qualified Class name of your own {@code PropertyFileConfig} implementation class. - *
- *     com.acme.my.own.SomeSpecialPropertyFileConfig
- * 
- * The implementation will look like the following: - *
- *     public class SomeSpecialPropertyFileConfig implements PropertyFileConfig {
- *         public String getPropertyFileName() {
- *             return "myconfig/specialconfig.properties"
- *         }
- *
- *         public boolean isOptional() {
- *             return false;
- *         }
- *     }
- * 
- *

- * - */ -public interface PropertyFileConfig -{ - /** - * All the property files on the classpath which have this name will get picked up and registered as - * {@link ConfigSource}s. - * - * @return the full file name (including path) of the property files to pick up. - */ - String getPropertyFileName(); - - /** - * @return true if the file is optional, false if the specified file has to be in place. - */ - boolean isOptional(); -} diff --git a/impl/debug-suite.xml b/impl/debug-suite.xml index 65957e2..b121bee 100644 --- a/impl/debug-suite.xml +++ b/impl/debug-suite.xml @@ -24,7 +24,7 @@ - + diff --git a/impl/pom.xml b/impl/pom.xml index 69d8a7c..f67ec8a 100644 --- a/impl/pom.xml +++ b/impl/pom.xml @@ -30,17 +30,34 @@ org.apache.geronimo.config config-impl + + 1.1.13.Final + + + + + + org.jboss.arquillian + arquillian-bom + ${arquillian.version} + pom + import + + + + + - org.apache.geronimo.config - config-api - 0.1-SNAPSHOT + org.eclipse.microprofile.apis + microprofile-config_1.0_api + 1.0-SNAPSHOT - org.apache.geronimo.config - config-tck - 0.1-SNAPSHOT + org.eclipse.microprofile.config.tck + microprofile-config-tck + 1.0-SNAPSHOT test @@ -57,6 +74,15 @@ provided + + org.jboss.arquillian.testng + arquillian-testng-container + ${arquillian.version} + test + + + + @@ -73,4 +99,65 @@ + + + + OWB + + true + + + + 1.7.3-SNAPSHOT + + + + + org.apache.geronimo.specs + geronimo-atinject_1.0_spec + 1.0 + provided + + + org.apache.geronimo.specs + geronimo-jcdi_1.1_spec + 1.0 + provided + + + org.apache.geronimo.specs + geronimo-interceptor_1.2_spec + 1.0 + provided + + + org.apache.geronimo.specs + geronimo-el_2.2_spec + 1.0.2 + provided + + + + org.apache.openwebbeans + openwebbeans-spi + ${owb.version} + test + + + org.apache.openwebbeans + openwebbeans-impl + ${owb.version} + test + + + org.apache.openwebbeans.arquillian + owb-arquillian-standalone + ${owb.version} + test + + + + + + diff --git a/impl/src/main/java/org/apache/geronimo/config/ConfigImpl.java b/impl/src/main/java/org/apache/geronimo/config/ConfigImpl.java index ed56aa3..f2ab338 100644 --- a/impl/src/main/java/org/apache/geronimo/config/ConfigImpl.java +++ b/impl/src/main/java/org/apache/geronimo/config/ConfigImpl.java @@ -18,21 +18,31 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; -import javx.config.Config; -import javx.config.ConfigValue; -import javx.config.spi.ConfigFilter; -import javx.config.spi.ConfigSource; -import javx.config.spi.Converter; +import org.apache.geronimo.config.converters.DurationConverter; +import org.apache.geronimo.config.converters.LocalDateConverter; +import org.apache.geronimo.config.converters.LocalDateTimeConverter; +import org.apache.geronimo.config.converters.LocalTimeConverter; +import org.apache.geronimo.config.converters.StringConverter; +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.spi.ConfigSource; +import org.eclipse.microprofile.config.spi.Converter; import org.apache.geronimo.config.converters.BooleanConverter; import org.apache.geronimo.config.converters.DoubleConverter; import org.apache.geronimo.config.converters.FloatConverter; @@ -40,15 +50,18 @@ import org.apache.geronimo.config.converters.LongConverter; import javax.annotation.Priority; +import javax.enterprise.inject.Typed; +import javax.enterprise.inject.Vetoed; /** * @author Mark Struberg */ +@Typed +@Vetoed public class ConfigImpl implements Config { protected Logger logger = Logger.getLogger(ConfigImpl.class.getName()); - protected ConfigSource[] configSources = new ConfigSource[0]; - protected List configFilters = new ArrayList<>(); + protected List configSources = new ArrayList<>(); protected Map converters = new HashMap<>(); @@ -57,96 +70,105 @@ public ConfigImpl() { } private void registerDefaultConverter() { + converters.put(String.class, StringConverter.INSTANCE); converters.put(Boolean.class, BooleanConverter.INSTANCE); converters.put(Double.class, DoubleConverter.INSTANCE); converters.put(Float.class, FloatConverter.INSTANCE); converters.put(Integer.class, IntegerConverter.INSTANCE); converters.put(Long.class, LongConverter.INSTANCE); + + converters.put(Duration.class, DurationConverter.INSTANCE); + converters.put(LocalTime.class, LocalTimeConverter.INSTANCE); + converters.put(LocalDate.class, LocalDateConverter.INSTANCE); + converters.put(LocalDateTime.class, LocalDateTimeConverter.INSTANCE); } + @Override + public Optional getOptionalValue(String propertyName, Class asType) { + String value = getValue(propertyName); + if (value != null && value.length() == 0) { + // treat an empty string as not existing + value = null; + } + return Optional.ofNullable(convert(value, asType)); + } + + @Override + public T getValue(String propertyName, Class propertyType) { + String value = getValue(propertyName); + if (value == null || value.length() == 0) { + throw new NoSuchElementException("No configured value found for config key " + propertyName); + } + + return convert(value, propertyType); + } + public String getValue(String key) { for (ConfigSource configSource : configSources) { - String value = configSource.getPropertyValue(key); + String value = configSource.getValue(key); if (value != null) { if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "found value {0} for key {1} in ConfigSource {2}.", - new Object[]{filterConfigValueForLog(key, value), key, configSource.getConfigName()}); + new Object[]{value, key, configSource.getName()}); } - return filterConfigValue(key, value); + return value; } } - return null; - } - @Override - public ConfigValue access(String key) { - return new ConfigValueImpl<>(this, key); + return null; } - @Override - public Map getAllProperties() { - Map result = new HashMap(); - - for (int i = configSources.length; i > 0; i--) { - ConfigSource configSource = configSources[i]; - if (configSource.isScannable()) { - result.putAll(configSource.getProperties()); - } + public T convert(String value, Class asType) { + if (value != null) { + Converter converter = getConverter(asType); + return converter.convert(value); } - // now filter them - for (Map.Entry entries : result.entrySet()) { - entries.setValue(filterConfigValue(entries.getKey(), entries.getValue())); + return null; + } + + private Converter getConverter(Class asType) { + Converter converter = converters.get(asType); + if (converter == null) { + throw new UnsupportedOperationException("No Converter registered for class " + asType); } + return converter; + } - return Collections.unmodifiableMap(result); + public ConfigValueImpl access(String key) { + return new ConfigValueImpl(this, key); } @Override - public String filterConfigValue(String key, String value) { - String filteredValue = value; + public Iterable getPropertyNames() { + Set result = new HashSet<>(); + + for (ConfigSource configSource : configSources) { + result.addAll(configSource.getProperties().keySet()); - for (ConfigFilter filter : configFilters) { - filteredValue = filter.filterValue(key, filteredValue); } - return filteredValue; + return result; } - @Override - public String filterConfigValueForLog(String key, String value) { - String logValue = value; - for (ConfigFilter filter : configFilters) { - logValue = filter.filterValueForLog(key, logValue); - } - - return logValue; - } @Override - public ConfigSource[] getConfigSources() { - return configSources; + public Iterable getConfigSources() { + return Collections.unmodifiableList(configSources); } - @Override public synchronized void addConfigSources(List configSourcesToAdd) { - List allConfigSources = new ArrayList<>(Arrays.asList(configSources)); + List allConfigSources = new ArrayList<>(configSources); allConfigSources.addAll(configSourcesToAdd); // finally put all the configSources back into the map configSources = sortDescending(allConfigSources); } - @Override - public synchronized void addConfigFilter(ConfigFilter configFilter) { - configFilters.add(configFilter); - - } - @Override public synchronized void addConverter(Converter converter) { if (converter == null) { return; @@ -178,14 +200,14 @@ public Map getConverters() { } - protected ConfigSource[] sortDescending(List configSources) { + protected List sortDescending(List configSources) { Collections.sort(configSources, new Comparator() { @Override public int compare(ConfigSource configSource1, ConfigSource configSource2) { return (configSource1.getOrdinal() > configSource2.getOrdinal()) ? -1 : 1; } }); - return configSources.toArray(new ConfigSource[configSources.size()]); + return configSources; } diff --git a/impl/src/main/java/org/apache/geronimo/config/ConfigValueImpl.java b/impl/src/main/java/org/apache/geronimo/config/ConfigValueImpl.java index 5d0fd8f..b88a0ff 100644 --- a/impl/src/main/java/org/apache/geronimo/config/ConfigValueImpl.java +++ b/impl/src/main/java/org/apache/geronimo/config/ConfigValueImpl.java @@ -1,16 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.geronimo.config; -import javx.config.ConfigValue; -import javx.config.spi.Converter; +import org.eclipse.microprofile.config.spi.Converter; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Optional; import java.util.concurrent.TimeUnit; -import java.util.logging.Level; import java.util.logging.Logger; +import javax.enterprise.inject.Typed; + /** * @author Mark Struberg */ -public class ConfigValueImpl implements ConfigValue { +@Typed +public class ConfigValueImpl { private static final Logger logger = Logger.getLogger(ConfigValueImpl.class.getName()); private final ConfigImpl config; @@ -23,78 +44,107 @@ public class ConfigValueImpl implements ConfigValue { private String[] lookupChain; - private boolean withDefault = false; - private T defaultValue; - - - private Converter converter; - private boolean evaluateVariables = false; - private boolean logChanges = false; - private long cacheTimeMs = -1; private volatile long reloadAfter = -1; private T lastValue = null; + private ConfigChanged valueChangeListener; public ConfigValueImpl(ConfigImpl config, String key) { this.config = config; this.keyOriginal = key; } - @Override - public ConfigValue as(Class clazz) { + //X @Override + public ConfigValueImpl as(Class clazz) { configEntryType = clazz; - this.converter = null; - return (ConfigValue) this; + return (ConfigValueImpl) this; } - @Override - public ConfigValue withDefault(T value) { - defaultValue = value; - withDefault = true; - return this; - } - - @Override - public ConfigValue withStringDefault(String value) { - if (value == null || value.isEmpty()) - { - throw new RuntimeException("Empty String or null supplied as string-default value for property " - + keyOriginal); - } - - defaultValue = convert(value); - withDefault = true; - return this; - } - @Override - public ConfigValue cacheFor(long value, TimeUnit timeUnit) { + //X @Override + public ConfigValueImpl cacheFor(long value, TimeUnit timeUnit) { this.cacheTimeMs = timeUnit.toMillis(value); return this; } - @Override - public ConfigValue evaluateVariables(boolean evaluateVariables) { + //X @Override + public ConfigValueImpl evaluateVariables(boolean evaluateVariables) { this.evaluateVariables = evaluateVariables; return this; } - @Override - public ConfigValue withLookupChain(String... postfixNames) { + public ConfigValueImpl withLookupChain(String... postfixNames) { this.lookupChain = postfixNames; return this; } - @Override - public ConfigValue logChanges(boolean logChanges) { - this.logChanges = logChanges; + //X @Override + public T get() { + T val = getValue(); + if (val == null) { + throw new NoSuchElementException("No config value present for key " + keyOriginal); + } + return val; + } + + //X @Override + public Optional getOptional() { + return Optional.ofNullable(getValue()); + } + + //X @Override + public ConfigValueImpl onChange(ConfigChanged valueChangeListener) { + this.valueChangeListener = valueChangeListener; return this; } - @Override + //X @Override + public List getValueList() { + String rawList = (String) getValue(false); + List values = new ArrayList(); + StringBuilder sb = new StringBuilder(64); + for (int i= 0; i < rawList.length(); i++) { + char c = rawList.charAt(i); + if ('\\' == c) { + if (i == rawList.length()) { + throw new IllegalStateException("incorrect escaping of key " + keyOriginal + " value: " + rawList); + } + char nextChar = rawList.charAt(i+1); + if (nextChar == '\\') { + sb.append('\\'); + } + else if (nextChar == ',') { + sb.append(','); + } + i++; + } + else if (',' == c) { + addListValue(values, sb); + } + else { + sb.append(c); + } + } + addListValue(values, sb); + + return values; + } + + private void addListValue(List values, StringBuilder sb) { + String val = sb.toString().trim(); + if (!val.isEmpty()) { + values.add(convert(val)); + } + sb.setLength(0); + } + public T getValue() { + return getValue(true); + } + + private T getValue(boolean convert) { long now = -1; if (cacheTimeMs > 0) { @@ -106,17 +156,11 @@ public T getValue() { } String valueStr = resolveStringValue(); - T value = convert(valueStr); - - if (withDefault) - { - value = fallbackToDefaultIfEmpty(keyResolved, value, defaultValue); - } + T value = convert ? convert(valueStr) : (T) valueStr; - if (logChanges && (value != null && !value.equals(lastValue) || (value == null && lastValue != null)) ) + if (valueChangeListener != null && (value != null && !value.equals(lastValue) || (value == null && lastValue != null)) ) { - logger.log(Level.INFO, "New value {0} for key {1}.", - new Object[]{config.filterConfigValueForLog(keyOriginal, valueStr), keyOriginal}); + valueChangeListener.onValueChange(keyOriginal, lastValue, value); } lastValue = value; @@ -149,7 +193,7 @@ private String resolveStringValue() { { break; } - String variableValue = config.access(varName).evaluateVariables(true).withLookupChain(lookupChain).getValue(); + String variableValue = config.access(varName).evaluateVariables(true).get(); if (variableValue != null) { value = value.replace("${" + varName + "}", variableValue); @@ -160,21 +204,16 @@ private String resolveStringValue() { return value; } - @Override + //X @Override public String getKey() { return keyOriginal; } - @Override + //X @Override public String getResolvedKey() { return keyResolved; } - @Override - public T getDefaultValue() { - return defaultValue; - } - private T convert(String value) { if (String.class == configEntryType) { return (T) value; @@ -188,16 +227,12 @@ private T convert(String value) { return (T) converter.convert(value); } - private T fallbackToDefaultIfEmpty(String key, T value, T defaultValue) { - if (value == null || (value instanceof String && ((String)value).isEmpty())) - { - logger.log(Level.FINE, "no configured value found for key {0}, using default value {1}.", - new Object[]{key, defaultValue}); - - return defaultValue; - } - - return value; + /** + * TODO feedback from gunnar: could be interesting to have this functionality also as Config#onChange(ConfigChanged) + * Callback which can be used with {@link #onChange(ConfigChanged)} + */ + interface ConfigChanged { + void onValueChange(String key, T oldValue, T newValue); } } diff --git a/impl/src/main/java/org/apache/geronimo/config/DefaultConfigBuilder.java b/impl/src/main/java/org/apache/geronimo/config/DefaultConfigBuilder.java new file mode 100644 index 0000000..ad56326 --- /dev/null +++ b/impl/src/main/java/org/apache/geronimo/config/DefaultConfigBuilder.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.geronimo.config; + +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.spi.ConfigBuilder; +import org.eclipse.microprofile.config.spi.ConfigSource; +import org.eclipse.microprofile.config.spi.ConfigSourceProvider; +import org.eclipse.microprofile.config.spi.Converter; +import org.apache.geronimo.config.configsource.PropertyFileConfigSourceProvider; +import org.apache.geronimo.config.configsource.SystemEnvConfigSource; +import org.apache.geronimo.config.configsource.SystemPropertyConfigSource; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.ServiceLoader; + +import javax.enterprise.inject.Typed; +import javax.enterprise.inject.Vetoed; + +import static java.util.Arrays.asList; + +/** + * @author Romain Manni-Bucau + * @author Mark Struberg + */ +@Typed +@Vetoed +public class DefaultConfigBuilder implements ConfigBuilder { + protected ClassLoader forClassLoader; + private final List sources = new ArrayList<>(); + private final List> converters = new ArrayList<>(); + private boolean ignoreDefaultSources = true; + private boolean ignoreDiscoveredSources = true; + + @Override + public ConfigBuilder addDefaultSources() { + this.ignoreDefaultSources = false; + return this; + } + + @Override + public ConfigBuilder addDiscoveredSources() { + this.ignoreDiscoveredSources = false; + return this; + } + + @Override + public ConfigBuilder forClassLoader(final ClassLoader loader) { + this.forClassLoader = loader; + return this; + } + + @Override + public ConfigBuilder withSources(final ConfigSource... sources) { + this.sources.addAll(asList(sources)); + return this; + } + + @Override + public ConfigBuilder withConverters(Converter... converters) { + this.converters.addAll(asList(converters)); + return this; + } + + @Override + public Config build() { + List configSources = new ArrayList<>(); + if (forClassLoader == null) { + forClassLoader = Thread.currentThread().getContextClassLoader(); + if (forClassLoader == null) { + forClassLoader = DefaultConfigProvider.class.getClassLoader(); + } + } + + if (!ignoreDefaultSources) { + configSources.addAll(getBuiltInConfigSources(forClassLoader)); + } + configSources.addAll(sources); + + if (!ignoreDiscoveredSources) { + // load all ConfigSource services + ServiceLoader configSourceLoader = ServiceLoader.load(ConfigSource.class, forClassLoader); + configSourceLoader.forEach(configSource -> configSources.add(configSource)); + + // load all ConfigSources from ConfigSourceProviders + ServiceLoader configSourceProviderLoader = ServiceLoader.load(ConfigSourceProvider.class, forClassLoader); + configSourceProviderLoader.forEach(configSourceProvider -> + configSourceProvider.getConfigSources(forClassLoader) + .forEach(configSource -> configSources.add(configSource))); + } + + ConfigImpl config = new ConfigImpl(); + config.addConfigSources(configSources); + + for (Converter converter : converters) { + config.addConverter(converter); + } + + return config; + } + + protected Collection getBuiltInConfigSources(ClassLoader forClassLoader) { + List configSources = new ArrayList<>(); + + configSources.add(new SystemEnvConfigSource()); + configSources.add(new SystemPropertyConfigSource()); + configSources.addAll(new PropertyFileConfigSourceProvider("/META-INF/microprofile-config.properties", true, forClassLoader).getConfigSources(forClassLoader)); + + return configSources; + } +} diff --git a/impl/src/main/java/org/apache/geronimo/config/DefaultConfigProvider.java b/impl/src/main/java/org/apache/geronimo/config/DefaultConfigProvider.java index a2ce39e..d70b9d2 100644 --- a/impl/src/main/java/org/apache/geronimo/config/DefaultConfigProvider.java +++ b/impl/src/main/java/org/apache/geronimo/config/DefaultConfigProvider.java @@ -17,46 +17,36 @@ package org.apache.geronimo.config; import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.Iterator; -import java.util.List; import java.util.Map; -import java.util.ServiceLoader; import java.util.WeakHashMap; -import javx.config.Config; -import javx.config.ConfigProvider; -import javx.config.spi.ConfigFilter; -import javx.config.spi.ConfigSource; -import javx.config.spi.ConfigSourceProvider; -import javx.config.spi.Converter; -import javx.config.spi.PropertyFileConfig; +import javax.enterprise.inject.Typed; +import javax.enterprise.inject.Vetoed; -import org.apache.geronimo.config.configsource.PropertyFileConfigSourceProvider; -import org.apache.geronimo.config.configsource.SystemEnvConfigSource; -import org.apache.geronimo.config.configsource.SystemPropertyConfigSource; +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.spi.ConfigBuilder; +import org.eclipse.microprofile.config.spi.ConfigProviderResolver; /** * @author Mark Struberg */ -public class DefaultConfigProvider implements ConfigProvider.SPI { +@Typed +@Vetoed +public class DefaultConfigProvider extends ConfigProviderResolver { - protected static Map> configs + private static Map> configs = Collections.synchronizedMap(new WeakHashMap>()); @Override public Config getConfig() { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - if (cl == null) { - cl = DefaultConfigProvider.class.getClassLoader(); - } - return getConfig(cl); + return getConfig(null); } + @Override public Config getConfig(ClassLoader forClassLoader) { @@ -65,7 +55,7 @@ public Config getConfig(ClassLoader forClassLoader) { synchronized (DefaultConfigProvider.class) { config = existingConfig(forClassLoader); if (config == null) { - config = createConfig(forClassLoader); + config = getBuilder().forClassLoader(forClassLoader).addDefaultSources().addDiscoveredSources().build(); registerConfig(config, forClassLoader); } } @@ -73,87 +63,47 @@ public Config getConfig(ClassLoader forClassLoader) { return config; } - private Config existingConfig(ClassLoader forClassLoader) { + Config existingConfig(ClassLoader forClassLoader) { WeakReference configRef = configs.get(forClassLoader); return configRef != null ? configRef.get() : null; } - protected Config createConfig(ClassLoader forClassLoader) { - ConfigImpl config = new ConfigImpl(); - - List configSources = new ArrayList<>(); - - configSources.addAll(getBuiltInConfigSources(forClassLoader)); - - - // load all ConfigSource services - ServiceLoader configSourceLoader = ServiceLoader.load(ConfigSource.class, forClassLoader); - for (ConfigSource configSource : configSourceLoader) { - configSources.add(configSource); - } - - // load all ConfigSources from ConfigSourceProviders - ServiceLoader configSourceProviderLoader = ServiceLoader.load(ConfigSourceProvider.class, forClassLoader); - for (ConfigSourceProvider configSourceProvider : configSourceProviderLoader) { - configSources.addAll(configSourceProvider.getConfigSources(forClassLoader)); - } - - config.addConfigSources(configSources); - addConverters(config, forClassLoader); - - // also register all ConfigFilters - ServiceLoader configFilterLoader = ServiceLoader.load(ConfigFilter.class, forClassLoader); - for (ConfigFilter configFilter : configFilterLoader) { - config.addConfigFilter(configFilter); - } - - return config; - } - - protected Collection getBuiltInConfigSources(ClassLoader forClassLoader) { - List configSources = new ArrayList<>(); - configSources.add(new SystemEnvConfigSource()); - configSources.add(new SystemPropertyConfigSource()); - configSources.addAll(new PropertyFileConfigSourceProvider("META-INF/java-config.properties", true, forClassLoader).getConfigSources(forClassLoader)); - configSources.addAll(getCustomPropertyFiles(forClassLoader)); - - return configSources; - } - - private Collection getCustomPropertyFiles(ClassLoader forClassLoader) { - List configSources = new ArrayList<>(); - ServiceLoader propertyFileConfigLoader = ServiceLoader.load(PropertyFileConfig.class); - for (PropertyFileConfig propConfig : propertyFileConfigLoader) { - configSources.addAll(new PropertyFileConfigSourceProvider(propConfig.getPropertyFileName(), propConfig.isOptional(), forClassLoader).getConfigSources(forClassLoader)); - } - - return configSources; - } - - protected void addConverters(Config config, ClassLoader forClassLoader) { - ServiceLoader converters = ServiceLoader.load(Converter.class, forClassLoader); - for (Converter converter : converters) { - config.addConverter(converter); - } - } - - private void registerConfig(Config config, ClassLoader forClassLoader) { + @Override + public void registerConfig(Config config, ClassLoader forClassLoader) { synchronized (DefaultConfigProvider.class) { configs.put(forClassLoader, new WeakReference<>(config)); } } @Override - public Config newConfig() { - return new ConfigImpl(); + public ConfigBuilder getBuilder() { + return new DefaultConfigBuilder(); } + @Override public void releaseConfig(Config config) { - Iterator>> it = configs.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry> next = it.next(); + if (config == null) { + // get the config from the current TCCL + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + if (classLoader == null) { + classLoader = DefaultConfigProvider.class.getClassLoader(); + } + config = existingConfig(classLoader); + } + + if (config != null) { + synchronized (DefaultConfigProvider.class) { + Iterator>> it = configs.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry> entry = it.next(); + if (entry.getValue().get() != null && entry.getValue().get() == config) { + it.remove(); + break; + } + } + } } } } diff --git a/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigExtension.java b/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigExtension.java new file mode 100644 index 0000000..94b1b39 --- /dev/null +++ b/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigExtension.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.geronimo.config.cdi; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.enterprise.event.Observes; +import javax.enterprise.inject.spi.AfterBeanDiscovery; +import javax.enterprise.inject.spi.AfterDeploymentValidation; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.BeforeShutdown; +import javax.enterprise.inject.spi.DeploymentException; +import javax.enterprise.inject.spi.Extension; +import javax.enterprise.inject.spi.InjectionPoint; +import javax.enterprise.inject.spi.ProcessInjectionPoint; +import javax.inject.Provider; + +import org.apache.geronimo.config.DefaultConfigProvider; +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +/** + * @author Mark Struberg + */ +public class ConfigExtension implements Extension { + + private Config config; + + private Set injectionPoints = new HashSet<>(); + + public void collectConfigProducer(@Observes ProcessInjectionPoint pip) { + ConfigProperty configProperty = pip.getInjectionPoint().getAnnotated().getAnnotation(ConfigProperty.class); + if (configProperty != null) { + injectionPoints.add(pip.getInjectionPoint()); + } + } + + public void registerConfigProducer(@Observes AfterBeanDiscovery abd, BeanManager bm) { + Set types = injectionPoints.stream() + .filter(ip -> ip.getType() instanceof Class) + .map(ip -> (Class) ip.getType()) + .collect(Collectors.toSet()); + + // Provider and Optional are ParameterizedTypes and not a Class, so we need to add them manually + types.add(Provider.class); + types.add(Optional.class); + + types.forEach(type -> abd.addBean(new ConfigInjectionBean(bm, type))); + } + + public void validate(@Observes AfterDeploymentValidation add) { + List deploymentProblems = new ArrayList<>(); + + config = ConfigProvider.getConfig(); + + for (InjectionPoint injectionPoint : injectionPoints) { + Type type = injectionPoint.getType(); + ConfigProperty configProperty = injectionPoint.getAnnotated().getAnnotation(ConfigProperty.class); + if (type instanceof Class) { + // a direct injection of a ConfigProperty + // that means a Converter must exist. + String key = ConfigInjectionBean.getConfigKey(injectionPoint, configProperty); + if (!config.getOptionalValue(key, (Class) type).isPresent()) { + deploymentProblems.add("No Config Value exists for " + key); + } + } + } + + if (!deploymentProblems.isEmpty()) { + add.addDeploymentProblem(new DeploymentException("Error while validating Configuration\n" + + String.join("\n", deploymentProblems))); + } + + } + + public void shutdown(@Observes BeforeShutdown bsd) { + DefaultConfigProvider.instance().releaseConfig(config); + } + + +} diff --git a/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigInjectionBean.java b/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigInjectionBean.java new file mode 100644 index 0000000..ba2b39b --- /dev/null +++ b/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigInjectionBean.java @@ -0,0 +1,250 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.geronimo.config.cdi; + +import java.io.IOException; +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import javax.enterprise.context.Dependent; +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.Annotated; +import javax.enterprise.inject.spi.AnnotatedMember; +import javax.enterprise.inject.spi.AnnotatedType; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.DeploymentException; +import javax.enterprise.inject.spi.InjectionPoint; +import javax.enterprise.inject.spi.PassivationCapable; +import javax.enterprise.util.AnnotationLiteral; +import javax.inject.Provider; + +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.config.spi.ConfigProviderResolver; + +/** + * @author Mark Struberg + */ +public class ConfigInjectionBean implements Bean, PassivationCapable { + + private final static Set QUALIFIERS = new HashSet<>(); + static { + QUALIFIERS.add(new ConfigPropertyLiteral()); + } + + private final BeanManager bm; + private final Class rawType; + private final Set types; + + /** + * only access via {@link #getConfig(} + */ + private Config _config; + + public ConfigInjectionBean(BeanManager bm, Type type) { + this.bm = bm; + + types = new HashSet<>(); + types.add(type); + rawType = getRawType(type); + } + + private Class getRawType(Type type) { + if (type instanceof Class) { + return (Class) type; + } + else if (type instanceof ParameterizedType) { + ParameterizedType paramType = (ParameterizedType) type; + + return (Class) paramType.getRawType(); + } + + throw new UnsupportedOperationException("No idea how to handle " + type); + } + + @Override + public Set getInjectionPoints() { + return Collections.EMPTY_SET; + } + + @Override + public Class getBeanClass() { + return rawType; + } + + @Override + public boolean isNullable() { + return false; + } + + @Override + public T create(CreationalContext context) { + Set> beans = bm.getBeans(InjectionPoint.class); + Bean bean = bm.resolve(beans); + InjectionPoint ip = (InjectionPoint) bm.getReference(bean, InjectionPoint.class, context); + if (ip == null) { + throw new IllegalStateException("Could not retrieve InjectionPoint"); + } + Annotated annotated = ip.getAnnotated(); + ConfigProperty configProperty = annotated.getAnnotation(ConfigProperty.class); + String key = configProperty.name(); + + if (annotated.getBaseType() instanceof ParameterizedType) { + ParameterizedType paramType = (ParameterizedType) annotated.getBaseType(); + Type rawType = paramType.getRawType(); + + // handle Provider + if (rawType instanceof Class && ((Class) rawType).isAssignableFrom(Provider.class) && paramType.getActualTypeArguments().length == 1) { + Class clazz = (Class) paramType.getActualTypeArguments()[0]; //X TODO check type again, etc + return (T) new ConfigValueProvider(getConfig(), key, clazz); + } + + // handle Optional + if (rawType instanceof Class && ((Class) rawType).isAssignableFrom(Optional.class) && paramType.getActualTypeArguments().length == 1) { + Class clazz = (Class) paramType.getActualTypeArguments()[0]; //X TODO check type again, etc + return (T) getConfig().getOptionalValue(key, clazz); + } + } + else { + Class clazz = (Class) annotated.getBaseType(); + return (T) getConfig().getValue(key, clazz); + } + + throw new IllegalStateException("unhandled ConfigProperty"); + } + + + /** + * Get the property key to use. + * In case the {@link ConfigProperty#name()} is empty we will try to determine the key name from the InjectionPoint. + */ + public static String getConfigKey(InjectionPoint ip, ConfigProperty configProperty) { + String key = configProperty.name(); + if (key.length() > 0) { + return key; + } + if (ip.getAnnotated() instanceof AnnotatedMember) { + AnnotatedMember member = (AnnotatedMember) ip.getAnnotated(); + AnnotatedType declaringType = member.getDeclaringType(); + if (declaringType != null) { + String[] parts = declaringType.getJavaClass().getName().split("."); + String cn = parts[parts.length-1]; + parts[parts.length-1] = Character.toLowerCase(cn.charAt(0)) + (cn.length() > 1 ? cn.substring(1) : ""); + StringBuilder sb = new StringBuilder(parts[0]); + for (int i = 1; i < parts.length; i++) { + sb.append(".").append(parts[i]); + } + + // now add the field name + sb.append(".").append(member.getJavaMember().getName()); + return sb.toString(); + } + } + + throw new IllegalStateException("Could not find default name for @ConfigProperty InjectionPoint " + ip); + } + + public Config getConfig() { + if (_config == null) { + _config = ConfigProvider.getConfig(); + } + return _config; + } + + @Override + public void destroy(T instance, CreationalContext context) { + + } + + @Override + public Set getTypes() { + return types; + } + + @Override + public Set getQualifiers() { + return QUALIFIERS; + } + + @Override + public Class getScope() { + return Dependent.class; + } + + @Override + public String getName() { + return null; + } + + @Override + public Set> getStereotypes() { + return Collections.EMPTY_SET; + } + + @Override + public boolean isAlternative() { + return true; + } + + @Override + public String getId() { + return "ConfigInjectionBean_" + rawType.getName(); + } + + private static class ConfigPropertyLiteral extends AnnotationLiteral implements ConfigProperty { + @Override + public String name() { + return ""; + } + + @Override + public String defaultValue() { + return ""; + } + } + + public static class ConfigValueProvider implements Provider, Serializable { + private transient Config config; + private final String key; + private final Class type; + + ConfigValueProvider(Config config, String key, Class type) { + this.config = config; + this.key = key; + this.type = type; + } + + @Override + public T get() { + return (T) config.getValue(key, type); + } + + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + config = ConfigProviderResolver.instance().getConfig(); + } + + } +} diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/converters/Duck.java b/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigInjectionProducer.java similarity index 57% rename from tck/src/main/java/org/apache/geronimo/config/tck/converters/Duck.java rename to impl/src/main/java/org/apache/geronimo/config/cdi/ConfigInjectionProducer.java index 18d0fb0..ce16e8e 100644 --- a/tck/src/main/java/org/apache/geronimo/config/tck/converters/Duck.java +++ b/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigInjectionProducer.java @@ -14,20 +14,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.geronimo.config.tck.converters; +package org.apache.geronimo.config.cdi; + + +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; + +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; /** - * @author Mark Struberg + * @author Mark Struberg */ -public class Duck { - private final String name; +@ApplicationScoped +public class ConfigInjectionProducer { + private Config config; - public Duck(String name) { - this.name = name; + @PostConstruct + void init() { + config = ConfigProvider.getConfig(); } - public String getName() { - return name; + @Produces + @ApplicationScoped + public Config createConfig() { + return config; } + + } diff --git a/impl/src/main/java/org/apache/geronimo/config/configsource/BaseConfigSource.java b/impl/src/main/java/org/apache/geronimo/config/configsource/BaseConfigSource.java index c8c8da1..d7117be 100644 --- a/impl/src/main/java/org/apache/geronimo/config/configsource/BaseConfigSource.java +++ b/impl/src/main/java/org/apache/geronimo/config/configsource/BaseConfigSource.java @@ -21,7 +21,7 @@ import java.util.logging.Level; import java.util.logging.Logger; -import javx.config.spi.ConfigSource; +import org.eclipse.microprofile.config.spi.ConfigSource; /** @@ -31,6 +31,9 @@ * @author Gerhard Petracek */ public abstract class BaseConfigSource implements ConfigSource { + + public final static String CONFIG_ORDINAL = "config_ordinal"; + protected Logger log = Logger.getLogger(getClass().getName()); private int ordinal = 1000; // default @@ -50,7 +53,7 @@ public int getOrdinal() { protected void initOrdinal(int defaultOrdinal) { ordinal = defaultOrdinal; - String configuredOrdinalString = getPropertyValue(ConfigSource.CONFIG_ORDINAL); + String configuredOrdinalString = getValue(CONFIG_ORDINAL); try { if (configuredOrdinalString != null) { @@ -63,8 +66,4 @@ protected void initOrdinal(int defaultOrdinal) { } } - @Override - public boolean isScannable() { - return true; - } } diff --git a/impl/src/main/java/org/apache/geronimo/config/configsource/PropertyFileConfigSource.java b/impl/src/main/java/org/apache/geronimo/config/configsource/PropertyFileConfigSource.java index d98826d..e7c0b2c 100644 --- a/impl/src/main/java/org/apache/geronimo/config/configsource/PropertyFileConfigSource.java +++ b/impl/src/main/java/org/apache/geronimo/config/configsource/PropertyFileConfigSource.java @@ -22,9 +22,14 @@ import java.util.Map; import java.util.Properties; +import javax.enterprise.inject.Typed; +import javax.enterprise.inject.Vetoed; + /** * @author Mark Struberg */ +@Typed +@Vetoed public class PropertyFileConfigSource extends BaseConfigSource { private Map properties; private String fileName; @@ -42,12 +47,12 @@ public PropertyFileConfigSource(URL propertyFileUrl) { * @return value for the given key or null if there is no configured value */ @Override - public String getPropertyValue(String key) { - return (String) properties.get(key); + public String getValue(String key) { + return properties.get(key); } @Override - public String getConfigName() { + public String getName() { return fileName; } diff --git a/impl/src/main/java/org/apache/geronimo/config/configsource/PropertyFileConfigSourceProvider.java b/impl/src/main/java/org/apache/geronimo/config/configsource/PropertyFileConfigSourceProvider.java index 9d6e218..abbf199 100644 --- a/impl/src/main/java/org/apache/geronimo/config/configsource/PropertyFileConfigSourceProvider.java +++ b/impl/src/main/java/org/apache/geronimo/config/configsource/PropertyFileConfigSourceProvider.java @@ -26,8 +26,11 @@ import java.util.logging.Level; import java.util.logging.Logger; -import javx.config.spi.ConfigSource; -import javx.config.spi.ConfigSourceProvider; +import javax.enterprise.inject.Typed; +import javax.enterprise.inject.Vetoed; + +import org.eclipse.microprofile.config.spi.ConfigSource; +import org.eclipse.microprofile.config.spi.ConfigSourceProvider; /** @@ -36,6 +39,8 @@ * * @author Mark Struberg */ +@Typed +@Vetoed public class PropertyFileConfigSourceProvider implements ConfigSourceProvider { private static final Logger LOG = Logger.getLogger(PropertyFileConfigSourceProvider.class.getName()); diff --git a/impl/src/main/java/org/apache/geronimo/config/configsource/SystemEnvConfigSource.java b/impl/src/main/java/org/apache/geronimo/config/configsource/SystemEnvConfigSource.java index c45a47d..6eefca5 100644 --- a/impl/src/main/java/org/apache/geronimo/config/configsource/SystemEnvConfigSource.java +++ b/impl/src/main/java/org/apache/geronimo/config/configsource/SystemEnvConfigSource.java @@ -21,7 +21,10 @@ import java.util.Map; -import javx.config.spi.ConfigSource; +import javax.enterprise.inject.Typed; +import javax.enterprise.inject.Vetoed; + +import org.eclipse.microprofile.config.spi.ConfigSource; /** * {@link ConfigSource} which uses {@link System#getenv()} @@ -31,6 +34,8 @@ * * @author Mark Struberg */ +@Typed +@Vetoed public class SystemEnvConfigSource extends BaseConfigSource { private Map configValues; @@ -40,7 +45,7 @@ public SystemEnvConfigSource() { } @Override - public String getConfigName() { + public String getName() { return "system_env"; } @@ -50,7 +55,7 @@ public Map getProperties() { } @Override - public String getPropertyValue(String key) { + public String getValue(String key) { String val = configValues.get(key); if (val == null || val.isEmpty()) { val = configValues.get(key.replace('.', '_')); diff --git a/impl/src/main/java/org/apache/geronimo/config/configsource/SystemPropertyConfigSource.java b/impl/src/main/java/org/apache/geronimo/config/configsource/SystemPropertyConfigSource.java index f29cf23..4d741bd 100644 --- a/impl/src/main/java/org/apache/geronimo/config/configsource/SystemPropertyConfigSource.java +++ b/impl/src/main/java/org/apache/geronimo/config/configsource/SystemPropertyConfigSource.java @@ -20,13 +20,18 @@ import java.util.Map; -import javx.config.spi.ConfigSource; +import javax.enterprise.inject.Typed; +import javax.enterprise.inject.Vetoed; + +import org.eclipse.microprofile.config.spi.ConfigSource; /** * {@link ConfigSource} which uses {@link System#getProperties()} * * @author Mark Struberg */ +@Typed +@Vetoed public class SystemPropertyConfigSource extends BaseConfigSource { public SystemPropertyConfigSource() { initOrdinal(400); @@ -38,12 +43,12 @@ public Map getProperties() { } @Override - public String getPropertyValue(String key) { + public String getValue(String key) { return System.getProperty(key); } @Override - public String getConfigName() { + public String getName() { return "system-properties"; } } diff --git a/impl/src/main/java/org/apache/geronimo/config/converters/BooleanConverter.java b/impl/src/main/java/org/apache/geronimo/config/converters/BooleanConverter.java index 5df76ee..9f70a33 100644 --- a/impl/src/main/java/org/apache/geronimo/config/converters/BooleanConverter.java +++ b/impl/src/main/java/org/apache/geronimo/config/converters/BooleanConverter.java @@ -16,14 +16,16 @@ */ package org.apache.geronimo.config.converters; -import javx.config.spi.Converter; +import org.eclipse.microprofile.config.spi.Converter; import javax.annotation.Priority; +import javax.enterprise.inject.Vetoed; /** * @author Mark Struberg */ @Priority(1) +@Vetoed public class BooleanConverter implements Converter { public static final BooleanConverter INSTANCE = new BooleanConverter(); @@ -35,6 +37,7 @@ public Boolean convert(String value) { || "1".equalsIgnoreCase(value) || "YES".equalsIgnoreCase(value) || "Y".equalsIgnoreCase(value) + || "ON".equalsIgnoreCase(value) || "JA".equalsIgnoreCase(value) || "J".equalsIgnoreCase(value) || "OUI".equalsIgnoreCase(value); diff --git a/impl/src/main/java/org/apache/geronimo/config/converters/DoubleConverter.java b/impl/src/main/java/org/apache/geronimo/config/converters/DoubleConverter.java index 99b0add..28cd9f8 100644 --- a/impl/src/main/java/org/apache/geronimo/config/converters/DoubleConverter.java +++ b/impl/src/main/java/org/apache/geronimo/config/converters/DoubleConverter.java @@ -16,14 +16,16 @@ */ package org.apache.geronimo.config.converters; -import javx.config.spi.Converter; +import org.eclipse.microprofile.config.spi.Converter; import javax.annotation.Priority; +import javax.enterprise.inject.Vetoed; /** * @author Mark Struberg */ @Priority(1) +@Vetoed public class DoubleConverter implements Converter { public static final DoubleConverter INSTANCE = new DoubleConverter(); diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/PropertyFileConfigSourceTest.java b/impl/src/main/java/org/apache/geronimo/config/converters/DurationConverter.java similarity index 54% rename from tck/src/main/java/org/apache/geronimo/config/tck/PropertyFileConfigSourceTest.java rename to impl/src/main/java/org/apache/geronimo/config/converters/DurationConverter.java index 229e42b..8f04abb 100644 --- a/tck/src/main/java/org/apache/geronimo/config/tck/PropertyFileConfigSourceTest.java +++ b/impl/src/main/java/org/apache/geronimo/config/converters/DurationConverter.java @@ -14,26 +14,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.geronimo.config.tck; +package org.apache.geronimo.config.converters; -import javx.config.Config; -import javx.config.ConfigProvider; -import org.testng.Assert; -import org.testng.annotations.Test; +import java.time.Duration; +import java.time.format.DateTimeParseException; + +import javax.annotation.Priority; +import javax.enterprise.inject.Vetoed; + +import org.eclipse.microprofile.config.spi.Converter; /** * @author Mark Struberg */ -public class PropertyFileConfigSourceTest { - @Test - public void testCustomPropertyFilesConfigSource() { - Config config = ConfigProvider.getConfig(); - Assert.assertEquals(config.getValue("tck.config.test.propertyfileconfig.custom.key1"), "value1"); - } +@Priority(1) +@Vetoed +public class DurationConverter implements Converter { + + public static final DurationConverter INSTANCE = new DurationConverter(); - @Test - public void testPropertyOverwrite() { - Config config = ConfigProvider.getConfig(); - Assert.assertEquals(config.getValue("tck.config.test.overwritten.in.custompropertyfile.key1"), "value from some/custom.properties"); + @Override + public Duration convert(String value) { + if (value != null) { + try { + return Duration.parse(value); + } + catch (DateTimeParseException dtpe) { + throw new IllegalArgumentException(dtpe); + } + } + return null; } -} \ No newline at end of file +} diff --git a/impl/src/main/java/org/apache/geronimo/config/converters/FloatConverter.java b/impl/src/main/java/org/apache/geronimo/config/converters/FloatConverter.java index c8d5806..94c14d7 100644 --- a/impl/src/main/java/org/apache/geronimo/config/converters/FloatConverter.java +++ b/impl/src/main/java/org/apache/geronimo/config/converters/FloatConverter.java @@ -17,13 +17,15 @@ package org.apache.geronimo.config.converters; import javax.annotation.Priority; +import javax.enterprise.inject.Vetoed; -import javx.config.spi.Converter; +import org.eclipse.microprofile.config.spi.Converter; /** * @author Mark Struberg */ @Priority(1) +@Vetoed public class FloatConverter implements Converter { public static final FloatConverter INSTANCE = new FloatConverter(); diff --git a/impl/src/main/java/org/apache/geronimo/config/converters/IntegerConverter.java b/impl/src/main/java/org/apache/geronimo/config/converters/IntegerConverter.java index e3c7e0d..d34c468 100644 --- a/impl/src/main/java/org/apache/geronimo/config/converters/IntegerConverter.java +++ b/impl/src/main/java/org/apache/geronimo/config/converters/IntegerConverter.java @@ -17,13 +17,15 @@ package org.apache.geronimo.config.converters; import javax.annotation.Priority; +import javax.enterprise.inject.Vetoed; -import javx.config.spi.Converter; +import org.eclipse.microprofile.config.spi.Converter; /** * @author Mark Struberg */ @Priority(1) +@Vetoed public class IntegerConverter implements Converter { public static final IntegerConverter INSTANCE = new IntegerConverter(); diff --git a/impl/src/main/java/org/apache/geronimo/config/converters/LocalDateConverter.java b/impl/src/main/java/org/apache/geronimo/config/converters/LocalDateConverter.java new file mode 100644 index 0000000..41b9968 --- /dev/null +++ b/impl/src/main/java/org/apache/geronimo/config/converters/LocalDateConverter.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.geronimo.config.converters; + +import java.time.LocalDate; +import java.time.format.DateTimeParseException; + +import javax.annotation.Priority; +import javax.enterprise.inject.Vetoed; + +import org.eclipse.microprofile.config.spi.Converter; + +/** + * @author Mark Struberg + */ +@Priority(1) +@Vetoed +public class LocalDateConverter implements Converter { + + public static final LocalDateConverter INSTANCE = new LocalDateConverter(); + + @Override + public LocalDate convert(String value) { + if (value != null) { + try { + return LocalDate.parse(value); + } + catch (DateTimeParseException dtpe) { + throw new IllegalArgumentException(dtpe); + } + } + return null; + } +} diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/configsources/SampleYamlConfigSource.java b/impl/src/main/java/org/apache/geronimo/config/converters/LocalDateTimeConverter.java similarity index 54% rename from tck/src/main/java/org/apache/geronimo/config/tck/configsources/SampleYamlConfigSource.java rename to impl/src/main/java/org/apache/geronimo/config/converters/LocalDateTimeConverter.java index 8112088..fe5c09e 100644 --- a/tck/src/main/java/org/apache/geronimo/config/tck/configsources/SampleYamlConfigSource.java +++ b/impl/src/main/java/org/apache/geronimo/config/converters/LocalDateTimeConverter.java @@ -14,46 +14,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.geronimo.config.tck.configsources; +package org.apache.geronimo.config.converters; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; +import java.time.LocalDateTime; +import java.time.format.DateTimeParseException; -import javx.config.spi.ConfigSource; +import javax.annotation.Priority; +import javax.enterprise.inject.Vetoed; + +import org.eclipse.microprofile.config.spi.Converter; /** * @author Mark Struberg */ -public class SampleYamlConfigSource implements ConfigSource { - private Map config = new HashMap<>(); - - public SampleYamlConfigSource(URL url) { - config.put("tck.config.test.sampleyaml.key1", "yamlvalue1"); - } - - @Override - public int getOrdinal() { - return 110; - } - - @Override - public Map getProperties() { - return config; - } +@Priority(1) +@Vetoed +public class LocalDateTimeConverter implements Converter { - @Override - public String getPropertyValue(String key) { - return config.get(key); - } + public static final LocalDateTimeConverter INSTANCE = new LocalDateTimeConverter(); @Override - public String getConfigName() { + public LocalDateTime convert(String value) { + if (value != null) { + try { + return LocalDateTime.parse(value); + } + catch (DateTimeParseException dtpe) { + throw new IllegalArgumentException(dtpe); + } + } return null; } - - @Override - public boolean isScannable() { - return false; - } } diff --git a/impl/src/main/java/org/apache/geronimo/config/converters/LocalTimeConverter.java b/impl/src/main/java/org/apache/geronimo/config/converters/LocalTimeConverter.java new file mode 100644 index 0000000..326c167 --- /dev/null +++ b/impl/src/main/java/org/apache/geronimo/config/converters/LocalTimeConverter.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.geronimo.config.converters; + +import java.time.LocalTime; +import java.time.format.DateTimeParseException; + +import javax.annotation.Priority; +import javax.enterprise.inject.Vetoed; + +import org.eclipse.microprofile.config.spi.Converter; + +/** + * @author Mark Struberg + */ +@Priority(1) +@Vetoed +public class LocalTimeConverter implements Converter { + + public static final LocalTimeConverter INSTANCE = new LocalTimeConverter(); + + @Override + public LocalTime convert(String value) { + if (value != null) { + try { + return LocalTime.parse(value); + } + catch (DateTimeParseException dtpe) { + throw new IllegalArgumentException(dtpe); + } + } + return null; + } +} diff --git a/impl/src/main/java/org/apache/geronimo/config/converters/LongConverter.java b/impl/src/main/java/org/apache/geronimo/config/converters/LongConverter.java index 2d9eff6..007d1c7 100644 --- a/impl/src/main/java/org/apache/geronimo/config/converters/LongConverter.java +++ b/impl/src/main/java/org/apache/geronimo/config/converters/LongConverter.java @@ -16,14 +16,16 @@ */ package org.apache.geronimo.config.converters; -import javx.config.spi.Converter; +import org.eclipse.microprofile.config.spi.Converter; import javax.annotation.Priority; +import javax.enterprise.inject.Vetoed; /** * @author Mark Struberg */ @Priority(1) +@Vetoed public class LongConverter implements Converter { public static final LongConverter INSTANCE = new LongConverter(); diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/configsources/CustomPropertyFileConfig.java b/impl/src/main/java/org/apache/geronimo/config/converters/StringConverter.java similarity index 61% rename from tck/src/main/java/org/apache/geronimo/config/tck/configsources/CustomPropertyFileConfig.java rename to impl/src/main/java/org/apache/geronimo/config/converters/StringConverter.java index f7589ad..0d5ccbc 100644 --- a/tck/src/main/java/org/apache/geronimo/config/tck/configsources/CustomPropertyFileConfig.java +++ b/impl/src/main/java/org/apache/geronimo/config/converters/StringConverter.java @@ -14,21 +14,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.geronimo.config.tck.configsources; +package org.apache.geronimo.config.converters; -import javx.config.spi.PropertyFileConfig; +import javax.annotation.Priority; +import javax.enterprise.inject.Vetoed; + +import org.eclipse.microprofile.config.spi.Converter; /** - * @author Mark Struberg + * 1:1 string output. Just to make converter logic happy. + * + * @author Mark Struberg */ -public class CustomPropertyFileConfig implements PropertyFileConfig { - @Override - public String getPropertyFileName() { - return "some/custom.properties"; - } +@Priority(1) +@Vetoed +public class StringConverter implements Converter { + + public static final StringConverter INSTANCE = new StringConverter(); @Override - public boolean isOptional() { - return false; + public String convert(String value) { + return value; } } diff --git a/impl/src/main/resources/META-INF/beans.xml b/impl/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000..48bb5d2 --- /dev/null +++ b/impl/src/main/resources/META-INF/beans.xml @@ -0,0 +1,18 @@ + diff --git a/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension new file mode 100644 index 0000000..f949a49 --- /dev/null +++ b/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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 current 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. +# + +org.apache.geronimo.config.cdi.ConfigExtension \ No newline at end of file diff --git a/impl/src/main/resources/META-INF/services/javx.config.ConfigProvider$SPI b/impl/src/main/resources/META-INF/services/javx.config.ConfigProvider$SPI deleted file mode 100644 index c22654d..0000000 --- a/impl/src/main/resources/META-INF/services/javx.config.ConfigProvider$SPI +++ /dev/null @@ -1 +0,0 @@ -org.apache.geronimo.config.DefaultConfigProvider \ No newline at end of file diff --git a/impl/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigProviderResolver b/impl/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigProviderResolver new file mode 100644 index 0000000..b3580b9 --- /dev/null +++ b/impl/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigProviderResolver @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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 current 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. +# + +org.apache.geronimo.config.DefaultConfigProvider \ No newline at end of file diff --git a/impl/src/test/java/org/apache/geronimo/config/test/GeronimoConfigArchiveProcessor.java b/impl/src/test/java/org/apache/geronimo/config/test/GeronimoConfigArchiveProcessor.java new file mode 100644 index 0000000..7316c01 --- /dev/null +++ b/impl/src/test/java/org/apache/geronimo/config/test/GeronimoConfigArchiveProcessor.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.geronimo.config.test; + +import org.apache.geronimo.config.ConfigImpl; +import org.apache.geronimo.config.DefaultConfigProvider; +import org.apache.geronimo.config.cdi.ConfigInjectionProducer; +import org.apache.geronimo.config.configsource.BaseConfigSource; +import org.apache.geronimo.config.converters.BooleanConverter; +import org.eclipse.microprofile.config.spi.ConfigProviderResolver; +import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor; +import org.jboss.arquillian.test.spi.TestClass; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jboss.shrinkwrap.api.spec.WebArchive; + +/** + * Adds the whole Config implementation classes and resources to the + * Arqillian deployment archive. This is needed to have the container + * pick up the beans from within the impl for the TCK tests. + * + * @author Mark Struberg + */ +public class GeronimoConfigArchiveProcessor implements ApplicationArchiveProcessor { + + @Override + public void process(Archive applicationArchive, TestClass testClass) { + if (applicationArchive instanceof WebArchive) { + JavaArchive configJar = ShrinkWrap + .create(JavaArchive.class, "geronimo-config-impl.jar") + .addPackage(ConfigImpl.class.getPackage()) + .addPackage(BooleanConverter.class.getPackage()) + .addPackage(BaseConfigSource.class.getPackage()) + .addPackage(ConfigInjectionProducer.class.getPackage()) + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml") + .addAsServiceProvider(ConfigProviderResolver.class, DefaultConfigProvider.class); + ((WebArchive) applicationArchive).addAsLibraries(configJar); + } + } +} diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/converters/DuckConverter.java b/impl/src/test/java/org/apache/geronimo/config/test/GeronimoConfigExtension.java similarity index 62% rename from tck/src/main/java/org/apache/geronimo/config/tck/converters/DuckConverter.java rename to impl/src/test/java/org/apache/geronimo/config/test/GeronimoConfigExtension.java index f8337bd..22335a0 100644 --- a/tck/src/main/java/org/apache/geronimo/config/tck/converters/DuckConverter.java +++ b/impl/src/test/java/org/apache/geronimo/config/test/GeronimoConfigExtension.java @@ -14,17 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.geronimo.config.tck.converters; +package org.apache.geronimo.config.test; -import javx.config.spi.Converter; +import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor; +import org.jboss.arquillian.core.spi.LoadableExtension; /** - * @author Mark Struberg + * @author Mark Struberg */ -public class DuckConverter implements Converter { - +public class GeronimoConfigExtension implements LoadableExtension { @Override - public Duck convert(String value) { - return new Duck(value); + public void register(ExtensionBuilder extensionBuilder) { + extensionBuilder.service(ApplicationArchiveProcessor.class, GeronimoConfigArchiveProcessor.class); } } diff --git a/impl/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension b/impl/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension new file mode 100644 index 0000000..91c04d4 --- /dev/null +++ b/impl/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension @@ -0,0 +1,21 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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 current 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. +# + + +org.apache.geronimo.config.test.GeronimoConfigExtension \ No newline at end of file diff --git a/impl/tck-suite.xml b/impl/tck-suite.xml index ab445be..a9fd699 100644 --- a/impl/tck-suite.xml +++ b/impl/tck-suite.xml @@ -15,18 +15,14 @@ the specific language governing permissions and limitations under the License. --> - - - - - + + - + - diff --git a/pom.xml b/pom.xml index 63b79ce..05e8c78 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ org.apache apache - 17 + 18 org.apache.geronimo.config @@ -31,19 +31,46 @@ 0.1-SNAPSHOT pom + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + A business-friendly OSS license + + + 3.1.0 - 1.7 - 1.7 + 1.8 + 1.8 - api - tck impl - spec + + + + + org.apache.rat + apache-rat-plugin + 0.12 + + + rat-check + check + + + + + .travis.yml.* + + + + + diff --git a/spec/pom.xml b/spec/pom.xml deleted file mode 100644 index b8a8c17..0000000 --- a/spec/pom.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - 4.0.0 - - - - org.apache.geronimo.config - config-parent - 0.1-SNAPSHOT - - - org.apache.geronimo.config - config-spec - pom - - - 1.5.3 - 1.5.0-alpha.10.1 - asl2 - MMMM dd, yyyy - ${maven.build.timestamp} - - - - clean package - - - org.asciidoctor - asciidoctor-maven-plugin - ${asciidoctor-maven.version} - - - org.asciidoctor - asciidoctorj-pdf - ${asciidoctorj-pdf.version} - - - - - generate-pdf-doc - generate-resources - - process-asciidoc - - - pdf - - - - output-html - generate-resources - - process-asciidoc - - - html5 - - - - - config-spec.asciidoc - coderay - - Apache License v2.0 - - - - - - - diff --git a/spec/src/main/asciidoc/architecture.asciidoc b/spec/src/main/asciidoc/architecture.asciidoc deleted file mode 100644 index cc1a15f..0000000 --- a/spec/src/main/asciidoc/architecture.asciidoc +++ /dev/null @@ -1,77 +0,0 @@ -[[architecture]] -== Architecture - -This specification defines a easy to use and flexible system for application configuration. -It also defines a way to extend the configuration mechanism itself via a SPI (Service Provider Interface). - -=== Rational - -Released binaries often contain classes which need to behave slightly different depending on the deployment. -This might be different REST endpoints to talk with depending on the customer at which a WAR gets deployed. -Or it might even be different features which need to be switched on and off depending on the installation. -All this must be possible without the need to re-package the whole application binary. - -Java-config provides a way to achieve this goal by allowing the application to bundle default configuration within the application. -But it also allows to overwrite them from outside, e.g. via an environment variable, a Java system property or even a database entry. - -=== Accessing a certain Configuration - -The `ConfigProvider` is the central class to access a configuration. -It must allow access to different configurations based on the application it gets used in. -We distinguish 3 different ways to resolve a `Config` instance: - -* A factory method `ConfigProvider#getConfig()` to create a `Config` object based on automatically picked up `ConfigSource` s from the current Thread Context ClassLoader classpath. - Subsequent calls to this method for a certain ClassLoader will return the same `Config` instance. - -* A factory method `ConfigProvider#getConfig(ClassLoader forClassLoader)` to create a `Config` object based on automatically picked up `ConfigSource` s from a given ClassLoader. - This can be used if the Thread Context ClassLoader does not represent the correct layer. - E.g. if you need the Config for a class in a shared EAR lib folder. - Subsequent calls to this method for a certain ClassLoader will return the same `Config` instance. - -* A factory method `ConfigProvider#newConfig()` to to create an empty `Config` object which can be filled manually. - No automatic `ConfigSource` and `ConfigFilter` lookup will be performed. - This configuration instance will not be shared by the `ConfigProvider`. - This method is intended be used if a IoT container or any other external Factory can be used to give access to a manualy created shared `Config`. - -All methods in the `ConfigProvider` and `Config` implementations are thread safe and reentrant. - -If a `Config` is bound to a ClassLoader ist must be made sure that it gets properly removed if the ClassLoader gets destroyed. -It must not create any mem leaks in that case. - -=== Configuration Lookup Mechanism Example - -Java-config is a String/String based mechanism. - -The configuration key might use dot-separated namespaces similar to Java package namespacing: - -[source, text] ----- -com.acme.myproject.someserver.url = http://some.server/some/endpoint -com.acme.myproject.someserver.active = true -com.acme.other.stuff.name = Karl ----- - -An application can access this configuration via a `Config` instance. - -[source, java] ----- -public class ConfigUsageSample { - - public void useTheConfig() { - // get access to the Config instance - Config config = ConfigProvider.getConfig(); - String serverUrl = config.getValue("com.acme.myproject.someserver.url"); - - callToServer(serverUrl); - } -} ----- - -If you like to access a different server then you can e.g. change the configuration via a `-D` system property: - -[source, text] ----- -$> java -jar some.jar -Dcom.acme.myproject.someserver.url=http://other.server/other/endpoint ----- - -Note that the way to inject this configuration into the application can be extended by providing custom `ConfigSource` s. \ No newline at end of file diff --git a/spec/src/main/asciidoc/config-spec.asciidoc b/spec/src/main/asciidoc/config-spec.asciidoc deleted file mode 100644 index cd8de66..0000000 --- a/spec/src/main/asciidoc/config-spec.asciidoc +++ /dev/null @@ -1,31 +0,0 @@ -= JSR XXX: Configuration for Java -:author: Mark Struberg -:email: struberg@apache.org -:revnumber: 0.1 -:revdate: 2016-07-15 -:revremark: Proposal -:version-label!: -:sectanchors: -:doctype: book -:license: Apache License v2.0 -:source-highlighter: coderay -:toc: left -:toclevels: 4 -:sectnumlevels: 4 -ifdef::backend-pdf[] -:pagenums: -endif::[] - -include::license-alv2.asciidoc[] - - -include::architecture.asciidoc[] - -include::configsources.asciidoc[] - -include::configfilters.asciidoc[] - -include::converters.asciidoc[] - -include::configvalue.asciidoc[] - diff --git a/spec/src/main/asciidoc/configfilters.asciidoc b/spec/src/main/asciidoc/configfilters.asciidoc deleted file mode 100644 index f3dbde7..0000000 --- a/spec/src/main/asciidoc/configfilters.asciidoc +++ /dev/null @@ -1,59 +0,0 @@ -[[configfilters]] -== ConfigFilters - -A `ConfigFilter` allows to act as a valve which is able to modify the configured values before they get handed out to the caller. - -The spec does not require the implementations to ship with any `ConfigFilters` enabled by default. - -A custom `ConfigFilter` must implement the interface `javx.config.spi.ConfigFilter`. -You have to register your implementation in a file `/META-INF/services/javx.config.spi.ConfigFilter` by writing the fully qualified class name of the custom implementation into it. - -Alternative to that a user can register a `ConfigFilter` manually via `void Config#addConfigFilter(ConfigFilter configFilterToAdd)`. - -=== Filtering a value for Usage - -A `ConfigFilter` can e.g. be used to decrypt a stored password on the fly: - -[source, java] ----- -public class PasswordDecryptionConfigFilter implements ConfigFilter { - @Override - public String filterValue(String key, String value) { - if (value != null && key.endsWith(".password")) { - return decrypt(value); - } - return value; - } - - @Override - public String filterValueForLog(String key, String value) { - // do nothing - return value; - } -} ----- - -=== Filtering a value for Logging - -To prevent passwords and other secret information to be printed out or logged away, a `ConfigFilter` can be used to mask out those values. - -[source, java] ----- -public class PasswordConfigFilter implements ConfigFilter { - @Override - public String filterValue(String key, String value) { - // do nothing - return value; - } - - @Override - public String filterValueForLog(String key, String value) { - if (value != null && - (key.contains("password") || key.contains("secret"))) { - return "*******"; // simply star-out the password - } - return value; - } -} - ----- \ No newline at end of file diff --git a/spec/src/main/asciidoc/configsources.asciidoc b/spec/src/main/asciidoc/configsources.asciidoc deleted file mode 100644 index 1a283df..0000000 --- a/spec/src/main/asciidoc/configsources.asciidoc +++ /dev/null @@ -1,144 +0,0 @@ -[[configsources]] -== ConfigSources - -A `ConfigSource` is exactly what its name says: a source for configured values. -The `Config` uses all configured implementations of `ConfigSource` to lookup the property in question. - -=== ConfigSource Ordering - -Each `ConfigSource` has a specified `ordinal`. -This ordinal get’s used to determine the importance of the values taken from the very `ConfigSource`. -A higher ordinal means that the values taken from this ConfigSource will override values from less important ConfigSources. -This is the trick which allows to amend configuration from outside a binary - given those outside ConfigSources have a higher `ordinal` than the ones who pickup the values from within the release binaries. - -It can also be used to implement a drop-in configuration approach. -Simply create a jar containing a `ConfigSource` with a higher ordinal and overwrite configuration values in it. -If the jar gets added to the classpath then it will overwrite the configuration from `ConfigSource` s with lower ordinal. - -The ordinal for property file based `ConfigSource` s can be configured using the key `config_ordinal` inside the property file. - -[source, text] ----- -config_ordinal = 120 -com.acme.myproject.someserver.url = http://more_important.server/some/endpoint ----- - -=== Default ConfigSources - -A Java-config implementation must provide `ConfigSource` s for the following data out of the box: - -* System properties (ordinal=400) -* Environment properties (ordinal=300) -* An own `ConfigSource` for each property file `META-INF/java-config.properties` found on the classpath. (default ordinal = 100) - -=== Custom ConfigSources - -ConfigSources are picked up using the `java.util.ServiceLoader` mechanism. - -To add a custom `ConfigSource`, you have to implement the interface `javx.config.spi.ConfigSource`. - -[source, java] ----- -public class CustomDbConfigSource implements ConfigSource { - - @Override - public int getOrdinal() { - return 112; - } - - @Override - public Map getProperties() { - return readPropertiesFromDb(); - } - - @Override - public String getPropertyValue(String key) { - return readPropertyFromDb(key); - } - - @Override - public String getConfigName() { - return "customDbConfig"; - } - - @Override - public boolean isScannable() { - return true; - } - - // + methods to read from the DB -} - ----- - -Then register your implementation in a file `/META-INF/services/javx.config.spi.ConfigSource` by writing the fully qualified class name of the custom implementation into it. - - -=== Custom ConfigSources via ConfigSourceProvider - -If you need dynamic ConfigSources you can also register a `ConfigSourceProvider` in a similar way. -This is useful if you like to dynamically pick up multiple `ConfigSource` s of the same kind. -For example, if you like to pick up all myproject.properties files from all the JARs in your classpath. - -A custom `ConfigSourceProvider` needs to implement the interface `javx.config.spi.ConfigSourceProvider`. -Register your implementation in a file `/META-INF/services/javx.config.spi.ConfigSourceProvider` by writing the fully qualified class name of the custom implementation/s into it. - -An example which registers all yaml files with the name `exampleconfig.yaml`: - -[source, java] ----- -public class ExampleYamlConfigSourceProvider - implements javx.config.spi.ConfigSourceProvider { - @Override - public List getConfigSources(ClassLoader forClassLoader) { - List configSources = new ArrayList<>(); - - Enumeration yamlFiles = null; - yamlFiles = forClassLoader.getResources("sampleconfig.yaml"); - while (yamlFiles.hasMoreElements()) { - configSources.add(new SampleYamlConfigSource(yamlFiles.nextElement())); - } - return configSources; - } -} ----- - -Please note that a single `ConfigSource` should be either registered directly or via a `ConfigSourceProvider`, but never both ways. - - -=== PropertyFileConfig - -You can also make Java-config pick up property files with a custom name as `ConfigSource` s. -The following example will pick up all property files with the name `some/custom.properties` from the classpath. - -[source, java] ----- -public class CustomPropertyFileConfig implements PropertyFileConfig { - @Override - public String getPropertyFileName() { - return "some/custom.properties"; - } - - @Override - public boolean isOptional() { - return false; - } -} ----- - -Register your implementation in a file `/META-INF/services/javx.config.spi.PropertyFileConfig` by writing the fully qualified class name of your `PropertyFileConfig` into it. - - -=== ConfigSource and Mutable Data - -A `Config` instance provides no caching but iterates over all `ConfigSources` for each `getValue(String)` operation. -A ConfigSource is allowed to cache the underlying values itself. - - -=== Manually adding ConfigSources - -A user can manually register `ConfigSource` s by using the method `void addConfigSources(List configSourcesToAdd)`. -This will add the given list to the already registered `ConfigSources` of the current `Config` instance. - -The order in which the `ConfigSources` get evaluates when using `Config#getValue(String key)` is independent from the order in which they got added to the `Config`. -It is only depending on the `ordinal` of the `ConfigSources`. \ No newline at end of file diff --git a/spec/src/main/asciidoc/configvalue.asciidoc b/spec/src/main/asciidoc/configvalue.asciidoc deleted file mode 100644 index d83d7d4..0000000 --- a/spec/src/main/asciidoc/configvalue.asciidoc +++ /dev/null @@ -1,3 +0,0 @@ -[[configvalue]] -== ConfigValue - diff --git a/spec/src/main/asciidoc/converters.asciidoc b/spec/src/main/asciidoc/converters.asciidoc deleted file mode 100644 index 46317ab..0000000 --- a/spec/src/main/asciidoc/converters.asciidoc +++ /dev/null @@ -1,29 +0,0 @@ -[[converters]] -== Converters - -For providing typeseafe configuration we need to convert from the configured Strings into target types. -This happens by providing `Converter` s in the `Config`. - -=== Built-in Converters - -The following `Converter` s are provided by Java-config by default: - -* `Boolean` , values for `true` (case insensitive) "true", "1", "YES", "Y" "JA" "J", "OUI". - Any other value will be interpreted as `false` -* `Integer` -* `Long` -* `Float` , a dot '.' is used to separate the fractional digits -* `Double` , a dot '.' is used to separate the fractional digits - - -=== Adding custom Converters - -A custom `Converter` must implement the generic interface `javx.config.spi.Converter`. -The TypedParameter of the interface is the target type the String is converted to -You have to register your implementation in a file `/META-INF/services/javx.config.spi.Converter` by writing the fully qualified class name of the custom implementation into it. - -A custom `Converter` can define a priority with the `@javax.annotation.Priority` annotation. -If a Priority annotation isn't applied, a default priority of 100 is assumed. -The `Config` will use the `Converter` with the highest `Priority` for each target type. - -A custom `Converter` for a target type of any of the built-in Converters will overwrite the default Converter. diff --git a/spec/src/main/asciidoc/license-alv2.asciidoc b/spec/src/main/asciidoc/license-alv2.asciidoc deleted file mode 100644 index 1461ae1..0000000 --- a/spec/src/main/asciidoc/license-alv2.asciidoc +++ /dev/null @@ -1,28 +0,0 @@ -[subs="normal"] -.... - -Specification: {doctitle} - -Version: {revnumber} - -Status: {revremark} - -Specification Lead: Mark Struberg - -Release: {revdate} - -Copyright 2016 Apache Software Foundation - -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. - -.... diff --git a/tck/pom.xml b/tck/pom.xml deleted file mode 100644 index d4858e0..0000000 --- a/tck/pom.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - 4.0.0 - - - org.apache.geronimo.config - config-parent - 0.1-SNAPSHOT - - - org.apache.geronimo.config - config-tck - - - - org.apache.geronimo.config - config-api - 0.1-SNAPSHOT - - - - org.testng - testng - 6.9.9 - compile - - - diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/ConfigFilterTest.java b/tck/src/main/java/org/apache/geronimo/config/tck/ConfigFilterTest.java deleted file mode 100644 index 3bb7fc8..0000000 --- a/tck/src/main/java/org/apache/geronimo/config/tck/ConfigFilterTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.apache.geronimo.config.tck; - -import javx.config.Config; -import javx.config.ConfigProvider; -import org.testng.Assert; -import org.testng.annotations.Test; - -/** - * @author Mark Struberg - */ -public class ConfigFilterTest { - - @Test - public void testConfigFiltering() { - Config config = ConfigProvider.getConfig(); - - // unfiltered - Assert.assertEquals(config.getValue("tck.config.test.javaconfig.configfilter.my.secret"), "SOME_SECRET"); - - // filtered - Assert.assertEquals(config.getValue("tck.config.test.javaconfig.configfilter.my.password"), "some_password"); - } - - @Test - public void testConfigFiltering_ForLogging() { - Config config = ConfigProvider.getConfig(); - - Assert.assertEquals( - config.filterConfigValueForLog("tck.config.test.javaconfig.configfilter.my.password", - config.getValue("tck.config.test.javaconfig.configfilter.my.password")), "*******"); - } -} diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/ConfigProviderTest.java b/tck/src/main/java/org/apache/geronimo/config/tck/ConfigProviderTest.java deleted file mode 100644 index 7e21402..0000000 --- a/tck/src/main/java/org/apache/geronimo/config/tck/ConfigProviderTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 org.apache.geronimo.config.tck; - -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Map; -import java.util.Properties; - -import javx.config.Config; -import javx.config.ConfigProvider; - -import org.testng.Assert; -import org.testng.annotations.Test; - -/** - * @author Mark Struberg - */ -public class ConfigProviderTest { - - @Test - public void testConfigProviderWithDefaultTCCL() { - ClassLoader oldTccl = Thread.currentThread().getContextClassLoader(); - try { - ClassLoader tempCl = new URLClassLoader(new URL[0], this.getClass().getClassLoader()); - Thread.currentThread().setContextClassLoader(tempCl); - Config config = ConfigProvider.getConfig(); - Assert.assertNotNull(config); - - Config config2 = ConfigProvider.getConfig(tempCl); - Assert.assertNotNull(config2); - Assert.assertEquals(config, config2); - } - finally { - Thread.currentThread().setContextClassLoader(oldTccl); - } - } - - @Test - public void testEnvironmentConfigSource() { - Map env = System.getenv(); - Config config = ConfigProvider.getConfig(); - for (Map.Entry envEntry : env.entrySet()) { - Assert.assertEquals(envEntry.getValue(), config.getValue(envEntry.getKey())); - } - } - - @Test - public void testPropertyConfigSource() { - Properties properties = System.getProperties(); - Config config = ConfigProvider.getConfig(); - - for (Map.Entry propEntry : properties.entrySet()) { - Assert.assertEquals(propEntry.getValue(), config.getValue((String) propEntry.getKey())); - } - } - - @Test - public void testDynamicValueInPropertyConfigSource() { - Config config = ConfigProvider.getConfig(); - String configKey = "tck.config.test.systemproperty.dynamic.value"; - String configValue = "myDynamicValue;"; - - System.setProperty(configKey, configValue); - Assert.assertEquals(config.getValue(configKey), configValue); - } - - @Test - public void testJavaConfigPropertyFilesConfigSource() { - Config config = ConfigProvider.getConfig(); - Assert.assertEquals(config.getValue("tck.config.test.javaconfig.properties.key1"), "VALue1"); - } - - @Test - public void testNonExistingConfigKey() { - Config config = ConfigProvider.getConfig(); - Assert.assertNull(config.getValue("tck.config.test.keydoesnotexist")); - } -} diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/ConfigSourceProviderTest.java b/tck/src/main/java/org/apache/geronimo/config/tck/ConfigSourceProviderTest.java deleted file mode 100644 index bf90fe8..0000000 --- a/tck/src/main/java/org/apache/geronimo/config/tck/ConfigSourceProviderTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.apache.geronimo.config.tck; - -import javx.config.Config; -import javx.config.ConfigProvider; -import org.testng.Assert; -import org.testng.annotations.Test; - -/** - * @author Mark Struberg - */ -public class ConfigSourceProviderTest { - - @Test - public void testConfigSourceProvider() { - Config config = ConfigProvider.getConfig(); - - Assert.assertEquals(config.getValue("tck.config.test.sampleyaml.key1"), "yamlvalue1"); - } -} diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/ConfigValueTest.java b/tck/src/main/java/org/apache/geronimo/config/tck/ConfigValueTest.java deleted file mode 100644 index 1d77279..0000000 --- a/tck/src/main/java/org/apache/geronimo/config/tck/ConfigValueTest.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.apache.geronimo.config.tck; - -import javx.config.Config; -import javx.config.ConfigProvider; -import javx.config.ConfigValue; -import org.testng.Assert; -import org.testng.annotations.Test; - -import java.util.concurrent.TimeUnit; - -/** - * @author Mark Struberg - */ -public class ConfigValueTest { - - private Config config = ConfigProvider.getConfig(); - - @Test - public void testGetValue() { - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.key1").getValue(), "value1"); - } - - @Test - public void testGetValueWithDefault() { - ConfigValue cfga = config.access("tck.config.test.javaconfig.configvalue.withdefault.notexisting") - .as(Integer.class) - .withDefault(Integer.valueOf(1234)); - - Assert.assertEquals(cfga.getValue(), Integer.valueOf(1234)); - } - - @Test - public void testGetValueWithStringDefault() { - ConfigValue cfga = config.access("tck.config.test.javaconfig.configvalue.withdefault.notexisting") - .as(Integer.class) - .withStringDefault("1234"); - - Assert.assertEquals(cfga.getValue(), Integer.valueOf(1234)); - } - - @Test - public void testIntegerConverter() { - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.integer").as(Integer.class).getValue(), Integer.valueOf(1234)); - } - - @Test - public void testLongConverter() { - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.long").as(Long.class).getValue(), Long.valueOf(1234567890123456L)); - } - - @Test - public void testFloatConverter() { - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.float").as(Float.class).getValue(), Float.valueOf(12.34f)); - } - - @Test - public void testDoubleonverter() { - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.double").as(Double.class).getValue(), Double.valueOf(12.34567890123456)); - } - - @Test - public void testBooleanConverter() { - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.true").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.true_uppercase").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.true_mixedcase").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.false").as(Boolean.class).getValue(), Boolean.FALSE); - - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.one").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.zero").as(Boolean.class).getValue(), Boolean.FALSE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.seventeen").as(Boolean.class).getValue(), Boolean.FALSE); - - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.yes").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.yes_uppercase").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.yes_mixedcase").as(Boolean.class).getValue(), Boolean.TRUE); - - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.y").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.y_uppercase").as(Boolean.class).getValue(), Boolean.TRUE); - - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.ja").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.ja_uppercase").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.ja_mixedcase").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.no_mixedcase").as(Boolean.class).getValue(), Boolean.FALSE); - - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.j").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.j_uppercase").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.n_uppercase").as(Boolean.class).getValue(), Boolean.FALSE); - - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.oui").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.oui_uppercase").as(Boolean.class).getValue(), Boolean.TRUE); - Assert.assertEquals(config.access("tck.config.test.javaconfig.configvalue.boolean.oui_mixedcase").as(Boolean.class).getValue(), Boolean.TRUE); - } - - @Test - public void testCacheFor() throws Exception { - String key = "tck.config.cachefor.key"; - System.setProperty(key, "firstvalue"); - ConfigValue val = config.access(key).cacheFor(30, TimeUnit.MILLISECONDS); - Assert.assertEquals(val.getValue(), "firstvalue"); - - // immediately change the value - System.setProperty(key, "secondvalue"); - - // we should still see the first value, because it is cached! - Assert.assertEquals(val.getValue(), "firstvalue"); - - // but now let's wait a bit - Thread.sleep(40); - Assert.assertEquals(val.getValue(), "secondvalue"); - } - - @Test - public void testWithVariable() throws Exception { - ConfigValue val = config.access("tck.config.test.javaconfig.configvalue.withvariable.key").evaluateVariables(true); - Assert.assertEquals(val.getValue(), "This key needs the perfect value!"); - } -} diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/ConverterTest.java b/tck/src/main/java/org/apache/geronimo/config/tck/ConverterTest.java deleted file mode 100644 index d5497bb..0000000 --- a/tck/src/main/java/org/apache/geronimo/config/tck/ConverterTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 org.apache.geronimo.config.tck; - -import javx.config.Config; -import javx.config.ConfigProvider; -import org.apache.geronimo.config.tck.converters.DuckConverter; -import org.testng.Assert; -import org.testng.annotations.Test; - -/** - * @author Mark Struberg - */ -public class ConverterTest { - - @Test - public void testIntegerConverter() { - Config config = ConfigProvider.getConfig(); - Integer value = config.access("tck.config.test.javaconfig.converter.integervalue").as(Integer.class).getValue(); - Assert.assertEquals(value, Integer.valueOf(1234)); - - } - - @Test - public void testFloatConverter() { - Config config = ConfigProvider.getConfig(); - Float value = config.access("tck.config.test.javaconfig.converter.floatvalue").as(Float.class).getValue(); - Assert.assertEquals(value, Float.valueOf(12.34f)); - - } - - @Test - public void testManuallyAddedConverter() { - Config config = ConfigProvider.getConfig(); - - config.addConverter(new DuckConverter()); - } - - - -} diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/CustomConfigSourceTest.java b/tck/src/main/java/org/apache/geronimo/config/tck/CustomConfigSourceTest.java deleted file mode 100644 index abcb2a1..0000000 --- a/tck/src/main/java/org/apache/geronimo/config/tck/CustomConfigSourceTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.apache.geronimo.config.tck; - -import javx.config.Config; -import javx.config.ConfigProvider; -import org.testng.Assert; -import org.testng.annotations.Test; - -/** - * @author Mark Struberg - */ -public class CustomConfigSourceTest { - - @Test - public void testConfigSourceProvider() { - Config config = ConfigProvider.getConfig(); - - Assert.assertEquals(config.getValue("tck.config.test.customDbConfig.key1"), "valueFromDb1"); - } -} diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/configfilters/PasswordConfigFilter.java b/tck/src/main/java/org/apache/geronimo/config/tck/configfilters/PasswordConfigFilter.java deleted file mode 100644 index 1d472e8..0000000 --- a/tck/src/main/java/org/apache/geronimo/config/tck/configfilters/PasswordConfigFilter.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 org.apache.geronimo.config.tck.configfilters; - -import javx.config.spi.ConfigFilter; - -/** - * @author Mark Struberg - */ -public class PasswordConfigFilter implements ConfigFilter { - @Override - public String filterValue(String key, String value) { - if (value != null && key.endsWith(".password")) { - return decrypt(value); - } - return value; - } - - @Override - public String filterValueForLog(String key, String value) { - if (value != null && - (key.contains("password") || key.contains("secret"))) { - return "*******"; // simply star-out the password - } - return value; - } - - private String decrypt(String value) { - // Just to modify the string. - // In reality the 'encryption' should be a bit stronger ;) - return value.toLowerCase(); - } -} diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/configsources/CustomConfigSourceProvider.java b/tck/src/main/java/org/apache/geronimo/config/tck/configsources/CustomConfigSourceProvider.java deleted file mode 100644 index d14bbb9..0000000 --- a/tck/src/main/java/org/apache/geronimo/config/tck/configsources/CustomConfigSourceProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 org.apache.geronimo.config.tck.configsources; - -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; - -import javx.config.spi.ConfigSource; -import javx.config.spi.ConfigSourceProvider; - -/** - * @author Mark Struberg - */ -public class CustomConfigSourceProvider implements ConfigSourceProvider { - @Override - public List getConfigSources(ClassLoader forClassLoader) { - List detectedConfigSources = new ArrayList<>(); - - Enumeration yamlFiles = null; - try { - yamlFiles = forClassLoader.getResources("sampleconfig.yaml"); - } catch (IOException e) { - throw new RuntimeException(e); - } - while (yamlFiles.hasMoreElements()) { - detectedConfigSources.add(new SampleYamlConfigSource(yamlFiles.nextElement())); - } - return detectedConfigSources; - } -} diff --git a/tck/src/main/java/org/apache/geronimo/config/tck/configsources/CustomDbConfigSource.java b/tck/src/main/java/org/apache/geronimo/config/tck/configsources/CustomDbConfigSource.java deleted file mode 100644 index 46c0934..0000000 --- a/tck/src/main/java/org/apache/geronimo/config/tck/configsources/CustomDbConfigSource.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 org.apache.geronimo.config.tck.configsources; - -import java.util.HashMap; -import java.util.Map; - -import javx.config.spi.ConfigSource; - -/** - * @author Mark Struberg - */ -public class CustomDbConfigSource implements ConfigSource { - - private Map configValues = new HashMap<>(); - - public CustomDbConfigSource() { - configValues.put("tck.config.test.customDbConfig.key1", "valueFromDb1"); - configValues.put("tck.config.test.customDbConfig.key2", "valueFromDb2"); - } - - @Override - public int getOrdinal() { - return 112; - } - - @Override - public Map getProperties() { - return readPropertiesFromDb(); - } - - @Override - public String getPropertyValue(String key) { - return readPropertyFromDb(key); - } - - @Override - public String getConfigName() { - return "customDbConfig"; - } - - @Override - public boolean isScannable() { - return true; - } - - private Map readPropertiesFromDb() { - return configValues; - } - - private String readPropertyFromDb(String key) { - return configValues.get(key); - } -} diff --git a/tck/src/main/resources/META-INF/java-config.properties b/tck/src/main/resources/META-INF/java-config.properties deleted file mode 100644 index 02d6826..0000000 --- a/tck/src/main/resources/META-INF/java-config.properties +++ /dev/null @@ -1,56 +0,0 @@ -tck.config.test.javaconfig.properties.key1=VALue1 - - -tck.config.test.overwritten.in.custompropertyfile.key1=value from java-config.properties - - -tck.config.test.javaconfig.configfilter.my.secret = SOME_SECRET -tck.config.test.javaconfig.configfilter.my.password = SOME_PASSWORD - -tck.config.test.javaconfig.converter.integervalue = 1234 -tck.config.test.javaconfig.converter.floatvalue = 12.34 - - -tck.config.test.javaconfig.configvalue.key1=value1 - -# test BooleanConverter START -tck.config.test.javaconfig.configvalue.boolean.true=true -tck.config.test.javaconfig.configvalue.boolean.true_uppercase=TRUE -tck.config.test.javaconfig.configvalue.boolean.true_mixedcase=TruE -tck.config.test.javaconfig.configvalue.boolean.false=false - -tck.config.test.javaconfig.configvalue.boolean.one=1 -tck.config.test.javaconfig.configvalue.boolean.zero=0 -tck.config.test.javaconfig.configvalue.boolean.seventeen=17 - -tck.config.test.javaconfig.configvalue.boolean.yes=yes -tck.config.test.javaconfig.configvalue.boolean.yes_uppercase=YES -tck.config.test.javaconfig.configvalue.boolean.yes_mixedcase=Yes - -tck.config.test.javaconfig.configvalue.boolean.y=y -tck.config.test.javaconfig.configvalue.boolean.y_uppercase=Y - -tck.config.test.javaconfig.configvalue.boolean.ja=ja -tck.config.test.javaconfig.configvalue.boolean.ja_uppercase=ja -tck.config.test.javaconfig.configvalue.boolean.ja_mixedcase=Ja -tck.config.test.javaconfig.configvalue.boolean.no_mixedcase=No - -tck.config.test.javaconfig.configvalue.boolean.j=j -tck.config.test.javaconfig.configvalue.boolean.j_uppercase=J -tck.config.test.javaconfig.configvalue.boolean.n_uppercase=N - -tck.config.test.javaconfig.configvalue.boolean.oui=oui -tck.config.test.javaconfig.configvalue.boolean.oui_uppercase=OUI -tck.config.test.javaconfig.configvalue.boolean.oui_mixedcase=Oui -# test BooleanConverter END - -# various other converter -tck.config.test.javaconfig.configvalue.integer=1234 -tck.config.test.javaconfig.configvalue.long=1234567890123456 -tck.config.test.javaconfig.configvalue.float=12.34 -tck.config.test.javaconfig.configvalue.double=12.34567890123456 - - -# withVariable -tck.config.test.javaconfig.configvalue.variable = the perfect value -tck.config.test.javaconfig.configvalue.withvariable.key = This key needs ${tck.config.test.javaconfig.configvalue.variable}! \ No newline at end of file diff --git a/tck/src/main/resources/META-INF/services/javx.config.spi.ConfigFilter b/tck/src/main/resources/META-INF/services/javx.config.spi.ConfigFilter deleted file mode 100644 index 7c75d4e..0000000 --- a/tck/src/main/resources/META-INF/services/javx.config.spi.ConfigFilter +++ /dev/null @@ -1 +0,0 @@ -org.apache.geronimo.config.tck.configfilters.PasswordConfigFilter \ No newline at end of file diff --git a/tck/src/main/resources/META-INF/services/javx.config.spi.ConfigSource b/tck/src/main/resources/META-INF/services/javx.config.spi.ConfigSource deleted file mode 100644 index 60f1da5..0000000 --- a/tck/src/main/resources/META-INF/services/javx.config.spi.ConfigSource +++ /dev/null @@ -1 +0,0 @@ -org.apache.geronimo.config.tck.configsources.CustomDbConfigSource \ No newline at end of file diff --git a/tck/src/main/resources/META-INF/services/javx.config.spi.ConfigSourceProvider b/tck/src/main/resources/META-INF/services/javx.config.spi.ConfigSourceProvider deleted file mode 100644 index a3c6d8a..0000000 --- a/tck/src/main/resources/META-INF/services/javx.config.spi.ConfigSourceProvider +++ /dev/null @@ -1 +0,0 @@ -org.apache.geronimo.config.tck.configsources.CustomConfigSourceProvider \ No newline at end of file diff --git a/tck/src/main/resources/META-INF/services/javx.config.spi.PropertyFileConfig b/tck/src/main/resources/META-INF/services/javx.config.spi.PropertyFileConfig deleted file mode 100644 index 20aa208..0000000 --- a/tck/src/main/resources/META-INF/services/javx.config.spi.PropertyFileConfig +++ /dev/null @@ -1 +0,0 @@ -org.apache.geronimo.config.tck.configsources.CustomPropertyFileConfig \ No newline at end of file diff --git a/tck/src/main/resources/sampleconfig.yaml b/tck/src/main/resources/sampleconfig.yaml deleted file mode 100644 index 7769f0c..0000000 --- a/tck/src/main/resources/sampleconfig.yaml +++ /dev/null @@ -1,2 +0,0 @@ -# just needed as a trigger for the ConfigSource pickup. -# Content is hardcoded in SampleYamlConfigSource \ No newline at end of file diff --git a/tck/src/main/resources/some/custom.properties b/tck/src/main/resources/some/custom.properties deleted file mode 100644 index 739ec20..0000000 --- a/tck/src/main/resources/some/custom.properties +++ /dev/null @@ -1,7 +0,0 @@ -# a bit higher than the default, to guarantee overwriting values from java-config.properties -config_ordinal = 110 - -tck.config.test.propertyfileconfig.custom.key1=value1 - - -tck.config.test.overwritten.in.custompropertyfile.key1=value from some/custom.properties \ No newline at end of file