| /* |
| * 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.tamaya; |
| |
| import org.apache.tamaya.spi.ConfigurationBuilder; |
| import org.apache.tamaya.spi.ConfigurationContext; |
| import org.apache.tamaya.spi.ConfigurationProviderSpi; |
| import org.apache.tamaya.spi.ServiceContextManager; |
| |
| import java.util.*; |
| import java.util.function.Function; |
| import java.util.function.UnaryOperator; |
| |
| |
| /** |
| * <p>A configuration models an aggregated set of current properties, identified by |
| * a unique key, but adds higher level access functions to |
| * a {@link org.apache.tamaya.spi.PropertySource}. Hereby in most |
| * cases a configuration is a wrapper around a composite |
| * {@link org.apache.tamaya.spi.PropertySource} instance, which may combine |
| * multiple child configurations in a well defined tree like structure, |
| * where nodes define logically the rules' current priority, filtering, |
| * combination and overriding. |
| * </p> |
| * <h3>Implementation Requirements</h3> |
| * Implementations of this interface must be |
| * <ul> |
| * <li>Thread safe</li> |
| * <li>Immutable</li> |
| * </ul> |
| * |
| * <p>It is not recommended that implementations also are serializable, since the any configuration can be <i>frozen</i> |
| * by reading out its complete configuration map into a serializable and remotable structure. This helps significantly |
| * by simplifying the development of this interface, e.g. for being backed up by systems and stores that are not part of |
| * this library at all.</p> |
| */ |
| public interface Configuration { |
| |
| /** |
| * Access a property. |
| * |
| * @param key the property's key, not {@code null}. |
| * @return the property's value. |
| */ |
| default String get(String key){ |
| return get(key, TypeLiteral.of(String.class)); |
| } |
| |
| /** |
| * Access a property. |
| * |
| * @param keys the property's keys, in order of evaluation, not {@code null}. |
| * @return the property's value. |
| */ |
| default String get(Iterable<String> keys){ |
| return get(keys, TypeLiteral.of(String.class)); |
| } |
| |
| /** |
| * Access a property. |
| * |
| * @param key the property's key, not {@code null}. |
| * @param defaultValue value to be returned, if no value is present, not {@code null} |
| * @return the property's keys. |
| */ |
| default String getOrDefault(String key, String defaultValue){ |
| return getOrDefault(key, TypeLiteral.of(String.class), defaultValue); |
| } |
| |
| /** |
| * Access a property. |
| * |
| * @param keys the property's keys, in order of evaluation, not {@code null}. |
| * @param defaultValue value to be returned, if no value is present, not {@code null} |
| * @return the property's keys. |
| */ |
| default String getOrDefault(Iterable<String> keys, String defaultValue){ |
| return getOrDefault(keys, TypeLiteral.of(String.class), defaultValue); |
| } |
| |
| /** |
| * Access a String property, using an an {@link Optional} instance. |
| * |
| * @param key the property's key, not {@code null}. |
| * @return the property's keys. |
| */ |
| default Optional<String> getOptional(String key){ |
| return Optional.ofNullable(getOrDefault(key, String.class, null)); |
| } |
| |
| /** |
| * Access a String property, using an an {@link Optional} instance. |
| * |
| * @param keys the property's keys, in evaluation order, not {@code null}. |
| * @return the property's keys. |
| */ |
| default Optional<String> getOptional(Iterable<String> keys){ |
| return Optional.ofNullable(getOrDefault(keys, String.class, null)); |
| } |
| |
| /** |
| * Access a property, using an an {@link Optional} instance. |
| * |
| * @param key the property's key, not {@code null}. |
| * @param type the target type, not null. |
| * @param <T> the type of the class modeled by the type parameter |
| * @return the property's keys. |
| */ |
| default <T> Optional<T> getOptional(String key, Class<T> type){ |
| return Optional.ofNullable(getOrDefault(key, TypeLiteral.of(type), null)); |
| } |
| |
| /** |
| * Access a property, using an an {@link Optional} instance. |
| * |
| * @param keys the property's keys, in evaluation order, not {@code null}. |
| * @param type the target type, not null. |
| * @param <T> the type of the class modeled by the type parameter |
| * @return the property's keys. |
| */ |
| default <T> Optional<T> getOptional(Iterable<String> keys, Class<T> type){ |
| return Optional.ofNullable(getOrDefault(keys, TypeLiteral.of(type), null)); |
| } |
| |
| /** |
| * Access a property, using an an {@link Optional} instance. |
| * |
| * @param key the property's key, not {@code null}. |
| * @param type the target type, not null. |
| * @param <T> the type of the class modeled by the type parameter |
| * @return the property's keys. |
| */ |
| default <T> Optional<T> getOptional(String key, TypeLiteral<T> type){ |
| return Optional.ofNullable(getOrDefault(key, type, null)); |
| } |
| |
| /** |
| * Access a property, using an an {@link Optional} instance. |
| * |
| * @param keys the property's keys, in evaluation order, not {@code null}. |
| * @param type the target type, not null. |
| * @param <T> the type of the class modeled by the type parameter |
| * @return the property's keys. |
| */ |
| default <T> Optional<T> getOptional(Iterable<String> keys, TypeLiteral<T> type){ |
| return Optional.ofNullable(getOrDefault(keys, type, null)); |
| } |
| |
| /** |
| * Gets the property keys as type T. This will implicitly require a corresponding {@link |
| * org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T |
| * fromMap for the given String keys. |
| * |
| * @param <T> the type of the class modeled by the type parameter |
| * @param key the property's absolute, or relative path, e.g. {@code |
| * a/b/c/d.myProperty}, not {@code null}. |
| * @param type The target type required, not {@code null}. |
| * @param defaultValue value to be used, if no value is present, not {@code null} |
| * @return the property value, never {@code null}. |
| * @throws ConfigException if the keys could not be converted to the required target type. |
| */ |
| default <T> T getOrDefault(String key, Class<T> type, T defaultValue){ |
| return getOrDefault(key, TypeLiteral.of(type), defaultValue); |
| } |
| |
| /** |
| * Gets the property keys as type T. This will implicitly require a corresponding {@link |
| * org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T |
| * fromMap for the given String keys. |
| * |
| * @param <T> the type of the class modeled by the type parameter |
| * @param keys the property's keys, in evaluation order, not {@code null}. |
| * @param type The target type required, not {@code null}. |
| * @param defaultValue value to be used, if no value is present, not {@code null} |
| * @return the property value, never {@code null}. |
| * @throws ConfigException if the keys could not be converted to the required target type. |
| */ |
| default <T> T getOrDefault(Iterable<String> keys, Class<T> type, T defaultValue){ |
| return getOrDefault(keys, TypeLiteral.of(type), defaultValue); |
| } |
| |
| /** |
| * Gets the property keys as type T. This will implicitly require a corresponding {@link |
| * org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T |
| * fromMap for the given String keys. |
| * |
| * @param <T> the type of the class modeled by the type parameter |
| * @param key the property's absolute, or relative path, e.g. @code |
| * a/b/c/d.myProperty}. |
| * @param type The target type required, not {@code null}. |
| * @return the property value, never {@code null}. |
| * @throws ConfigException if the keys could not be converted to the required target type. |
| */ |
| default <T> T get(String key, Class<T> type){ |
| return get(key, TypeLiteral.of(type)); |
| } |
| |
| /** |
| * Gets the property keys as type T. This will implicitly require a corresponding {@link |
| * org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T |
| * fromMap for the given String keys. |
| * |
| * @param <T> the type of the class modeled by the type parameter |
| * @param keys the property's keys, in evaluation order, not {@code null}. |
| * @param type The target type required, not {@code null}. |
| * @return the property value, never {@code null}. |
| * @throws ConfigException if the keys could not be converted to the required target type. |
| */ |
| default <T> T get(Iterable<String> keys, Class<T> type){ |
| return get(keys, TypeLiteral.of(type)); |
| } |
| |
| |
| |
| /** |
| * Get the property keys as type T. This will implicitly require a corresponding {@link |
| * org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T |
| * literals for the given key. |
| * |
| * @param <T> the type of the type literal |
| * @param key the property's absolute, or relative path, e.g. @code |
| * a/b/c/d.myProperty}, not {@code null}. |
| * @param type The target type required, not {@code null}. |
| * @return the property value, never {@code null}. |
| * @throws ConfigException if the keys could not be converted to the required target type. |
| */ |
| <T> T get(String key, TypeLiteral<T> type); |
| |
| /** |
| * Get the property keys as type T. This will implicitly require a corresponding {@link |
| * org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T |
| * literals for the given key. |
| * |
| * @param <T> the type of the type literal |
| * @param keys the property's keys, in evaluation order, not {@code null}. |
| * @param type The target type required, not {@code null}. |
| * @return the property value, never {@code null}. |
| * @throws ConfigException if the keys could not be converted to the required target type. |
| */ |
| default <T> T get(Iterable<String> keys, TypeLiteral<T> type){ |
| for(String k:keys){ |
| T t = getOrDefault(k, type, null); |
| if(t!=null){ |
| return t; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Get the property keys as type T. This will implicitly require a corresponding {@link |
| * org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T |
| * literals for the given key. |
| * |
| * @param <T> the type of the type literal |
| * @param key the property's absolute, or relative path, e.g. |
| * {@code a/b/c/d.myProperty}, not {@code null}. |
| * @param type The target type required, not {@code null}. |
| * @param defaultValue default value to be used, if no value is present. |
| * @return the property value, never null. |
| * @throws ConfigException if the keys could not be converted to the required target type. |
| */ |
| <T> T getOrDefault(String key, TypeLiteral<T> type, T defaultValue); |
| |
| /** |
| * Get the property keys as type T. This will implicitly require a corresponding {@link |
| * org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T |
| * literals for the given key. |
| * |
| * @param <T> the type of the type literal |
| * @param keys the property's keys, in evaluation order, not {@code null}. |
| * @param type The target type required, not {@code null}. |
| * @param defaultValue default value to be used, if no value is present. |
| * @return the property value, never null. |
| * @throws ConfigException if the keys could not be converted to the required target type. |
| */ |
| default <T> T getOrDefault(Iterable<String> keys, TypeLiteral<T> type, T defaultValue){ |
| for(String k:keys){ |
| T t = getOrDefault(k, type, null); |
| if(t!=null){ |
| return t; |
| } |
| } |
| return defaultValue; |
| } |
| |
| /** |
| * Access all currently known configuration properties as a full {@code Map<String,String>}. |
| * Be aware that entries from non scannable parts of the registered {@link org.apache.tamaya.spi.PropertySource} |
| * instances may not be contained in the result, but nevertheless be accessible by calling one of the |
| * {@code current(...)} methods. |
| * @return all currently known configuration properties. |
| */ |
| Map<String,String> getProperties(); |
| |
| /** |
| * Extension point for adjusting configuration. |
| * |
| * @param operator A configuration operator, e.g. a filter, or an adjuster |
| * combining configurations, never {@code null}. |
| * @return the new adjusted configuration returned by the {@code operator}, never {@code null}. |
| * @deprecated use {@link #map(UnaryOperator)} |
| */ |
| @Deprecated |
| default Configuration with(ConfigOperator operator){ |
| Objects.requireNonNull(operator, "Operator must be given."); |
| return operator.operate(this); |
| } |
| |
| /** |
| * Extension point for adjusting configuration. |
| * |
| * @param operator A configuration operator, e.g. a filter, or an adjuster |
| * combining configurations, never {@code null}. |
| * @return the new adjusted configuration returned by the {@code operator}, never {@code null}. |
| */ |
| default Configuration map(UnaryOperator<Configuration> operator){ |
| Objects.requireNonNull(operator, "Operator must be given."); |
| return operator.apply(this); |
| } |
| |
| /** |
| * Query a configuration. |
| * |
| * @param <T> the type of the configuration. |
| * @param query the query, not {@code null}. |
| * @return the result returned by the {@code query}. |
| * @deprecated Use {@link #adapt(Function)} |
| */ |
| @Deprecated |
| default <T> T query(ConfigQuery<T> query){ |
| Objects.requireNonNull(query, "Query must be given."); |
| return query.query(this); |
| } |
| |
| /** |
| * Query a configuration. |
| * |
| * @param <T> the type of the configuration. |
| * @param query the query, not {@code null}. |
| * @return the result returned by the {@code query}. |
| */ |
| default <T> T adapt(Function<Configuration, T> query){ |
| Objects.requireNonNull(query, "Adapter must be given."); |
| return query.apply(this); |
| } |
| |
| /** |
| * Access a configuration's context. |
| * @return the configuration context, never null. |
| */ |
| ConfigurationContext getContext(); |
| |
| /** |
| * Create a snapshot, which contains the given keys. |
| * |
| * @param keys the keys, not null. If empty a full snapshot with all known keys is returned. |
| * @return a corresponding snapshot instance. |
| */ |
| ConfigurationSnapshot getSnapshot(Iterable<String> keys); |
| |
| /** |
| * Create a snapshot, which contains all known keys. |
| * |
| * @param keys the target key. If empty a full snapshot with all known keys is returned. |
| * @return a corresponding snapshot instance. |
| */ |
| default ConfigurationSnapshot getSnapshot(String... keys){ |
| return getSnapshot(Arrays.asList(keys)); |
| } |
| |
| /** |
| * Create a new builder using this instance as its base. |
| * @return a new builder, never null. |
| */ |
| default ConfigurationBuilder toBuilder() { |
| return ServiceContextManager.getServiceContext(Configuration.class.getClassLoader()) |
| .getService(ConfigurationProviderSpi.class).getConfigurationBuilder().setConfiguration(this); |
| } |
| |
| /** |
| * This method allows replacement of the current default {@link org.apache.tamaya.Configuration} with a new |
| * instance. It is the responsibility of the ConfigurationProvider to trigger |
| * corresponding update events for the current {@link org.apache.tamaya.Configuration}, so observing |
| * listeners can do whatever is appropriate to react to any given configuration change. |
| * |
| * @param config the new Configuration to be applied, not {@code null} |
| * @throws java.lang.UnsupportedOperationException if the current provider is read-only and |
| * does not support |
| * applying a new Configuration. |
| */ |
| static void setCurrent(Configuration config) { |
| ServiceContextManager.getServiceContext(Configuration.class.getClassLoader()) |
| .getService(ConfigurationProviderSpi.class).setConfiguration(config, Thread.currentThread().getContextClassLoader()); |
| } |
| |
| /** |
| * This method allows replacement of the current default {@link org.apache.tamaya.Configuration} with a new |
| * instance. It is the responsibility of the ConfigurationProvider to trigger |
| * corresponding update events for the current {@link org.apache.tamaya.Configuration}, so observing |
| * listeners can do whatever is appropriate to react to any given configuration change. |
| * |
| * @param config the new Configuration to be applied, not {@code null} |
| * @param classLoader the target classloader, not null. |
| * @throws java.lang.UnsupportedOperationException if the current provider is read-only and |
| * does not support |
| * applying a new Configuration. |
| */ |
| static void setCurrent(Configuration config, ClassLoader classLoader) { |
| ServiceContextManager.getServiceContext(Configuration.class.getClassLoader()) |
| .getService(ConfigurationProviderSpi.class).setConfiguration(config, classLoader); |
| } |
| |
| /** |
| * Access the configuration instance for the current thread's context classloader. |
| * @return the configuration instance, never null. |
| */ |
| static Configuration current(){ |
| return ServiceContextManager.getServiceContext(Configuration.class.getClassLoader()) |
| .getService(ConfigurationProviderSpi.class).getConfiguration(Thread.currentThread().getContextClassLoader()); |
| } |
| |
| /** |
| * Accesses the configuration for a given classloader. |
| * @param classloader the classloader, not null. |
| * @return the configuration instance, never null. |
| */ |
| static Configuration current(ClassLoader classloader){ |
| return ServiceContextManager.getServiceContext(Configuration.class.getClassLoader()) |
| .getService(ConfigurationProviderSpi.class).getConfiguration(classloader); |
| } |
| |
| /** |
| * Releases the configuration associated with the given classloader. |
| * @param classloader the classloader, not null. |
| * @return the released configuration, or null. |
| */ |
| static Configuration releaseConfiguration(ClassLoader classloader) { |
| return ServiceContextManager.getServiceContext(Configuration.class.getClassLoader()) |
| .getService(ConfigurationProviderSpi.class).releaseConfiguration(classloader); |
| } |
| |
| /** |
| * Access a new configuration builder initialized with the current thread's context classloader. |
| * @return the builder, never null. |
| */ |
| static ConfigurationBuilder createConfigurationBuilder(){ |
| return ServiceContextManager.getServiceContext(Configuration.class.getClassLoader()) |
| .getService(ConfigurationProviderSpi.class).getConfigurationBuilder(); |
| } |
| |
| |
| /** |
| * Immutable and reusable, thread-safe implementation of an empty propertySource. |
| */ |
| Configuration EMPTY = new Configuration() { |
| |
| @Override |
| public String get(String key) { |
| return null; |
| } |
| |
| @Override |
| public String getOrDefault(String key, String defaultValue) { |
| return defaultValue; |
| } |
| |
| @Override |
| public <T> T getOrDefault(String key, Class<T> type, T defaultValue) { |
| return defaultValue; |
| } |
| |
| @Override |
| public <T> T get(String key, Class<T> type) { |
| return null; |
| } |
| |
| @Override |
| public <T> T get(String key, TypeLiteral<T> type) { |
| return null; |
| } |
| |
| @Override |
| public <T> T getOrDefault(String key, TypeLiteral<T> type, T defaultValue) { |
| return defaultValue; |
| } |
| |
| @Override |
| public Map<String, String> getProperties() { |
| return Collections.emptyMap(); |
| } |
| |
| @Override |
| public ConfigurationContext getContext() { |
| return ConfigurationContext.EMPTY; |
| } |
| |
| @Override |
| public ConfigurationSnapshot getSnapshot(Iterable<String> keys) { |
| return ConfigurationSnapshot.EMPTY; |
| } |
| |
| @Override |
| public String toString(){ |
| return "Configuration<EMPTY>"; |
| } |
| }; |
| |
| } |