http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/AggregationPolicy.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/AggregationPolicy.java b/dormant/core/src/main/java/old/AggregationPolicy.java new file mode 100644 index 0000000..99be931 --- /dev/null +++ b/dormant/core/src/main/java/old/AggregationPolicy.java @@ -0,0 +1,133 @@ +/* +* 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.core.properties; + +import org.apache.tamaya.ConfigException; + +import java.util.logging.Logger; + +/** +* Policy that defines how the different configurations/property sources should be aggregated. +* This is done by a mapping function defined as follows: +* <pre> +* function f(key, value1, value2) -> result +* +* whereas +* +* key = the fully qualified property key, +* value1 = the value from the first configuration/property source (can be null) +* value2 = the value from the second configuration/property source (can be null) +* +* result = the value to be used in the aggregation, or null, which removed the +* key from the result. +* </pre> +* +* Of course, during this evaluation step additional actions can be taken, e.g. refer to #LOG_ERROR, which +* ignores duplicate entries, but also logs the conflict on severe/error level. +*/ +public interface AggregationPolicy { + + /** + * Method which decides how keys/values are aggregated. + * @param key the key current the entry, must not be {@code null}. + * @param currentValue the current keys, or {@code null}. + * @param newValue the new keys, never {@code null}. + * @return the target keys to be used in the resulting property set, or null, to remove the property. + */ + public String aggregate(String key, String currentValue, String newValue); + + /** Ignore overrides, only extend (additive). */ + public static final AggregationPolicy IGNORE_DUPLICATES = (k, v1, v2) -> v1 == null? v2 : v1; + + /** Combine multiple values into a comma separated list. */ + public static final AggregationPolicy COMBINE = (k, v1, v2) -> v1 != null && v2 != null ? v1 + ',' + v2: v2; + + /** + * Interpret later keys as override (additive and override), replacing + * the key loaded earlier/fromMap previous contained + * {@link org.apache.tamaya.PropertySource}. + */ + public static final AggregationPolicy OVERRIDE = (k, v1, v2) -> v2; + + /** + * Throw an exception, when keys are not disjunctive (strictly + * additive). + */ + public static final AggregationPolicy EXCEPTION = + (String key, String value, String newValue) -> { + if(value!=null && newValue!=null && !value.equals(newValue)){ + throw new ConfigException("Conflicting values encountered key="+key+", keys="+value+", newValue="+newValue); + } + return newValue; + }; + + /** + * Ignores any duplicates, but logs the conflict encountered to error/severe level. + */ + public static final AggregationPolicy LOG_ERROR = + (String key, String value, String newValue) -> { + if(value!=null && newValue!=null && !value.equals(newValue)){ + Logger.getLogger(AggregationPolicy.class.getName()) + .severe(() -> "Conflicting values encountered key=" + key + ", keys=" + value + ", newValue=" + newValue); + return value; + } + return newValue; + }; + + /** + * Ignores any duplicates, but logs the conflict encountered to info level. + */ + public static final AggregationPolicy LOG_WARNING = + (String key, String value, String newValue) -> { + if(value!=null && newValue!=null && !value.equals(newValue)){ + Logger.getLogger(AggregationPolicy.class.getName()) + .warning(() -> "Conflicting values encountered key=" + key + ", keys=" + value + ", newValue=" + newValue); + return value; + } + return newValue; + }; + + /** + * Ignores any duplicates, but logs the conflict encountered to info level. + */ + public static final AggregationPolicy LOG_INFO = + (String key, String value, String newValue) -> { + if(value!=null && newValue!=null && !value.equals(newValue)){ + Logger.getLogger(AggregationPolicy.class.getName()) + .info(() -> "Conflicting values encountered key=" + key + ", keys=" + value + ", newValue=" + newValue); + return value; + } + return newValue; + }; + + /** + * Ignores any duplicates, but logs the conflict encountered to debug/finest level. + */ + public static final AggregationPolicy LOG_DEBUG = + (String key, String value, String newValue) -> { + if(value!=null && newValue!=null && !value.equals(newValue)){ + Logger.getLogger(AggregationPolicy.class.getName()) + .finest(() -> "Conflicting values encountered key=" + key + ", keys=" + value + ", newValue=" + newValue); + return value; + } + return newValue; + }; + + +}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/BuildablePropertySource.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/BuildablePropertySource.java b/dormant/core/src/main/java/old/BuildablePropertySource.java new file mode 100644 index 0000000..847fbe9 --- /dev/null +++ b/dormant/core/src/main/java/old/BuildablePropertySource.java @@ -0,0 +1,60 @@ +/* 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. + */ +package org.apache.tamaya.core.properties; + +import org.apache.tamaya.PropertySource; + +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +/** + * Created by Anatole on 07.12.2014. + */ +class BuildablePropertySource implements PropertySource +{ + + private String name; + private PropertySource baseProvider; + + public BuildablePropertySource(String name, PropertySource baseProvider) { + this.name = Objects.requireNonNull(name); + this.baseProvider = Objects.requireNonNull(baseProvider); + } + + @Override + public Optional<String> get(String key) { + return this.baseProvider.get(key); + } + + @Override + public Map<String, String> getProperties() { + return this.baseProvider.getProperties(); + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String toString(){ + return "BuildablePropertyProvider -> " + getName(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/ConfigurationBuilder.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/ConfigurationBuilder.java b/dormant/core/src/main/java/old/ConfigurationBuilder.java new file mode 100644 index 0000000..6d50d0e --- /dev/null +++ b/dormant/core/src/main/java/old/ConfigurationBuilder.java @@ -0,0 +1,375 @@ +/* +* 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 old; + +import java.net.URL; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.BiFunction; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import org.apache.tamaya.Configuration; +import org.apache.tamaya.PropertySource; +import org.apache.tamaya.core.config.FreezedConfiguration; +import org.apache.tamaya.core.properties.AggregationPolicy; +import org.apache.tamaya.core.properties.PropertySourceBuilder; + +/** +* Builder for assembling non trivial {@link org.apache.tamaya.Configuration} instances. +*/ +public final class ConfigurationBuilder { + + /** + * The final meta info to be used, or null, if a default should be generated. + */ + private PropertySourceBuilder builderDelegate; + + /** + * Private singleton constructor. + */ + private ConfigurationBuilder(String name) { + this.builderDelegate = PropertySourceBuilder.of(name); + } + + /** + * Private singleton constructor. + */ + private ConfigurationBuilder(String name, PropertySource source) { + this.builderDelegate = PropertySourceBuilder.of(name, source); + } + + /** + * Private singleton constructor. + */ + private ConfigurationBuilder(PropertySource source) { + this.builderDelegate = PropertySourceBuilder.of(source); + } + + + /** + * Creates a new builder instance. + * + * @param provider the base provider to be used, not null. + * @return a new builder instance, never null. + */ + public static ConfigurationBuilder of(PropertySource provider) { + return new ConfigurationBuilder(provider); + } + + /** + * Creates a new builder instance. + * + * @param name the provider name, not null. + * @return a new builder instance, never null. + */ + public static ConfigurationBuilder of(String name) { + return new ConfigurationBuilder(Objects.requireNonNull(name)); + } + + /** + * Creates a new builder instance. + * + * @return a new builder instance, never null. + */ + public static ConfigurationBuilder of() { + return new ConfigurationBuilder("<noname>"); + } + + + + + /** + * Sets the aggregation policy to be used, when adding additional property sets. The policy will + * be active a slong as the builder is used or it is reset to another keys. + * + * @param aggregationPolicy the aggregation policy, not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder withAggregationPolicy(AggregationPolicy aggregationPolicy) { + this.builderDelegate.withAggregationPolicy(aggregationPolicy); + return this; + } + + /** + * Sets the meta info to be used for the next operation. + * + * @param name the name, not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder withName(String name) { + this.builderDelegate.withName(name); + return this; + } + + /** + * Adds the given providers with the current active {@link AggregationPolicy}. By + * default {@link AggregationPolicy#OVERRIDE} is used. + * @see #withAggregationPolicy(AggregationPolicy) + * @param providers providers to be added, not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder addProviders(PropertySource... providers) { + this.builderDelegate.addProviders(providers); + return this; + } + + /** + * Adds the given providers with the current active {@link AggregationPolicy}. By + * default {@link AggregationPolicy#OVERRIDE} is used. + * @see #withAggregationPolicy(AggregationPolicy) + * @param providers providers to be added, not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder addProviders(List<PropertySource> providers) { + this.builderDelegate.addProviders(providers); + return this; + } + + + /** + * Creates a new {@link org.apache.tamaya.PropertySource} using the given command line arguments and adds it + * using the current aggregation policy in place. + * + * @param args the command line arguments, not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder addArgs(String... args) { + this.builderDelegate.addArgs(args); + return this; + } + + /** + * Creates a new read-only {@link org.apache.tamaya.PropertySource} by reading the according path resources. The effective resources read + * hereby are determined by the {@code PathResolverService} configured into the {@code Bootstrap} SPI. + * Properties read are aggregated using the current aggregation policy active. + * + * @param paths the paths to be resolved by the {@code PathResolverService} , not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder addPaths(String... paths) { + this.builderDelegate.addPaths(paths); + return this; + } + + + /** + * Creates a new read-only {@link org.apache.tamaya.PropertySource} by reading the according path resources. The effective resources read + * hereby are determined by the {@code PathResolverService} configured into the {@code Bootstrap} SPI. + * Properties read are aggregated using the current aggregation policy active. + * + * @param paths the paths to be resolved by the {@code PathResolverService} , not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder addPaths(List<String> paths) { + this.builderDelegate.addPaths(paths); + return this; + } + + /** + * Creates a new read-only {@link org.apache.tamaya.PropertySource} by reading the according URL resources. + * Properties read are aggregated using the current aggregation policy active. + * + * @param urls the urls to be read, not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder addURLs(URL... urls) { + this.builderDelegate.addURLs(urls); + return this; + } + + /** + * Creates a new read-only {@link org.apache.tamaya.PropertySource} by reading the according URL resources. + * Properties read are aggregated using the current aggregation policy active. + * + * @param urls the urls to be read, not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder addURLs(List<URL> urls) { + this.builderDelegate.addURLs(urls); + return this; + } + + + /** + * Creates a new read-only {@link org.apache.tamaya.PropertySource} based on the given map. + * Properties read are aggregated using the current aggregation policy active. + * + * @param map the map to be added, not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder addMap(Map<String, String> map) { + this.builderDelegate.addMap(map); + return this; + } + + + /** + * Add the current environment properties. Aggregation is based on the current {@link AggregationPolicy} acvtive. + * + * @return the builder for chaining. + */ + public ConfigurationBuilder addEnvironmentProperties() { + this.builderDelegate.addEnvironmentProperties(); + return this; + } + + /** + * Add the current system properties. Aggregation is based on the current {@link AggregationPolicy} acvtive. + * + * @return the builder for chaining. + */ + public ConfigurationBuilder addSystemProperties() { + this.builderDelegate.addSystemProperties(); + return this; + } + + /** + * Adds the given {@link org.apache.tamaya.PropertySource} instances using the current {@link AggregationPolicy} + * active. + * + * @param providers the maps to be included, not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder aggregate(PropertySource... providers) { + this.builderDelegate.aggregate(providers); + return this; + } + + + /** + * Adds the given {@link org.apache.tamaya.PropertySource} instances using the current {@link AggregationPolicy} + * active. + * + * @param providers the maps to be included, not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder aggregate(List<PropertySource> providers) { + this.builderDelegate.aggregate(providers); + return this; + } + + + /** + * Intersetcs the current properties with the given {@link org.apache.tamaya.PropertySource} instance. + * + * @param providers the maps to be intersected, not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder intersect(PropertySource... providers) { + this.builderDelegate.intersect(providers); + return this; + } + + + /** + * Subtracts with the given {@link org.apache.tamaya.PropertySource} instance from the current properties. + * + * @param providers the maps to be subtracted, not null. + * @return the builder for chaining. + */ + public ConfigurationBuilder subtract(PropertySource... providers) { + this.builderDelegate.subtract(providers); + return this; + } + + + /** + * Filters the current properties based on the given predicate.. + * + * @param filter the filter to be applied, not null. + * @return the new filtering instance. + */ + public ConfigurationBuilder filter(Predicate<String> filter) { + this.builderDelegate.filter(filter); + return this; + } + + /** + * Filters the current {@link org.apache.tamaya.Configuration} with the given valueFilter. + * @param valueFilter the value filter, not null. + * @return the (dynamically) filtered source instance, never null. + */ + public ConfigurationBuilder filterValues(BiFunction<String, String, String> valueFilter){ + this.builderDelegate.filterValues(valueFilter); + return this; + } + + /** + * Creates a new contextual {@link org.apache.tamaya.PropertySource}. Contextual maps delegate to different instances current PropertyMap depending + * on the keys returned fromMap the isolationP + * + * @param mapSupplier the supplier creating new provider instances + * @param isolationKeySupplier the supplier providing contextual keys based on the current environment. + */ + public ConfigurationBuilder addContextual(Supplier<PropertySource> mapSupplier, + Supplier<String> isolationKeySupplier) { + this.builderDelegate.addContextual(mapSupplier, isolationKeySupplier); + return this; + } + + /** + * Replaces all keys in the current provider by the given map. + * + * @param replacementMap the map instance, that will replace all corresponding entries in {@code mainMap}, not null. + * @return the new delegating instance. + */ + public ConfigurationBuilder replace(Map<String, String> replacementMap) { + this.builderDelegate.replace(replacementMap); + return this; + } + + /** + * Build a new property provider based on the input. + * @return a new property provider, or null. + */ + public PropertySource buildPropertySource(){ + return this.builderDelegate.build(); + } + + /** + * Build a new property provider based on the input. + * @return a new property provider, or null. + */ + public Configuration build(){ + return this.buildPropertySource().toConfiguration(); + } + + /** + * Creates a {@link org.apache.tamaya.PropertySource} instance that is serializable and immutable, + * so it can be sent over a network connection. + * + * @return the freezed instance, never null. + */ + public PropertySource buildFreezedPropertySource() { + return this.builderDelegate.buildFrozen(); + } + + /** + * Creates a {@link org.apache.tamaya.PropertySource} instance that is serializable and immutable, + * so it can be sent over a network connection. + * + * @return the freezed instance, never null. + */ + public Configuration buildFreezed() { + return FreezedConfiguration.of(this.buildFreezedPropertySource().toConfiguration()); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/ConfigurationProviderSpi.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/ConfigurationProviderSpi.java b/dormant/core/src/main/java/old/ConfigurationProviderSpi.java new file mode 100644 index 0000000..26697ea --- /dev/null +++ b/dormant/core/src/main/java/old/ConfigurationProviderSpi.java @@ -0,0 +1,46 @@ +/* + * 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 old; + +import org.apache.tamaya.Configuration; + +/** +* This configuration provider SPI allows to register the effective factory logic to of and manage a configuration +* instance. Hereby the qualifiers determine the type current configuration. By default +*/ +public interface ConfigurationProviderSpi{ + + /** + * Returns the name current the configuration provided. + * @return the name current the configuration provided, not empty. + */ + String getConfigName(); + + /** + * Get the {@link Configuration}, if available. + * @return according configuration, or null, if none is available for the given environment. + */ + Configuration getConfiguration(); + + /** + * Reloads the provider for the current context. + */ + void reload(); + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/ContextualPropertySource.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/ContextualPropertySource.java b/dormant/core/src/main/java/old/ContextualPropertySource.java new file mode 100644 index 0000000..6290706 --- /dev/null +++ b/dormant/core/src/main/java/old/ContextualPropertySource.java @@ -0,0 +1,142 @@ +/* + * 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.core.properties; + +import org.apache.tamaya.*; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +/** + * Created by Anatole on 12.04.2014. + */ +class ContextualPropertySource implements PropertySource { + + private volatile Map<String,PropertySource> cachedMaps = new ConcurrentHashMap<>(); + + private Supplier<PropertySource> mapSupplier; + private Supplier<String> isolationKeySupplier; + private String name; + + + /** + * Creates a new contextual PropertyMap. Contextual maps delegate to different instances current PropertyMap depending + * on the keys returned fromMap the isolationP + * + * @param mapSupplier + * @param isolationKeySupplier + */ + public ContextualPropertySource(String name, Supplier<PropertySource> mapSupplier, Supplier<String> isolationKeySupplier){ + this.name = Optional.ofNullable(name).orElse("<noname>"); + Objects.requireNonNull(mapSupplier); + Objects.requireNonNull(isolationKeySupplier); + this.mapSupplier = mapSupplier; + this.isolationKeySupplier = isolationKeySupplier; + } + + /** + * This method provides the contextual Map for the current environment. Hereby, ba default, for each different + * key returned by the #isolationKeySupplier a separate PropertyMap instance is acquired fromMap the #mapSupplier. + * If the map supplier returns an instance it is cached in the local #cachedMaps. + * + * @return the current contextual PropertyMap. + */ + protected PropertySource getContextualMap(){ + String environmentKey = this.isolationKeySupplier.get(); + if(environmentKey == null){ + return PropertySource.EMPTY_PROPERTYSOURCE; + } + PropertySource map = this.cachedMaps.get(environmentKey); + if(map == null){ + synchronized(cachedMaps){ + map = this.cachedMaps.get(environmentKey); + if(map == null){ + map = this.mapSupplier.get(); + if(map == null){ + return PropertySource.EMPTY_PROPERTYSOURCE; + } + this.cachedMaps.put(environmentKey, map); + } + } + } + return map; + } + + @Override + public Map<String,String> getProperties(){ + return getContextualMap().getProperties(); + } + + @Override + public String getName(){ + return this.name; + } + + @Override + public Optional<String> get(String key){ + return getContextualMap().get(key); + } + + /** + * Access a cached PropertyMap. + * + * @param key the target environment key as returned by the environment key supplier, not null. + * @return the corresponding PropertyMap, or null. + */ + public PropertySource getCachedMap(String key){ + return this.cachedMaps.get(key); + } + + /** + * Access the set current currently loaded/cached maps. + * + * @return the set current cached map keys, never null. + */ + public Set<String> getCachedMapKeys(){ + return this.cachedMaps.keySet(); + } + + /** + * Access the supplier for environment key, determining map isolation. + * + * @return the environment key supplier instance, not null. + */ + public Supplier<String> getIsolationKeySupplier(){ + return this.isolationKeySupplier; + } + + /** + * Access the supplier for new PropertyMap instances. + * + * @return the PropertyMap supplier instance, not null. + */ + public Supplier<PropertySource> getMapSupplier(){ + return this.mapSupplier; + } + + @Override + public String toString(){ + return "ContextualMap{" + + "cachedMaps(key)=" + cachedMaps.keySet() + + ", mapSupplier=" + mapSupplier + + ", isolationKeySupplier=" + isolationKeySupplier + + '}'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/DefaultConfigurationSpi.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/DefaultConfigurationSpi.java b/dormant/core/src/main/java/old/DefaultConfigurationSpi.java new file mode 100644 index 0000000..fe9f788 --- /dev/null +++ b/dormant/core/src/main/java/old/DefaultConfigurationSpi.java @@ -0,0 +1,116 @@ +/* + * 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 old; + +import java.lang.reflect.Proxy; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tamaya.ConfigException; +import org.apache.tamaya.Configuration; +import org.apache.tamaya.core.internal.config.FallbackSimpleConfigProvider; +import org.apache.tamaya.core.internal.el.DefaultExpressionEvaluator; +import org.apache.tamaya.core.internal.inject.ConfigTemplateInvocationHandler; +import org.apache.tamaya.core.internal.inject.ConfigurationInjector; +import org.apache.tamaya.core.spi.ExpressionEvaluator; +import org.apache.tamaya.spi.ConfigurationSpi; +import org.apache.tamaya.spi.ServiceContext; + + +/** + * Default SPI that implements the behaviour of {@link org.apache.tamaya.spi.ConfigurationSpi}. + */ +@SuppressWarnings("unchecked") +public class DefaultConfigurationSpi implements ConfigurationSpi { + + private static final String DEFAULT_CONFIG_NAME = "default"; + + private Map<String, ConfigurationProviderSpi> configProviders = new ConcurrentHashMap<>(); + + private ExpressionEvaluator expressionEvaluator = loadEvaluator(); + + private ExpressionEvaluator loadEvaluator() { + ExpressionEvaluator eval = ServiceContext.getInstance().getService(ExpressionEvaluator.class).orElse(null); + if (eval == null) { + eval = new DefaultExpressionEvaluator(); + } + return eval; + } + + public DefaultConfigurationSpi() { + if(configProviders.isEmpty()) { + for (ConfigurationProviderSpi spi : ServiceContext.getInstance().getServices(ConfigurationProviderSpi.class, Collections.emptyList())) { + configProviders.put(spi.getConfigName(), spi); + } + } + } + + @Override + public <T> T createTemplate(Class<T> type, Configuration... configurations) { + ClassLoader cl = Optional.ofNullable(Thread.currentThread() + .getContextClassLoader()).orElse(getClass().getClassLoader()); + return (T) Proxy.newProxyInstance(cl, new Class[]{type}, new ConfigTemplateInvocationHandler(type, configurations)); + } + + /** + * + * @param instance the instance with configuration annotations, not null. + * @param configurations the configurations to be used for evaluating the values for injection into {@code instance}. + * If no items are passed, the default configuration is used. + */ + @Override + public void configure(Object instance, Configuration... configurations) { + ConfigurationInjector.configure(instance, configurations); + } + + + @Override + public String evaluateValue(String expression, Configuration... configurations) { + return expressionEvaluator.evaluate(expression, configurations); + } + + @Override + public boolean isConfigurationAvailable(String name) { + ConfigurationProviderSpi spi = this.configProviders.get(name); + return spi != null; + } + + @Override + public Configuration getConfiguration(String name) { + ConfigurationProviderSpi provider = configProviders.get(name); + if (provider == null) { + if (DEFAULT_CONFIG_NAME.equals(name)) { + provider = new FallbackSimpleConfigProvider(); + configProviders.put(DEFAULT_CONFIG_NAME, provider); + } else { + throw new ConfigException("No such config: " + name); + } + } + Configuration config = provider.getConfiguration(); + if (config == null) { + throw new ConfigException("No such config: " + name); + } + return config; + } + + + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/DefaultServiceComparator.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/DefaultServiceComparator.java b/dormant/core/src/main/java/old/DefaultServiceComparator.java new file mode 100644 index 0000000..f284426 --- /dev/null +++ b/dormant/core/src/main/java/old/DefaultServiceComparator.java @@ -0,0 +1,85 @@ +/* + * 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 old; + +import java.util.*; + +/** + * Simple comparator based on a Collection of {@link OrdinalProvider} instances. + */ +final class DefaultServiceComparator implements Comparator<Object>{ + + /** + * List of ordinal providers loaded. + */ + private List<OrdinalProvider> ordinalProviders = new ArrayList<>(); + + DefaultServiceComparator(Collection<? extends OrdinalProvider> providers){ + ordinalProviders.addAll(Objects.requireNonNull(providers)); + ordinalProviders.sort(this::compare); + } + + private int compare(OrdinalProvider provider1, OrdinalProvider provider2){ + int o1 = getOrdinal(provider1); + int o2 = getOrdinal(provider2); + int order = o1-o2; + if(order < 0){ + return -1; + } + else if(order > 0){ + return 1; + } + return 0; + } + + private int getOrdinal(OrdinalProvider provider){ + if(provider instanceof Orderable){ + return ((Orderable)provider).order(); + } + return 0; + } + + public int getOrdinal(Object service){ + for(OrdinalProvider provider: ordinalProviders){ + OptionalInt ord = provider.getOrdinal(service.getClass()); + if(ord.isPresent()){ + return ord.getAsInt(); + } + } + if(service instanceof Orderable){ + return ((Orderable)service).order(); + } + return 0; + } + + + @Override + public int compare(Object o1, Object o2) { + int ord1 = getOrdinal(o1); + int ord2 = getOrdinal(o2); + int order = ord1-ord2; + if(order < 0){ + return -1; + } + else if(order > 0){ + return 1; + } + return 0; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/DefaultServiceContextProvider.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/DefaultServiceContextProvider.java b/dormant/core/src/main/java/old/DefaultServiceContextProvider.java new file mode 100644 index 0000000..ae02afd --- /dev/null +++ b/dormant/core/src/main/java/old/DefaultServiceContextProvider.java @@ -0,0 +1,112 @@ +/* + * 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 old; + +import org.apache.tamaya.spi.ServiceContext; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class implements the (default) {@link org.apache.tamaya.spi.ServiceContext} interface and hereby uses the JDK + * {@link java.util.ServiceLoader} to load the services required. + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +class DefaultServiceContextProvider implements ServiceContext { + /** List current services loaded, per class. */ + private final ConcurrentHashMap<Class, List<Object>> servicesLoaded = new ConcurrentHashMap<>(); + /** Singletons. */ + private final ConcurrentHashMap<Class, Optional<?>> singletons = new ConcurrentHashMap<>(); + /** Comparator for ordering of multiple services found. */ + private DefaultServiceComparator serviceComparator; + + public DefaultServiceContextProvider(){ + serviceComparator = new DefaultServiceComparator(getServices(OrdinalProvider.class, Collections.emptyList())); + } + + @Override + public <T> Optional<T> getService(Class<T> serviceType) { + Optional<T> cached = (Optional<T>)singletons.get(serviceType); + if(cached==null) { + List<? extends T> services = getServices(serviceType, Collections.emptyList()); + if (services.isEmpty()) { + cached = Optional.empty(); + } + else{ + cached = Optional.of(services.get(0)); + } + singletons.put(serviceType, cached); + } + return cached; + } + + /** + * Loads and registers services. + * + * @param serviceType + * The service type. + * @param <T> + * the concrete type. + * @param defaultList + * the list current items returned, if no services were found. + * @return the items found, never {@code null}. + */ + @Override + public <T> List<? extends T> getServices(final Class<T> serviceType, final List<? extends T> defaultList) { + List<T> found = (List<T>) servicesLoaded.get(serviceType); + if (found != null) { + return found; + } + return loadServices(serviceType, defaultList); + } + + /** + * Loads and registers services. + * + * @param serviceType The service type. + * @param <T> the concrete type. + * @param defaultList the list current items returned, if no services were found. + * + * @return the items found, never {@code null}. + */ + private <T> List<? extends T> loadServices(final Class<T> serviceType, final List<? extends T> defaultList) { + try { + List<T> services = new ArrayList<>(); + for (T t : ServiceLoader.load(serviceType)) { + services.add(t); + } + if(services.isEmpty()){ + services.addAll(defaultList); + } + if(!serviceType.equals(OrdinalProvider.class)) { + services.sort(serviceComparator); + } + services = Collections.unmodifiableList(services); + final List<T> previousServices = (List<T>) servicesLoaded.putIfAbsent(serviceType, (List<Object>)services); + return previousServices != null ? previousServices : services; + } catch (Exception e) { + Logger.getLogger(DefaultServiceContextProvider.class.getName()).log(Level.WARNING, + "Error loading services current type " + serviceType, e); + return defaultList; + } + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/DelegatingPropertySource.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/DelegatingPropertySource.java b/dormant/core/src/main/java/old/DelegatingPropertySource.java new file mode 100644 index 0000000..9cb9f57 --- /dev/null +++ b/dormant/core/src/main/java/old/DelegatingPropertySource.java @@ -0,0 +1,80 @@ +/* + * 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 old; + +import org.apache.tamaya.PropertySource; +import org.apache.tamaya.spi.PropertySource; + +import java.util.*; + +/** + * Implementation for a {@link org.apache.tamaya.PropertySource} that is an aggregate current + * multiple child instances. Controlled by an {@link org.apache.tamaya.AggregationPolicy} the + * following aggregations are supported: + * <ul> + * <li><b>IGNORE_DUPLICATES: </b>Ignore all overrides.</li> + * <li><b>: </b></li> + * <li><b>: </b></li> + * <li><b>: </b></li> + * </ul> + */ +class DelegatingPropertySource implements PropertySource { + + private PropertySource mainMap; + private Map<String,String> parentMap; + private String name; + + + /** + * Creates a mew instance, with aggregation polilcy + * {@code AggregationPolicy.OVERRIDE}. + * + * @param mainMap The main ConfigMap. + * @param parentMap The delegated parent ConfigMap. + */ + public DelegatingPropertySource(String name, PropertySource mainMap, Map<String, String> parentMap){ + this.name = Optional.of(name).orElse("<noname>"); + this.parentMap = Objects.requireNonNull(parentMap); + this.parentMap = Objects.requireNonNull(parentMap); + } + + @Override + public Map<String,String> getProperties(){ + return null; + } + + @Override + public String getName(){ + return this.name; + } + + @Override + public Optional<String> get(String key){ + Optional<String> val = mainMap.get(key); + if(!val.isPresent()){ + return Optional.ofNullable(parentMap.get(key)); + } + return val; + } + + @Override + public String toString(){ + return super.toString() + "(mainMap=" + mainMap + ", delegate=" + parentMap + ")"; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/EnvPropertiesConfigProvider.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/EnvPropertiesConfigProvider.java b/dormant/core/src/main/java/old/EnvPropertiesConfigProvider.java new file mode 100644 index 0000000..82306bb --- /dev/null +++ b/dormant/core/src/main/java/old/EnvPropertiesConfigProvider.java @@ -0,0 +1,54 @@ +/* + * 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 old; + +import org.apache.tamaya.core.properties.PropertySourceBuilder; +import old.ConfigurationProviderSpi; + +import org.apache.tamaya.Configuration; + +/** + * Provides a {@link org.apache.tamaya.Configuration} named 'environment.properties' + * containing the current environment properties. + * + * Created by Anatole on 29.09.2014. + */ +public class EnvPropertiesConfigProvider implements ConfigurationProviderSpi{ + + private Configuration envConfig; + + public EnvPropertiesConfigProvider(){ + envConfig = Configuration.from(PropertySourceBuilder.of("environment.properties").addEnvironmentProperties().build()); + } + + @Override + public String getConfigName(){ + return "environment.properties"; + } + + @Override + public Configuration getConfiguration(){ + return envConfig; + } + + @Override + public void reload() { + // nothing todo here + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/MappedConfiguration.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/MappedConfiguration.java b/dormant/core/src/main/java/old/MappedConfiguration.java new file mode 100644 index 0000000..43c63dc --- /dev/null +++ b/dormant/core/src/main/java/old/MappedConfiguration.java @@ -0,0 +1,57 @@ +package old; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.UnaryOperator; + +import org.apache.tamaya.Configuration; +import org.apache.tamaya.core.config.AbstractConfiguration; + +/** + * Configuration implementation that maps certain parts (defined by an {@code UnaryOperator<String>}) to alternate areas. + */ +class MappedConfiguration extends AbstractConfiguration implements Configuration { + + private static final long serialVersionUID = 8690637705511432083L; + + /** The mapping operator. */ + private UnaryOperator<String> keyMapper; + /** The base configuration. */ + private Configuration config; + + /** + * Creates a new instance. + * @param config the base configuration, not null + * @param keyMapper The mapping operator, not null + */ + public MappedConfiguration(Configuration config, UnaryOperator<String> keyMapper) { + super(config.getName()); + this.config = Objects.requireNonNull(config); + this.keyMapper = Objects.requireNonNull(keyMapper); + } + + @Override + public Map<String, String> getProperties() { + Map<String, String> result = new HashMap<>(); + Map<String, String> map = this.config.getProperties(); + map.forEach((k,v) -> { + String targetKey = keyMapper.apply(k); + if(targetKey!=null){ + result.put(targetKey, v); + } + }); + return result; + } + + @Override + public boolean isEmpty() { + return this.config.isEmpty(); + } + + @Override + public Configuration toConfiguration() { + return this; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/Orderable.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/Orderable.java b/dormant/core/src/main/java/old/Orderable.java new file mode 100644 index 0000000..13380a1 --- /dev/null +++ b/dormant/core/src/main/java/old/Orderable.java @@ -0,0 +1,34 @@ +/* + * 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 old; + +/** + * Interface that can be optionally implemented by SPI components to be loaded into + * the Tamaya's ServiceContext. The ordinal provided will be used to determine + * priority and precedence, when multiple components implement the same + * service interface. + */ +@FunctionalInterface +public interface Orderable { + /** + * Get the ordinal keys for the component, by default 0. + * @return the ordinal keys + */ + int order(); +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/OrdinalProvider.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/OrdinalProvider.java b/dormant/core/src/main/java/old/OrdinalProvider.java new file mode 100644 index 0000000..0152b84 --- /dev/null +++ b/dormant/core/src/main/java/old/OrdinalProvider.java @@ -0,0 +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 old; + +import java.util.OptionalInt; + +/** + * The ordinal provider is an optional component that provides an abstraction for ordering/prioritizing + * services loaded. This can be used to determine, which SPI should be used, if multiple instances are + * available, or for ordering chain of services. + * @see org.apache.tamaya.spi.ServiceContext + */ +public interface OrdinalProvider { + /** + * Evaluate the ordinal number for the given type. + * @param type the target type, not null. + * @return the ordinal, if not defined, 0 should be returned. + */ + OptionalInt getOrdinal(Class<?> type); + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/PropertyAdapterProviderSpi.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/PropertyAdapterProviderSpi.java b/dormant/core/src/main/java/old/PropertyAdapterProviderSpi.java new file mode 100644 index 0000000..65c31a7 --- /dev/null +++ b/dormant/core/src/main/java/old/PropertyAdapterProviderSpi.java @@ -0,0 +1,36 @@ +/* + * 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 old; + +import org.apache.tamaya.PropertyAdapter; + +/** + * This service provides different {@link org.apache.tamaya.PropertyAdapter} instances for types. + */ +public interface PropertyAdapterProviderSpi { + + /** + * Called, when a given {@link org.apache.tamaya.Configuration} has to be evaluated. + * + * @return the corresponding {@link java.util.function.Function<String, T>}, or {@code null}, if + * not available for the given target type. + */ + <T> PropertyAdapter<T> getPropertyAdapter(Class<T> type); + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/PropertyChangeSet.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/PropertyChangeSet.java b/dormant/core/src/main/java/old/PropertyChangeSet.java new file mode 100644 index 0000000..3cf6b31 --- /dev/null +++ b/dormant/core/src/main/java/old/PropertyChangeSet.java @@ -0,0 +1,169 @@ +/* + * 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.core.properties; + +import org.apache.tamaya.PropertySource; + +import java.beans.PropertyChangeEvent; +import java.io.Serializable; +import java.util.*; + +/** + * Event that contains a set current changes that were applied or could be applied. + * This class is immutable and thread-safe. To create instances use + * {@link PropertyChangeSetBuilder}. + * + * Created by Anatole on 22.10.2014. + */ +public final class PropertyChangeSet implements Serializable{ + + private static final long serialVersionUID = 1l; + /** The base property provider/configuration. */ + private PropertySource propertySource; + /** The base version, usable for optimistic locking. */ + private String baseVersion; + /** The recorded changes. */ + private Map<String,PropertyChangeEvent> changes = new HashMap<>(); + + /** + * Get an empty change set for the given provider. + * @param propertyProvider The base property provider/configuration, not null. + * @return an empty ConfigChangeSet instance. + */ + public static PropertyChangeSet emptyChangeSet(PropertySource propertyProvider){ + return new PropertyChangeSet(propertyProvider, Collections.emptySet()); + } + + /** + * Constructor used by {@link PropertyChangeSetBuilder}. + * @param propertySource The base property provider/configuration, not null. + * @param changes The recorded changes, not null. + */ + PropertyChangeSet(PropertySource propertySource, Collection<PropertyChangeEvent> changes) { + this.propertySource = Objects.requireNonNull(propertySource); + changes.forEach((c) -> this.changes.put(c.getPropertyName(), c)); + } + + /** + * Get the underlying property provider/configuration. + * @return the underlying property provider/configuration, never null. + */ + public PropertySource getPropertySource(){ + return this.propertySource; + } + + /** + * Get the base version, usable for optimistic locking. + * @return the base version. + */ + public String getBaseVersion(){ + return baseVersion; + } + + /** + * Get the changes recorded. + * @return the recorded changes, never null. + */ + public Collection<PropertyChangeEvent> getEvents(){ + return Collections.unmodifiableCollection(this.changes.values()); + } + + /** + * Access the number current removed entries. + * @return the number current removed entries. + */ + public int getRemovedSize() { + return (int) this.changes.values().stream().filter((e) -> e.getNewValue() == null).count(); + } + + /** + * Access the number current added entries. + * @return the number current added entries. + */ + public int getAddedSize() { + return (int) this.changes.values().stream().filter((e) -> e.getOldValue() == null).count(); + } + + /** + * Access the number current updated entries. + * @return the number current updated entries. + */ + public int getUpdatedSize() { + return (int) this.changes.values().stream().filter((e) -> e.getOldValue()!=null && e.getNewValue()!=null).count(); + } + + + /** + * Checks if the given key was removed. + * @param key the target key, not null. + * @return true, if the given key was removed. + */ + public boolean isRemoved(String key) { + PropertyChangeEvent change = this.changes.get(key); + return change != null && change.getNewValue() == null; + } + + /** + * Checks if the given key was added. + * @param key the target key, not null. + * @return true, if the given key was added. + */ + public boolean isAdded(String key) { + PropertyChangeEvent change = this.changes.get(key); + return change != null && change.getOldValue() == null; + } + + /** + * Checks if the given key was updated. + * @param key the target key, not null. + * @return true, if the given key was updated. + */ + public boolean isUpdated(String key) { + PropertyChangeEvent change = this.changes.get(key); + return change != null && change.getOldValue() != null && change.getNewValue() != null; + } + + /** + * Checks if the given key is added, or updated AND NOT removed. + * @param key the target key, not null. + * @return true, if the given key was added, or updated BUT NOT removed. + */ + public boolean containsKey(String key) { + PropertyChangeEvent change = this.changes.get(key); + return change != null && change.getNewValue() != null; + } + + /** + * CHecks if the current change set does not contain any changes. + * @return tru, if the change set is empty. + */ + public boolean isEmpty(){ + return this.changes.isEmpty(); + } + + + @Override + public String toString() { + return "ConfigChangeSet{" + + "properties=" + propertySource + + ", baseVersion=" + baseVersion + + ", changes=" + changes + + '}'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/PropertyChangeSetBuilder.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/PropertyChangeSetBuilder.java b/dormant/core/src/main/java/old/PropertyChangeSetBuilder.java new file mode 100644 index 0000000..b6e22f8 --- /dev/null +++ b/dormant/core/src/main/java/old/PropertyChangeSetBuilder.java @@ -0,0 +1,347 @@ +/* + * 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.core.properties; + +import org.apache.tamaya.PropertySource; + +import java.beans.PropertyChangeEvent; +import java.util.*; +import java.util.function.Function; + +/** + * Models a set current changes to be applied to a configuration/property provider. Such a set can be applied + * to any {@link org.apache.tamaya.PropertySource} instance. If the provider is mutable it may check the + * version given and applyChanges the changes to the provider/configuration, including triggering current regarding + * change events. + * <p> + * For appropriate conversion a {@code Function<String, Codec>} can be applied, which performs correct conversion, + * when changed values are set. This function enables connecting e.g. setters on a configuration template with + * the corresponding conversion logic, so the template calls are correctly converted back. + */ +public final class PropertyChangeSetBuilder { + /** + * The recorded changes. + */ + final SortedMap<String, PropertyChangeEvent> delta = new TreeMap<>(); + /** + * The underlying configuration/provider. + */ + PropertySource source; + + /** + * Constructor. + * + * @param source the underlying configuration/provider, not null. + */ + private PropertyChangeSetBuilder(PropertySource source) { + this.source = Objects.requireNonNull(source); + } + + /** + * Creates a new instance current this builder. + * + * @param source the underlying property provider/configuration, not null. + * @return the builder for chaining. + */ + public static PropertyChangeSetBuilder of(PropertySource source) { + return new PropertyChangeSetBuilder(source); + } + + /** + * This method records all changes to be applied to the base property provider/configuration to + * achieve the given target state. + * + * @param newState the new target state, not null. + * @return the builder for chaining. + */ + public PropertyChangeSetBuilder addChanges(PropertySource newState) { + compare(newState, this.source).forEach((c) -> this.delta.put(c.getPropertyName(), c)); + return this; + } + + /** + * Get the current values, also considering any changes recorded within this change set. + * + * @param key the key current the entry, not null. + * @return the keys, or null. + */ + public String get(String key) { + PropertyChangeEvent change = this.delta.get(key); + if (change != null && !(change.getNewValue() == null)) { + return (String) change.getNewValue(); + } + return null; + } + + /** + * Marks the given key(s) fromMap the configuration/properties to be removed. + * + * @param key the key current the entry, not null. + * @param otherKeys additional keys to be removed (convenience), not null. + * @return the builder for chaining. + */ + public PropertyChangeSetBuilder remove(String key, String... otherKeys) { + String oldValue = this.source.get(key).orElse(null); + if (oldValue == null) { + this.delta.remove(key); + } + this.delta.put(key, new PropertyChangeEvent(this.source, key, oldValue, null)); + for (String addKey : otherKeys) { + oldValue = this.source.get(addKey).orElse(null); + if (oldValue == null) { + this.delta.remove(addKey); + } + this.delta.put(addKey, new PropertyChangeEvent(this.source, addKey, oldValue, null)); + } + return this; + } + + /** + * Applies the given keys. + * + * @param key the key current the entry, not null. + * @param value the keys to be applied, not null. + * @return the builder for chaining. + */ + public PropertyChangeSetBuilder put(String key, boolean value) { + this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value))); + return this; + } + + /** + s* Applies the given keys. + * + * @param key the key current the entry, not null. + * @param value the keys to be applied, not null. + * @return the builder for chaining. + */ + public PropertyChangeSetBuilder put(String key, byte value) { + this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value))); + return this; + } + + /** + * Applies the given keys. + * + * @param key the key current the entry, not null. + * @param value the keys to be applied, not null. + * @return the builder for chaining. + */ + public PropertyChangeSetBuilder put(String key, char value) { + this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value))); + return this; + } + + /** + * Applies the given keys. + * + * @param key the key current the entry, not null. + * @param value the keys to be applied, not null. + * @return the builder for chaining. + */ + public PropertyChangeSetBuilder put(String key, short value) { + this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value))); + return this; + } + + /** + * Applies the given keys. + * + * @param key the key current the entry, not null. + * @param value the keys to be applied, not null. + * @return the builder for chaining. + */ + public PropertyChangeSetBuilder put(String key, int value) { + this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value))); + return this; + } + + /** + * Applies the given keys. + * + * @param key the key current the entry, not null. + * @param value the keys to be applied, not null. + * @return the builder for chaining. + */ + public PropertyChangeSetBuilder put(String key, long value) { + this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value))); + return this; + } + + /** + * Applies the given keys. + * + * @param key the key current the entry, not null. + * @param value the keys to be applied, not null. + * @return the builder for chaining. + */ + public PropertyChangeSetBuilder put(String key, float value) { + this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value))); + return this; + } + + /** + * Applies the given keys. + * + * @param key the key current the entry, not null. + * @param value the keys to be applied, not null. + * @return the builder for chaining. + */ + public PropertyChangeSetBuilder put(String key, double value) { + this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value))); + return this; + } + + + /** + * Applies the given keys. + * + * @param key the key current the entry, not null. + * @param value the keys to be applied, not null. + * @return the builder for chaining. + */ + public PropertyChangeSetBuilder put(String key, String value) { + this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value))); + return this; + } + + /** + * Applies the given keys. + * + * @param key the key current the entry, not null. + * @param value the keys to be applied, not null. + * @return the builder for chaining. + * @throws org.apache.tamaya.ConfigException if no matching Codec could be found. + */ + public <T> PropertyChangeSetBuilder put(String key, Class<T> type, T value) { + put(key, type, value, null); + return this; + } + + /** + * Applies the given keys. + * + * @param key the key current the entry, not null. + * @param value the keys to be applied, not null. + * @param adapter the codec to be used, if set overrides any other codecs that may apply. If null an appropriate + * codec is tried to be evaluated as needed. + * @return the builder for chaining. + * @throws org.apache.tamaya.ConfigException if no matching Codec could be found. + */ + public <T> PropertyChangeSetBuilder put(String key, Class<T> type, T value, Function<T,String> adapter) { + this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), adapter.apply(Objects.requireNonNull(value)))); + return this; + } + + + /** + * Apply all the given values to the base configuration/properties. + * Note that all values passed must be convertible to String, either + * <ul> + * <li>the registered codecs provider provides codecs for the corresponding keys, or </li> + * <li>default codecs are present for the given type, or</li> + * <li>the value is an instanceof String</li> + * </ul> + * + * @param changes the changes to be applied, not null. + * @return the builder for chaining. + */ + public PropertyChangeSetBuilder putAll(Map<String, String> changes) { + changes.putAll(changes); + return this; + } + + /** + * This method will create a change set that clears all entries fromMap the given base configuration/properties. + * + * @return the builder for chaining. + */ + public PropertyChangeSetBuilder deleteAll() { + this.delta.clear(); + this.source.getProperties().forEach((k, v) -> + this.delta.put(k, new PropertyChangeEvent(this.source, k, v, null))); + return this; + } + + /** + * Checks if the change set is empty, i.e. does not contain any changes. + * + * @return true, if the set is empty. + */ + public boolean isEmpty() { + return this.delta.isEmpty(); + } + + /** + * Resets this change set instance. This will clear all changes done to this builder, so the + * set will be empty. + */ + public void reset() { + this.delta.clear(); + } + + /** + * Builds the corresponding change set. + * + * @return the new change set, never null. + */ + public PropertyChangeSet build() { + return new PropertyChangeSet(this.source, Collections.unmodifiableCollection(this.delta.values())); + } + + /** + * Compares the two property config/configurations and creates a collection current all changes + * that must be appied to render {@code map1} into {@code map2}. + * + * @param map1 the source map, not null. + * @param map2 the target map, not null. + * @return a collection current change events, never null. + */ + public static Collection<PropertyChangeEvent> compare(PropertySource map1, PropertySource map2) { + List<PropertyChangeEvent> changes = new ArrayList<>(); + for (Map.Entry<String, String> en : map1.getProperties().entrySet()) { + Optional<String> val = map2.get(en.getKey()); + if (!val.isPresent()) { + changes.add(new PropertyChangeEvent(map1, en.getKey(), null, en.getValue())); + } else if (!val.get().equals(en.getValue())) { + changes.add(new PropertyChangeEvent(map1, en.getKey(), val.get(), en.getValue())); + } + } + for (Map.Entry<String, String> en : map2.getProperties().entrySet()) { + Optional<String> val = map1.get(en.getKey()); + if (!val.isPresent()) { + changes.add(new PropertyChangeEvent(map1, en.getKey(), null, en.getValue())); + } else if (!val.equals(Optional.ofNullable(en.getValue()))) { + changes.add(new PropertyChangeEvent(map1, en.getKey(), val.get(), en.getValue())); + } + } + return changes; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "PropertyChangeEventBuilder [source=" + source + ", " + + ", delta=" + delta + "]"; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/SubtractingPropertySource.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/SubtractingPropertySource.java b/dormant/core/src/main/java/old/SubtractingPropertySource.java new file mode 100644 index 0000000..f78ceb9 --- /dev/null +++ b/dormant/core/src/main/java/old/SubtractingPropertySource.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.tamaya.core.properties; + +import org.apache.tamaya.PropertySource; + +import java.util.*; +import java.util.stream.Collectors; + +class SubtractingPropertySource extends AbstractPropertySource { + + private static final long serialVersionUID = 4301042530074932562L; + private PropertySource unit; + private List<PropertySource> subtrahends; + + public SubtractingPropertySource(String name, PropertySource configuration, List<PropertySource> subtrahends){ + super(name); + Objects.requireNonNull(configuration); + this.unit = configuration; + this.subtrahends = new ArrayList<>(subtrahends); + } + + private boolean filter(Map.Entry<String,String> entry){ + for(PropertySource prov: subtrahends){ + if(prov.get(entry.getKey()).isPresent()){ + return false; + } + } + return true; + } + + @Override + public Map<String,String> getProperties(){ + return this.unit.getProperties().entrySet().stream().filter(this::filter).collect(Collectors.toMap( + Map.Entry::getKey, + Map.Entry::getValue + )); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/old/SystemPropertiesConfigProvider.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/old/SystemPropertiesConfigProvider.java b/dormant/core/src/main/java/old/SystemPropertiesConfigProvider.java new file mode 100644 index 0000000..30a0cf0 --- /dev/null +++ b/dormant/core/src/main/java/old/SystemPropertiesConfigProvider.java @@ -0,0 +1,54 @@ +/* + * 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 old; + +import org.apache.tamaya.core.properties.PropertySourceBuilder; +import old.ConfigurationProviderSpi; + +import org.apache.tamaya.Configuration; + +/** + * Provides a {@link org.apache.tamaya.Configuration} named 'system.properties' + * containing the current system properties. + * + * Created by Anatole on 29.09.2014. + */ +public class SystemPropertiesConfigProvider implements ConfigurationProviderSpi{ + + private Configuration systemConfig; + + public SystemPropertiesConfigProvider(){ + systemConfig = Configuration.from(PropertySourceBuilder.of("system.properties").addSystemProperties().build()); + } + + @Override + public String getConfigName(){ + return "system.properties"; + } + + @Override + public Configuration getConfiguration(){ + return systemConfig; + } + + @Override + public void reload() { + // nothing todo here + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/org/apache/tamaya/core/config/AbstractConfiguration.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/config/AbstractConfiguration.java b/dormant/core/src/main/java/org/apache/tamaya/core/config/AbstractConfiguration.java index 31179cd..8289d64 100644 --- a/dormant/core/src/main/java/org/apache/tamaya/core/config/AbstractConfiguration.java +++ b/dormant/core/src/main/java/org/apache/tamaya/core/config/AbstractConfiguration.java @@ -22,7 +22,7 @@ import java.util.Optional; import org.apache.tamaya.*; import org.apache.tamaya.core.properties.AbstractPropertySource; -import org.apache.tamaya.core.spi.PropertyAdapterProviderSpi; +import old.PropertyAdapterProviderSpi; import org.apache.tamaya.spi.ServiceContext; /** http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/core/src/main/java/org/apache/tamaya/core/config/ConfigFunctions.java ---------------------------------------------------------------------- diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/config/ConfigFunctions.java b/dormant/core/src/main/java/org/apache/tamaya/core/config/ConfigFunctions.java index c1a2518..7306fff 100644 --- a/dormant/core/src/main/java/org/apache/tamaya/core/config/ConfigFunctions.java +++ b/dormant/core/src/main/java/org/apache/tamaya/core/config/ConfigFunctions.java @@ -18,6 +18,7 @@ */ package org.apache.tamaya.core.config; +import old.MappedConfiguration; import org.apache.tamaya.ConfigQuery; import org.apache.tamaya.Configuration; import org.apache.tamaya.core.properties.PropertySourceBuilder;