http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/ConfigurationContextBuilder.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/ConfigurationContextBuilder.java b/code/old/api/src/main/java/org/apache/tamaya/spi/ConfigurationContextBuilder.java new file mode 100644 index 0000000..17c1bf4 --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/ConfigurationContextBuilder.java @@ -0,0 +1,336 @@ +/* + * 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.spi; + +import org.apache.tamaya.TypeLiteral; + +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +/** + * A builder for creating new or adapting instances of {@link ConfigurationContext}. + * Builders can be obtained in exactly two ways: + * <ol> + * <li>By accessing a preinitialized builder from an existing {@link ConfigurationContext}, + * by calling {@link org.apache.tamaya.spi.ConfigurationContext#toBuilder()}.</li> + * <li>By accessing an empty builder instance from + * {@link org.apache.tamaya.ConfigurationProvider#getConfigurationContextBuilder()}.</li> + * </ol> + * After all changes are applied to a builder a new {@link ConfigurationContext} instance can + * be created and can be applied by calling + * {@link org.apache.tamaya.ConfigurationProvider#setConfigurationContext(org.apache.tamaya.spi.ConfigurationContext)}. + * @deprecated Use {@link ConfigurationBuilder} instead. + */ +@Deprecated +public interface ConfigurationContextBuilder { + + /** + * Init this builder instance with the given {@link ConfigurationContext} instance. This + * method will use any existing property sources, filters, converters and the combination + * policy of the given {@link ConfigurationContext} and initialize the current builder + * with them. + * + * @param context the {@link ConfigurationContext} instance to be used, not {@code null}. + * @return this builder, for chaining, never null. + */ + ConfigurationContextBuilder setContext(ConfigurationContext context); + + /** + * This method can be used for adding {@link PropertySource}s. + * Hereby the property source is added to the tail of property sources with + * lowest priority regardless of its current ordinal value. To sort the property + * sources based on their ordinals call {@link #sortPropertySources}. + * + * @param propertySources the PropertySources to add + * @return this builder, for chaining, never null. + * @throws IllegalArgumentException If a property source with a given name already + * exists. + */ + ConfigurationContextBuilder addPropertySources(PropertySource... propertySources); + + /** + * This method can be used for programmatically adding {@link PropertySource}s. + * Hereby the property source is added to the tail of property sources with + * lowest priority regardless of its current ordinal value. To sort the property + * sources based on their ordinals call {@link #sortPropertySources}. + * + * @param propertySources the PropertySources to add + * @return this builder, for chaining, never null. + * @throws IllegalArgumentException If a property source with a given name already + * exists. + */ + ConfigurationContextBuilder addPropertySources(Collection<PropertySource> propertySources); + + /** + * Add all registered (default) property sources to the context built. The sources are ordered + * based on their ordinal values and added to the chain of property sources with + * higher priority. + * @return this builder, for chaining, never null. + */ + ConfigurationContextBuilder addDefaultPropertySources(); + + /** + * Removes the given property sources, if existing. The existing order of property + * sources is preserved. + * + * @param propertySources the property sources to remove, not {@code null}. + * @return the builder for chaining. + */ + ConfigurationContextBuilder removePropertySources(PropertySource... propertySources); + + /** + * Removes the given property sources, if existing. The existing order of property + * sources is preserved. + * + * @param propertySources the property sources to remove, not {@code null}. + * @return the builder for chaining. + */ + ConfigurationContextBuilder removePropertySources(Collection<PropertySource> propertySources); + + /** + * Access the current chain of property sources. Items at the end of the list have + * precedence/more significance. + * + * @return the property source chain, never {@code null}. + */ + List<PropertySource> getPropertySources(); + + /** + * Access the current chain of property filters. Items at the end of the list have + * precedence/more significance. + * + * @return the property source chain, never {@code null}. + */ + List<PropertyFilter> getPropertyFilters(); + + /** + * Access the current registered property converters. + * + * @return the current registered property converters. + */ + Map<TypeLiteral<?>, Collection<PropertyConverter<?>>> getPropertyConverter(); + + /** + * Increases the priority of the given property source, by moving it towards the end + * of the chain of property sources. If the property source given is already at the end + * this method has no effect. This operation does not change any ordinal values. + * + * @param propertySource the property source to be incresed regarding its significance. + * @return the builder for chaining. + * @throws IllegalArgumentException If no such property source exists in the current + * chain. + */ + ConfigurationContextBuilder increasePriority(PropertySource propertySource); + + /** + * Decreases the priority of the given property source, by moving it towards the start + * of the chain of property sources. If the property source given is already the first + * this method has no effect. This operation does not change any ordinal values. + * + * @param propertySource the property source to be decresed regarding its significance. + * @return the builder for chaining. + * @throws IllegalArgumentException If no such property source exists in the current + * chain. + */ + ConfigurationContextBuilder decreasePriority(PropertySource propertySource); + + /** + * Increases the priority of the given property source to be maximal, by moving it to + * the tail of the of property source chain. If the property source given is + * already the last item this method has no effect. This operation does not change + * any ordinal values. + * + * @param propertySource the property source to be maximized regarding its significance. + * @return the builder for chaining. + * @throws IllegalArgumentException If no such property source exists in the current + * chain. + */ + ConfigurationContextBuilder highestPriority(PropertySource propertySource); + + /** + * Decreases the priority of the given property source to be minimal, by moving it to + * the start of the chain of property source chain. If the property source given is + * already the first item this method has no effect. This operation does not change + * any ordinal values. + * + * @param propertySource the property source to be minimized regarding its significance. + * @return the builder for chaining. + * @throws IllegalArgumentException If no such property source exists in the current + * chain. + */ + ConfigurationContextBuilder lowestPriority(PropertySource propertySource); + + /** + * Adds the given PropertyFilter instances, hereby the instances are added + * to the end of the list with highest priority. The ordering of existing + * property filters remains unchanged. To sort the property + * filters call {@link #sortPropertyFilter}. + * + * @param filters the filters to add + * @return this builder, for chaining, never null. + */ + ConfigurationContextBuilder addPropertyFilters(PropertyFilter... filters); + + /** + * Adds the given PropertyFilter instances, hereby the instances are added + * to the end of the list with highest priority. The ordering of existing + * property filters remains unchanged. To sort the property + * filters call {@link #sortPropertyFilter}. + * + * @param filters the filters to add + * @return this builder, for chaining, never null. + */ + ConfigurationContextBuilder addPropertyFilters(Collection<PropertyFilter> filters); + + /** + * Add all registered (default) property filters to the context built. + * @return this builder, for chaining, never null. + */ + ConfigurationContextBuilder addDefaultPropertyFilters(); + + + /** + * Removes the given PropertyFilter instances, if existing. The order of the remaining + * filters is preserved. + * + * @param filters the filter to remove + * @return this builder, for chaining, never null. + */ + ConfigurationContextBuilder removePropertyFilters(PropertyFilter... filters); + + /** + * Removes the given PropertyFilter instances, if existing. The order of the remaining + * filters is preserved. + * + * @param filters the filter to remove + * @return this builder, for chaining, never null. + */ + ConfigurationContextBuilder removePropertyFilters(Collection<PropertyFilter> filters); + + /** + * This method can be used for adding {@link PropertyConverter}s. + * Converters are added at the end after any existing converters. + * For converters already registered for the current target type the + * method has no effect. + * + * @param typeToConvert the type for which the converters is for + * @param propertyConverters the PropertyConverters to add for this type + * @param <T> the target type. + * @return this builder, for chaining, never null. + */ + <T> ConfigurationContextBuilder addPropertyConverters(TypeLiteral<T> typeToConvert, + @SuppressWarnings("unchecked") PropertyConverter<T>... propertyConverters); + + /** + * This method can be used for adding {@link PropertyConverter}s. + * Converters are added at the end after any existing converters. + * For converters already registered for the current target type the + * method has no effect. + * + * @param typeToConvert the type for which the converters is for + * @param propertyConverters the PropertyConverters to add for this type + * @param <T> the target type. + * @return this builder, for chaining, never null. + */ + <T> ConfigurationContextBuilder addPropertyConverters(TypeLiteral<T> typeToConvert, + Collection<PropertyConverter<T>> propertyConverters); + + /** + * Add all registered (default) property converters to the context built. + * @return this builder, for chaining, never null. + */ + ConfigurationContextBuilder addDefaultPropertyConverters(); + + /** + * Removes the given PropertyConverter instances for the given type, + * if existing. + * + * @param typeToConvert the type which the converters is for + * @param propertyConverters the converters to remove + * @param <T> the target type. + * @return this builder, for chaining, never null. + */ + <T> ConfigurationContextBuilder removePropertyConverters(TypeLiteral<T> typeToConvert, + @SuppressWarnings("unchecked") PropertyConverter<T>... propertyConverters); + + /** + * Removes the given PropertyConverter instances for the given type, + * if existing. + * + * @param typeToConvert the type which the converters is for + * @param propertyConverters the converters to remove + * @param <T> the target type. + * @return this builder, for chaining, never null. + */ + <T> ConfigurationContextBuilder removePropertyConverters(TypeLiteral<T> typeToConvert, + Collection<PropertyConverter<T>> propertyConverters); + + /** + * Removes all converters for the given type, which actually renders a given type + * unsupported for type conversion. + * + * @param typeToConvert the type which the converters is for + * @return this builder, for chaining, never null. + */ + ConfigurationContextBuilder removePropertyConverters(TypeLiteral<?> typeToConvert); + + /** + * Sorts the current registered property sources using the given comparator. + * + * NOTE: property sources at the beginning have minimal significance. + * + * @param comparator the comparator to be used, not {@code null}. + * @return this instance for chaining. + */ + ConfigurationContextBuilder sortPropertySources(Comparator<PropertySource> comparator); + + /** + * Sorts the current registered property filters using the given comparator. + * + * NOTE: property filters at the beginning have minimal significance. + * + * @param comparator the comparator to be used, not {@code null}. + * @return this instance for chaining. + */ + ConfigurationContextBuilder sortPropertyFilter(Comparator<PropertyFilter> comparator); + + /** + * Sets the {@link PropertyValueCombinationPolicy} used to evaluate the final + * property values. + * + * @param policy the {@link PropertyValueCombinationPolicy} used, not {@code null}. + * @return this builder, for chaining, never null. + */ + ConfigurationContextBuilder setPropertyValueCombinationPolicy(PropertyValueCombinationPolicy policy); + + /** + * Builds a new {@link ConfigurationContext} based on the data in this builder. The ordering of property + * sources and property filters is not changed, regardless of their ordinals. For ensure a certain + * ordering/significance call {@link #sortPropertyFilter(Comparator)} and/or {@link #sortPropertySources(Comparator)} + * before building the context. + * + * @return the final context to be used to create a configuration. + * @see org.apache.tamaya.ConfigurationProvider#createConfiguration(ConfigurationContext) + */ + ConfigurationContext build(); + +} +
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/ConfigurationProviderSpi.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/ConfigurationProviderSpi.java b/code/old/api/src/main/java/org/apache/tamaya/spi/ConfigurationProviderSpi.java new file mode 100644 index 0000000..fb93ab4 --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/ConfigurationProviderSpi.java @@ -0,0 +1,128 @@ +/* + * 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.spi; + +import org.apache.tamaya.Configuration; + +/** + * SPI that must be implemented to provide the component that manages all {@link org.apache.tamaya.Configuration} + * instances in a system. In SE this may be a true singleton containing exact one {@link org.apache.tamaya.Configuration} + * instance, whereas in Java EE and other more complex environments instances may be returned depending the current + * runtime context. + */ +public interface ConfigurationProviderSpi { + + /** + * Access the current {@link org.apache.tamaya.Configuration}. + * + * @return the current {@link org.apache.tamaya.Configuration} instance, never null. + */ + Configuration getConfiguration(); + + /** + * Create a {@link Configuration} instance using the given context. The configuration + * created hereby must respect the artifacts provided by its context (property sources, + * filters, converters, policies etc), including their ordering and significance. + * @param context the context to be used, not {@code null}. + * @return the corresponding configuration instance. + */ + Configuration createConfiguration(ConfigurationContext context); + + /** + * Creates a new {@link org.apache.tamaya.spi.ConfigurationContextBuilder} instance. + * + * @return a new {@link org.apache.tamaya.spi.ConfigurationContextBuilder}, never null. + * @deprecated Will be removed + */ + @Deprecated + ConfigurationContextBuilder getConfigurationContextBuilder(); + + /** + * Creates a new {@link org.apache.tamaya.spi.ConfigurationBuilder} instance. + * + * @return a new {@link org.apache.tamaya.spi.ConfigurationBuilder}, never null. + */ + ConfigurationBuilder getConfigurationBuilder(); + + /** + * This method allows to replace the current {@link org.apache.tamaya.Configuration} with a new + * instance. This can be used to update the configuration with a new one, e.g. because some of the + * data has changed and must be updated. It is the responsibility of the ConfigurationProvider to trigger + * corresponding update events for the current {@link org.apache.tamaya.Configuration}. + * + * @param config the new Configuration to be applied. + * @throws java.lang.UnsupportedOperationException if the current provider is read-only. + */ + void setConfiguration(Configuration config); + + /** + * Method that allows to determine if a new {@link org.apache.tamaya.Configuration} can be applied + * programmatically. + * + * @return true, if {@link #setConfiguration(org.apache.tamaya.Configuration)} is supported + * by the current implementation. + * @see #setConfiguration(org.apache.tamaya.Configuration) + */ + default boolean isConfigurationSettable(){ + return true; + } + + /** + * Get access to the current {@link ConfigurationContext}. + * + * @return the current {@link ConfigurationContext}, never null. + * @deprecated Will be removed in favour of {@link Configuration#getContext()}. + */ + @Deprecated + default ConfigurationContext getConfigurationContext(){ + return getConfiguration().getContext(); + } + + /** + * This method allows to replace the current {@link org.apache.tamaya.spi.ConfigurationContext} with a new + * instance. This can be used to update the context with a new one, e.g. because some of the configuration + * data has changed and must be updated. It is the responsibility of the ConfigurationProvider to trigger + * corresponding update event for the current {@link org.apache.tamaya.spi.ConfigurationContext} or + * {@link org.apache.tamaya.Configuration}. + * + * @param context the new ConfigurationContext to be applied. + * @throws java.lang.UnsupportedOperationException if the current provider is read-only. + * @deprecated use {@link #setConfiguration(Configuration)} + */ + @Deprecated + default void setConfigurationContext(ConfigurationContext context){ + setConfiguration(createConfiguration(context)); + } + + /** + * Method that allows to determine if a new {@link org.apache.tamaya.spi.ConfigurationContext} can be applied + * programmatically. + * + * @return true, if {@link #setConfigurationContext(org.apache.tamaya.spi.ConfigurationContext)} is supported + * by the current implementation. + * @see #setConfigurationContext(org.apache.tamaya.spi.ConfigurationContext) + * @deprecated use {@link #isConfigurationSettable()} + */ + @Deprecated + default boolean isConfigurationContextSettable(){ + return isConfigurationSettable(); + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/ConversionContext.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/ConversionContext.java b/code/old/api/src/main/java/org/apache/tamaya/spi/ConversionContext.java new file mode 100644 index 0000000..ac8de68 --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/ConversionContext.java @@ -0,0 +1,267 @@ +/* + * 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.spi; + +import org.apache.tamaya.Configuration; +import org.apache.tamaya.TypeLiteral; + +import java.lang.reflect.AnnotatedElement; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * A conversion context containing all the required values for implementing conversion. Use the included #Builder + * for creating new instances of. This class is thread-safe to use. Adding supported formats is synchronized. + * @see PropertyConverter + */ +public class ConversionContext { + + private final Configuration configuration; + private final String key; + private final TypeLiteral<?> targetType; + private final AnnotatedElement annotatedElement; + private final List<String> supportedFormats = new ArrayList<>(); + private final ConfigurationContext configurationContext; + + /** + * Private constructor used from builder. + * @param builder the builder, not {@code null}. + */ + protected ConversionContext(Builder builder){ + this.key = builder.key; + this.annotatedElement = builder.annotatedElement; + this.targetType = builder.targetType; + this.supportedFormats.addAll(builder.supportedFormats); + this.configuration = builder.configuration; + this.configurationContext = builder.configurationContext; + } + + /** + * Get the key accessed. This information is very useful to evaluate additional metadata needed to determine/ + * control further aspects of the conversion. + * @return the key. This may be null in case where a default value has to be converted and no unique underlying + * key/value configuration is present. + */ + public String getKey(){ + return key; + } + + /** + * Get the target type required. + * @return the target type required. + */ + public TypeLiteral<?> getTargetType(){ + return targetType; + } + + /** + * Get the annotated element, if conversion is performed using injection mechanisms. + * @return the annotated element, or {@code null}. + */ + public AnnotatedElement getAnnotatedElement(){ + return annotatedElement; + } + + /** + * Get the configuration, which is targeted. + * @return the configuration instance, or {@code null}. + */ + public Configuration getConfiguration(){ + return configuration; + } + + /** + * Allows to add information on the supported/tried formats, which can be shown to the user, especially when + * conversion failed. Adding of formats is synchronized, all formats are added in order to the overall list. + * This means formats should be passed in order of precedence. + * @param converterType the converters, which implements the formats provided. + * @param formatDescriptors the format descriptions in a human readable form, e.g. as regular expressions. + */ + public void addSupportedFormats(@SuppressWarnings("rawtypes") Class<? extends PropertyConverter> converterType, String... formatDescriptors){ + synchronized (supportedFormats){ + for(String format: formatDescriptors) { + supportedFormats.add(format + " (" + converterType.getSimpleName() + ")"); + } + } + } + + /** + * Get the supported/tried formats in precedence order. The contents of this method depends on the + * {@link PropertyConverter} instances involved in a conversion. + * @return the supported/tried formats, never {@code null}. + */ + public List<String> getSupportedFormats(){ + synchronized (supportedFormats){ + return new ArrayList<>(supportedFormats); + } + } + + @Override + public String toString() { + return "ConversionContext{" + + "configuration=" + configuration + + ", key='" + key + '\'' + + ", targetType=" + targetType + + ", annotatedElement=" + annotatedElement + + ", supportedFormats=" + supportedFormats + + '}'; + } + + public ConfigurationContext getConfigurationContext() { + return configurationContext; + } + + /** + * Builder to create new instances of {@link ConversionContext}. + */ + public static final class Builder{ + /** The backing configuration. */ + private Configuration configuration; + /** The configuration context. */ + private ConfigurationContext configurationContext; + /** The accessed key, or null. */ + private String key; + /** The target type. */ + private TypeLiteral<?> targetType; + /** The injection target (only set with injection used). */ + private AnnotatedElement annotatedElement; + /** The ordered list of formats tried. */ + private final Set<String> supportedFormats = new HashSet<>(); + + /** + * Creates a new Builder instance. + * @param targetType the target type + */ + public Builder(TypeLiteral<?> targetType) { + this(null, null, null, targetType); + } + + /** + * Creates a new Builder instance. + * @param key the requested key, may be null. + * @param targetType the target type + */ + public Builder(String key, TypeLiteral<?> targetType) { + this(null, null, key, targetType); + } + + /** + * Creates a new Builder instance. + * @param configuration the configuration, not {@code null}. + * @param configurationContext configuration context, not {@code null}. + * @param key the requested key, may be {@code null}. + * @param targetType the target type + */ + public Builder(Configuration configuration, ConfigurationContext configurationContext, String key, TypeLiteral<?> targetType){ + this.key = key; + this.configuration = configuration; + this.configurationContext = configurationContext; + this.targetType = Objects.requireNonNull(targetType); + } + + /** + * Sets the key. + * @param key the key, not {@code null}. + * @return the builder instance, for chaining + */ + public Builder setKey(String key){ + this.key = Objects.requireNonNull(key); + return this; + } + + /** + * Sets the configuration. + * @param configuration the configuration, not {@code null} + * @return the builder instance, for chaining + */ + public Builder setConfiguration(Configuration configuration){ + this.configuration = Objects.requireNonNull(configuration); + return this; + } + + /** + * Sets the configuration. + * @param configurationContext the configuration, not {@code null} + * @return the builder instance, for chaining + */ + public Builder setConfigurationContext(ConfigurationContext configurationContext){ + this.configurationContext = Objects.requireNonNull(configurationContext); + return this; + } + + /** + * Sets the annotated element, when configuration is injected. + * @param annotatedElement the annotated element, not {@code null} + * @return the builder instance, for chaining + */ + public Builder setAnnotatedElement(AnnotatedElement annotatedElement){ + this.annotatedElement = Objects.requireNonNull(annotatedElement); + return this; + } + + /** + * Sets the target type explicitly. This is required in some rare cases, e.g. injection of {@code Provider} + * instances, where the provider's result type must be produced. + * @param targetType the + * @return the builder for chaining. + */ + public Builder setTargetType(@SuppressWarnings("rawtypes") TypeLiteral targetType) { + this.targetType = Objects.requireNonNull(targetType); + return this; + } + + /** + * Add the formats provided by a {@link PropertyConverter}. This method should be called by each converters + * performing/trying conversion, so the user can be given feedback on the supported formats on failure. + * @param converterType the converters type, not {@code null}. + * @param formatDescriptors the formats supported in a human readable form, e.g. as regular expressions. + * @return the builder instance, for chaining + */ + public Builder addSupportedFormats(@SuppressWarnings("rawtypes") Class<? extends PropertyConverter> converterType, String... formatDescriptors){ + for(String format: formatDescriptors) { + supportedFormats.add(format + " (" + converterType.getSimpleName() + ")"); + } + return this; + } + + /** + * Builds a new context instance. + * @return a new context, never null. + */ + public ConversionContext build(){ + return new ConversionContext(this); + } + + @Override + public String toString() { + return "Builder{" + + "configuration=" + configuration + + "context=" + configurationContext + + ", key='" + key + '\'' + + ", targetType=" + targetType + + ", annotatedElement=" + annotatedElement + + ", supportedFormats=" + supportedFormats + + '}'; + } + + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/Experimental.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/Experimental.java b/code/old/api/src/main/java/org/apache/tamaya/spi/Experimental.java new file mode 100644 index 0000000..9831820 --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/Experimental.java @@ -0,0 +1,32 @@ +/* + * 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.spi; + +import java.lang.annotation.*; + +/** + * This is a simple annotation for flaging out functionality or features the Tamaya team is not sure if it is already + * stabilized, so use it with some caution. + */ +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, + ElementType.TYPE}) +public @interface Experimental { +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/FilterContext.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/FilterContext.java b/code/old/api/src/main/java/org/apache/tamaya/spi/FilterContext.java new file mode 100644 index 0000000..2851697 --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/FilterContext.java @@ -0,0 +1,140 @@ +/* + * 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.spi; + +import org.apache.tamaya.Configuration; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * A filter context containing all the required values for implementing filtering. + * + * @see PropertyFilter + */ +public class FilterContext { + /** The key. */ + private final PropertyValue value; + /** The current context. */ + private final ConfigurationContext context; + @Experimental + private Map<String, PropertyValue> configEntries = new HashMap<>(); + @Experimental + private boolean singlePropertyScoped; + + + /** + * Creates a new FilterContext, for filtering of a multi value access + * using {@link Configuration#getProperties()}. + * + * @param value the value under evaluation, not {@code null}. + * @param configEntries the raw configuration data available in the + * current evaluation context, not {@code null}. + * @param context the current context, not {@code null}. + */ + public FilterContext(PropertyValue value, Map<String,PropertyValue> configEntries, ConfigurationContext context) { + Objects.requireNonNull(value, "Value must not be null."); + Objects.requireNonNull(configEntries, "Initial configuration entries must be not null."); + Objects.requireNonNull(context, "Context must be not null."); + + this.singlePropertyScoped = false; + this.value = Objects.requireNonNull(value); + this.context = Objects.requireNonNull(context); + this.configEntries.putAll(configEntries); + this.configEntries = Collections.unmodifiableMap(this.configEntries); + } + + /** + * Creates a new FilterContext, for filtering of a single value access + * using {@link Configuration#getProperties()}. + * @param value the value under evaluation, not {@code null}. + * @param context the current context, not {@code null}. + */ + public FilterContext(PropertyValue value, ConfigurationContext context) { + Objects.requireNonNull(value, "Value must not be null."); + Objects.requireNonNull(context, "Context must be not null."); + + this.singlePropertyScoped = true; + this.context = Objects.requireNonNull(context); + this.value = Objects.requireNonNull(value); + this.configEntries = Collections.unmodifiableMap(this.configEntries); + } + + /** + * Get the current context. + * @return the current context, not {@code null}. + */ + public ConfigurationContext getContext(){ + return context; + } + + /** + * Get the property value under evaluation. This information is very useful to evaluate additional metadata needed to determine/ + * control further aspects of the conversion. + * + * @return the key. This may be null in case where a default value has to be converted and no unique underlying + * key/value configuration is present. + */ + public PropertyValue getProperty() { + return value; + } + + /** + * Method that determines if filtering is done for a single property accessed, or as part of call to + * {@code getProperties()}. + * @return true, if its scoped to a single property accessed. + */ + @Experimental + public boolean isSinglePropertyScoped(){ + return singlePropertyScoped; + } + + /** + * This map contains the following keys: + * <ul> + * <li>the original value <b>before</b> any filters were applied on it.</li> + * <li>all values starting with an {@code _<key>.}, for example {@code a.value} + * may have a map set with {@code a.value} (oringinal value), {@code _a.value.origin, + * _a.value.type, etc}. The exact contents is determine by the {@link PropertySource}s + * active.</li> + * </ul> + * Also important to know is that this map given contains all the evaluated raw entries, regardless + * of the filters that are later applied. This ensures that met-information required by one filter is + * not hidden by another filter, because of an invalid filter ordering. In other words filters may remove + * key/value pairs, e.g. fir security reasons, by returning {@code null}, but the values in the raw map + * passed as input to the filter process will not be affected by any such removal (but the final properties + * returned are affected, of course). + * + * Finally, when a single property is accessed, e.g. by calling {@code Configuration.get(String)}. + * + * @return the configuration instance, or null. + */ + @Experimental + public Map<String, PropertyValue> getConfigEntries() { + return configEntries; + } + + @Override + public String toString() { + return "FilterContext{value='" + value + "', configEntries=" + configEntries.keySet() + '}'; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyConverter.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyConverter.java b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyConverter.java new file mode 100644 index 0000000..ab96b6b --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyConverter.java @@ -0,0 +1,44 @@ +/* + * 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.spi; + +/** + * Interface for an property that converts a configured String into something else. + * This is used for implementing type conversion from a property (String) to a certain target + * type. Hereby the target type can be multi-value (e.g. collections) or complex if needed. + * + * @param <T> the type of the type literal + */ +@FunctionalInterface +public interface PropertyConverter<T>{ + + /** + * Convert the given configuration keys from its String representation into the required target type. + * The context instance passed also allows to add a list of supported formats, which is very handy in case a + * value could not be converted. This list of supported formats can then shown to the user to give some hints + * how a value could be configured. + * + * @param value configuration key that needs to be converted + * @param context the {@link ConversionContext}, containing the String value and the requested configuration key. + * @return converted keys + * @see ConversionContext#addSupportedFormats(Class, String...) + */ + T convert(String value, ConversionContext context); + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyFilter.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyFilter.java b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyFilter.java new file mode 100644 index 0000000..3054496 --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyFilter.java @@ -0,0 +1,51 @@ +/* + * 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.spi; + + +/** + * <p>Interface for filtering the current map of properties during the evaluation of the chain of PropertySources. + * Filters can be registered using the {@link org.apache.tamaya.spi.ServiceContext}. The ordinal + * hereby is defined by the corresponding {@code @Priority} annotation.</p> + * <p>Filters </p> + */ +@FunctionalInterface +public interface PropertyFilter { + + /** + * <p>Maps the current {@code valueToBeFiltered} value to a new value. The resulting value will be used as the result + * passed to the user.</p> + * <p>If a filter is currently not available, it should just pass the input map to the method's + * output.</p> + * <p>Returning {@code null} will remove the entry.</p> + * <h3>Implementation specification</h3> + * Implementations of this class must be + * <ul> + * <li>reentrant</li> + * <li>thread-safe</li> + * </ul> + * @param value the value to be filtered, which also can be {@code null} if removed by another filter. + * @param context the filter context, not {@code null}. + * @return the filtered value, or {@code null} if the value should be removed alltogether. + * @see PropertyValue + * @see PropertyValueBuilder + */ + PropertyValue filterProperty(PropertyValue value, FilterContext context); + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/PropertySource.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/PropertySource.java b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertySource.java new file mode 100644 index 0000000..864cd95 --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertySource.java @@ -0,0 +1,174 @@ +/* +* 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.spi; + + +import org.apache.tamaya.Configuration; + +import java.util.Collections; +import java.util.Map; + + +/** + * <p>This interface models a provider that serves configuration properties. The contained + * properties may be read from a Map of single or several sources (composite). + * PropertySources are the building blocks of the final configuration. </p> + * <h3>Implementation Requirements</h3> + * <p>Implementations of this interface must be</p> + * <ul> + * <li>Thread safe.</li> + * </ul> + * + * <p>A PropertySourceProvider will get picked up via the + * {@link java.util.ServiceLoader} mechanism and can be registered via + * {@code META-INF/services/org.apache.tamaya.spi.PropertySource} + * </p> + * <p> + * If you like to register multiple PropertySources at the same time + * you can use the {@link org.apache.tamaya.spi.PropertySourceProvider} + * interface. + * </p> + */ +public interface PropertySource { + + /** + * property name to override default tamaya ordinals + */ + String TAMAYA_ORDINAL = "tamaya.ordinal"; + + /** + * A resusable instance of an empty PropertySource. + */ + PropertySource EMPTY = new PropertySource() { + + @Override + public int getOrdinal() { + return Integer.MIN_VALUE; + } + + @Override + public String getName() { + return "<empty>"; + } + + @Override + public PropertyValue get(String key) { + return null; + } + + @Override + public Map<String, PropertyValue> getProperties() { + return Collections.emptyMap(); + } + + @Override + public boolean isScannable() { + return false; + } + + @Override + public String toString(){ + return "PropertySource.EMPTY"; + } + }; + + + /** + * The ordinal value is the default ordering parameter which definines the default order of + * auto-discovered property sources. Ordering of property sources is important since values + * from property sources with higher ordinal values override values from less significant + * property sources. + * + * By default Tamaya includes the following property sources: + * <ol> + * <li>Properties file values (/META-INF/javaconfiguration.properties) (ordinal 100)</li> + * <li>JNDI values (ordinal 200, only when adding the {@code tamaya-jndi} extension module)</li> + * <li>Environment properties (ordinal 300)</li> + * <li>System properties (ordinal 1000)</li> + * </ol> + * + * <p><b>Important Hints for custom implementations</b>:</p> + * <p> + * If a custom implementation should be invoked <b>before</b> the default implementations, use a value > 1000 + * </p> + * <p> + * If a custom implementation should be invoked <b>after</b> the default implementations, use a value < 100 + * </p> + * + * <p>Reordering of the default order of the config-sources:</p> + * <p>Example: If the properties file/s should be used <b>before</b> the other implementations, + * you have to configure an ordinal > 1000. That means, you have to add e.g. tamaya.ordinal=401 to + * /META-INF/javaconfiguration.properties . Hint: In case of property files every file is handled as independent + * config-source, but all of them have ordinal 400 by default (and can be reordered in a fine-grained manner.</p> + * + * In cases where it is not possible to change a config sources ordinal value, you may have several options: + * <ul> + * <li>you can register an alternate implementation of {@link PropertyValueCombinationPolicy}.</li> + * <li>you can use a {@link ConfigurationContextBuilder} to redefine the source order and finally use + * {@link org.apache.tamaya.ConfigurationProvider#setConfiguration(Configuration)} to + * change the current default {@link Configuration}.</li> + * <li>finally, the imeplementor of this API may define alternate mechanism to reconfigure an ordinal + * in a vendor specific way.</li> + * </ul> + * @return the 'importance' aka ordinal of the configured values. The higher, the more important. + */ + int getOrdinal(); + + + /** + * Get the name of the property source. The name should be unique for the type of source, whereas the id is used + * to ensure unique identity, either locally or remotely. + * @return the configuration's name, never {@code null}. + */ + String getName(); + + /** + * Access a property. + * + * @param key the property's key, not {@code null}. + * @return the property value map, where {@code map.get(key) == value}, including also any metadata. In case a + * value is null, simply return {@code null}. + */ + PropertyValue get(String key); + + /** + * Access the current properties as Set. The resulting Map may not return all items accessible, e.g. + * when the underlying storage does not support iteration of its entries. + {@code null} + * @return the corresponding map, never null. + */ + Map<String, PropertyValue> getProperties(); + + /** + * Determines if this config source can be scanned for its list of properties. + * + * <p> + * PropertySources which are not scannable might not be able to find all the + * configured values to provide via {@link #getProperties()}. This might happen + * if the underlying storage doesn't support listing. + * </p> + * + * @return {@code true} if this PropertySource can be scanned for its list of properties, + * {@code false} if it cannot/should not be scanned. + */ + default boolean isScannable(){ + return true; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/PropertySourceProvider.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/PropertySourceProvider.java b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertySourceProvider.java new file mode 100644 index 0000000..3f7beea --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertySourceProvider.java @@ -0,0 +1,61 @@ +/* + * 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.spi; + +import java.util.Collection; +import java.util.Collections; + +/** + * <p>Implement this interfaces to provide a PropertySource provider which + * is able to register multiple PropertySources. This is e.g. needed if + * there are multiple property files of a given config file name.</p> + * + * <p>If a PropertySource like JNDI only exists once, then there is no need + * to implement it via the PropertySourceProvider but should directly + * expose a {@link PropertySource}.</p> + * + * <p>A PropertySourceProvider will get picked up via the + * {@link java.util.ServiceLoader} mechanism and must get registered via + * META-INF/services/org.apache.tamaya.spi.PropertySourceProvider</p> + */ +@FunctionalInterface +public interface PropertySourceProvider { + + /** + * A resusable instance of an empty PropertySource. + */ + PropertySourceProvider EMPTY = new PropertySourceProvider() { + + @Override + public Collection<PropertySource> getPropertySources() { + return Collections.emptySet(); + } + + @Override + public String toString(){ + return "PropertySourceProvider(empty)"; + } + }; + + /** + * @return For each e.g. property file, we return a single PropertySource + * or an empty list if no PropertySource exists. + */ + Collection<PropertySource> getPropertySources(); +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java new file mode 100644 index 0000000..c538de7 --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyValue.java @@ -0,0 +1,232 @@ +/* + * 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.spi; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * Class modelling the result of a request for a property value. A property value is basically identified by its key. + * There might be reasons, where one want to further analyze, which PropertySources provided a value and which not, so + * it is possible to create a PropertyValue with a null value. Nevertheless in all cases the provider source (typically + * the name of the PropertySource) must be set. + */ +public final class PropertyValue implements Serializable{ + private static final long serialVersionUID = 1L; + /** The requested key. */ + private String key; + /** The value. */ + private String value; + /** The source of the value. */ + private String source; + /** Additional metadata provided by the provider. */ + private Map<String,String> metaEntries = new HashMap<>(); + + PropertyValue(PropertyValueBuilder builder){ + this.key = Objects.requireNonNull(builder.key); + this.value = builder.value; + this.source = Objects.requireNonNull(builder.source); + if(builder.metaEntries !=null) { + this.metaEntries.putAll(builder.metaEntries); + } + } + + /** + * Creates a new instance + * @param key the key, not {@code null}. + * @param value the value, not {@code null}. + * @param source the source, typically the name of the {@link PropertySource} providing + * the value, not {@code null}. + */ + private PropertyValue(String key, String value, String source){ + this.key = Objects.requireNonNull(key, "Key is required."); + this.value = Objects.requireNonNull(value, "Value is required."); + this.source = Objects.requireNonNull(source, "Source is required."); + } + + /** + * The requested key. + * @return the, key never {@code null}. + */ + public String getKey() { + return key; + } + + /** + * The source. + * @return the source, which provided the value, not {@code null}. + * @see PropertySource#getName() . + */ + public String getSource() { + return this.source; + } + + + /** + * The value. + * @return the value, in case a value is null it is valid to return {#code null} as result for + * {@link PropertySource#get(String)}. + */ + public String getValue() { + return this.value; + } + + /** + * Creates a full configuration map for this key, value pair and all its meta context data. This map + * is also used for subsequent processing, like value filtering. + * @return the property value entry map. + */ + public Map<String, String> getMetaEntries() { + return Collections.unmodifiableMap(metaEntries); + } + + /** + * Creates a new builder instance. + * @param key the key, not {@code null}. + * @param source the source, typically the name of the {@link PropertySource} + * providing the value, not {@code null}. + * @return a new builder instance. + */ + public static PropertyValueBuilder builder(String key, String source){ + Objects.requireNonNull(key, "Key must be given."); + Objects.requireNonNull(source, "Source must be given"); + + return new PropertyValueBuilder(key, source); + } + + /** + * Creates a new builder instance. + * @param key the key, not {@code null}. + * @param value the property value, not {@code null}. + * @param source the source, typically the name of the {@link PropertySource} + * providing the value, not {@code null}. + * @return a new builder instance. + */ + public static PropertyValueBuilder builder(String key, String value, String source) { + Objects.requireNonNull(key, "Key must be given."); + Objects.requireNonNull(value, "Value must be given"); + Objects.requireNonNull(source, "Source must be given."); + + return new PropertyValueBuilder(key, value, source); + } + + + /** + * Creates a new PropertyValue without any metadata.. + * @param key the key, not {@code null}. + * @param value the value. + * @param source the source, typically the name of the {@link PropertySource} + * providing the value, not {@code null}. + * @return a new property value instance, or {@code null}, + * if the value passed is {@code null}.. + */ + public static PropertyValue of(String key, String value, String source) { + if (value==null) { + return null; + } + return new PropertyValue(key, value, source); + } + + /** + * Access the given key from this value. Valid keys are the key or any meta-context key. + * @param key the key, not {@code null}. + * @return the value found, or {@code null}. + */ + public String getMetaEntry(String key) { + return this.metaEntries.get(Objects.requireNonNull(key)); + } + + /** + * Creates a new builder instance based on this item. + * @return a new builder, never null. + */ + public PropertyValueBuilder toBuilder() { + return new PropertyValueBuilder(this.getKey(), this.getSource()) + .setValue(this.getValue()) + .setMetaEntries(this.metaEntries); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof PropertyValue)) return false; + PropertyValue that = (PropertyValue) o; + return Objects.equals(getKey(), that.getKey()) && + Objects.equals(getValue(), that.getValue()) && + Objects.equals(getSource(), that.getSource()) && + Objects.equals(getMetaEntries(), that.getMetaEntries()); + } + + @Override + public int hashCode() { + return Objects.hash(getKey(), getValue(), getSource(), + getMetaEntries()); + } + + @Override + public String toString() { + return "PropertyValue{" + + "key='" + key + '\'' + + ", value='" + value + '\'' + + ", source='" + source + '\'' + + (metaEntries.isEmpty()?"":", metaEntries=" + metaEntries) + + '}'; + } + + /** + * Maps a map of {@code Map<String,String>} to a {@code Map<String,PropertyValue>}. + * @param config the String based map, not {@code null}. + * @param source the source name, not {@code null}. + * @return the corresponding value based map. + */ + public static Map<String,PropertyValue> map(Map<String, String> config, String source) { + Map<String,PropertyValue> result = new HashMap<>(config.size()); + for(Map.Entry<String,String> en:config.entrySet()){ + result.put(en.getKey(), PropertyValue.of(en.getKey(), en.getValue(), source)); + } + return result; + } + + /** + * Maps a map of {@code Map<String,String>} to a {@code Map<String,PropertyValue>}. + * + * @param config the String based map, not {@code null}. + * @param source the source name, not {@code null}. + * @param metaData additional metadata, not {@code null}. + * @return the corresponding value based map. + */ + public static Map<String,PropertyValue> map(Map<String, String> config, String source, + Map<String,String> metaData) { + Objects.requireNonNull(config, "Config must be given."); + Objects.requireNonNull(source, "Source must be given."); + Objects.requireNonNull(metaData, "Meta data must be given."); + + Map<String,PropertyValue> result = new HashMap<>(config.size()); + + for(Map.Entry<String,String> en:config.entrySet()){ + PropertyValue value = new PropertyValueBuilder(en.getKey(), source).setValue(en.getValue()) + .addMetaEntries(metaData).build(); + result.put(en.getKey(), value); + } + return result; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java new file mode 100644 index 0000000..af01987 --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyValueBuilder.java @@ -0,0 +1,196 @@ +/* + * 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.spi; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * Builder to create a {@link PropertyValue} instance. + */ +public class PropertyValueBuilder { + /** The key accessed. */ + String key; + /** The property value. */ + String value; + /** The property vaoue source. */ + String source; + /** additional metadata entries (optional). */ + Map<String,String> metaEntries = new HashMap<>(); + + /** + * Create a new builder instance, for a given set of parameters. + * Before calling build at least a {@link #value} and its {@link #source} + * must be set. + */ + PropertyValueBuilder(String key){ + this.key = Objects.requireNonNull(key); + } + + /** + * Create a new builder instance, for a given set of parameters. + * @param key to access a property value, not {@code null}. + * @param source property source. + */ + PropertyValueBuilder(String key, String source) { + this.key = Objects.requireNonNull(key); + this.source = Objects.requireNonNull(source); + } + + /** + * Create a new builder instance, for a given set of parameters. + * + * @param key to access a property value. + * @param value the value, not {@code null}. If a value is {@code null} + * {@link PropertySource#get(String)} should return {@code null}. + * @param source property source. + */ + PropertyValueBuilder(String key, String value, String source) { + this.key = Objects.requireNonNull(key); + this.value = value; + this.source = Objects.requireNonNull(source); + } + + /** + * Replaces/sets the context data. + * @param metaEntries the context data to be applied, not {@code null}. + * @return the builder for chaining. + */ + public PropertyValueBuilder setMetaEntries(Map<String, String> metaEntries) { + this.metaEntries.clear(); + this.metaEntries.putAll(metaEntries); + return this; + } + + /** + * Add an additional context data information. + * @param key the context data key, not {@code null}. + * @param value the context value, not {@code null} (will be converted to String). + * @return the builder for chaining. + */ + public PropertyValueBuilder addMetaEntry(String key, Object value) { + Objects.requireNonNull(key, "Meta key must be given."); + Objects.requireNonNull(value, "Meta value must be given."); + + this.metaEntries.put(key, String.valueOf(value)); + return this; + } + + /** + * Adds the context data given. + * @param metaEntries the context data to be applied, not {@code null}. + * @return the builder for chaining. + */ + public PropertyValueBuilder addMetaEntries(Map<String, String> metaEntries) { + this.metaEntries.putAll(metaEntries); + return this; + } + + /** + * Removes a meta entry. + * @param key the entry's key, not {@code null}. + * @return the builder for chaining. + */ + public PropertyValueBuilder removeMetaEntry(String key) { + Objects.requireNonNull(key, "Key must be given."); + + this.metaEntries.remove(key); + return this; + } + + /** + * Get the value's context data. + * @return the context data, not {@code null}. + */ + public Map<String,String> getMetaEntries() { + return Collections.unmodifiableMap(this.metaEntries); + } + + /** + * Changes the entry's key, mapping also corresponding context entries. + * @param key the new key, not {@code null}. + * @return the builder for chaining. + */ + public PropertyValueBuilder mapKey(String key) { + // todo obf if (1==1) throw new RuntimeException("No tests written."); + Map<String,String> newContext = new HashMap<>(); + for(Map.Entry<String,String> en:this.metaEntries.entrySet()){ + if(en.getKey().startsWith("_"+this.key)){ + newContext.put("_"+key+'.'+ en.getKey().substring(this.key.length()+1), en.getValue()); + }else{ + newContext.put(en.getKey(), en.getValue()); + } + } + this.metaEntries = newContext; + this.key = key; + return this; + } + + /** + * Sets a new key. + * @param key the new key, not {@code null}. + * @return the builder for chaining. + */ + public PropertyValueBuilder setKey(String key) { + this.key = Objects.requireNonNull(key); + return this; + } + + /** + * Sets a new value. + * @param value the new value, not {@code null}. + * @return the builder for chaining. + */ + public PropertyValueBuilder setValue(String value) { + this.value = Objects.requireNonNull(value, "Value must be given."); + + return this; + } + + /** + * Sets a new source. + * @param source the new source, not {@code null}. + * @return the builder for chaining. + */ + public PropertyValueBuilder setSource(String source) { + // todo obf if (1==1) throw new RuntimeException("No tests written."); + this.source = Objects.requireNonNull(source); + return this; + } + + /** + * Creates a new immutable {@link PropertyValue}. + * @return a new immutable {@link PropertyValue}, never {@code null}. + */ + public PropertyValue build(){ + return new PropertyValue(this); + } + + @Override + public String toString() { + return "PropertyValueBuilder{" + + "key='" + key + '\'' + + "value='" + value + '\'' + + ", metaEntries=" + metaEntries + + '}'; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java new file mode 100644 index 0000000..14640e6 --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/PropertyValueCombinationPolicy.java @@ -0,0 +1,71 @@ +/* + * 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.spi; + + +/** + * Policy that determines how the final value of a configuration entry is evaluated. An instances of this + * interface can be registered to get control how multiple PropertySources are combined. This is useful in cases + * where the default overriding policy as implemented in {@link #DEFAULT_OVERRIDING_POLICY} is not matching + * the need of the current application, e.g. then entries containing multiple values should be combined to new + * values instead of overridden. + */ +public interface PropertyValueCombinationPolicy { + + /** + * Default overriding collector, where each existing entry ({@code current} is overridden by a subsequent non-null + * entry evaluated by {@code propertySource.get(key)}. + */ + PropertyValueCombinationPolicy DEFAULT_OVERRIDING_POLICY = new PropertyValueCombinationPolicy(){ + + @Override + public PropertyValue collect(PropertyValue currentValue, String key, PropertySource propertySource) { + PropertyValue value = propertySource.get(key); + return value!=null?value:currentValue; + } + }; + + /** + * @deprecated Use {@linkplain #DEFAULT_OVERRIDING_POLICY} instead. Will be removed in 1.0. + */ + @Deprecated + PropertyValueCombinationPolicy DEFAULT_OVERRIDING_COLLECTOR = DEFAULT_OVERRIDING_POLICY; + + + /** + * Method that is called for each value evaluated by a PropertySource for the given key. This method is called + * either when a single key is accessed, e.g. by calling {@code org.apache.tamaya.Configuration.getXXX}, but also + * when the full configuration property map is accessed by calling + * {@link org.apache.tamaya.Configuration#getProperties()}. + * + * @param currentValue the current value, including metadata entries. If no such key is present the current value + * is null. + * The collector should either combine the existing value with value from {@code currentValue} + * or replace the value in {@code currentValue} with {@code valueRead}, hereby returning the + * result to be used as new {@code currentValue}. + * @param key The current key to be evaluated. + * @param propertySource The PropertySource that may return an value for the given key. The PropertySource given + * may be evaluated for additional meta-data, how the given values are to be combined. + * Note that the value returned by a PropertySource can be null. In that case + * {@code currentValue} should be returned in almost all cases. + * @return the value to be used for future evaluation, including metadata entries. + */ + PropertyValue collect(PropertyValue currentValue, String key, PropertySource propertySource); + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/ServiceContext.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/ServiceContext.java b/code/old/api/src/main/java/org/apache/tamaya/spi/ServiceContext.java new file mode 100644 index 0000000..9eb18e8 --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/ServiceContext.java @@ -0,0 +1,93 @@ +/* + * 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.spi; + +import java.io.IOException; +import java.net.URL; +import java.util.Enumeration; +import java.util.List; + + +/** + * This class models the component that is managing the lifecycle current the + * services used by the Configuration API. + */ +public interface ServiceContext { + + /** + * @return ordinal of the ServiceContext. The one with the highest ordinal will be taken. + */ + int ordinal(); + + /** + * Access a service singleton via its type. + * If multiple implementations for the very serviceType exist then + * the one with the highest {@link javax.annotation.Priority} will be used. + * + * @param <T> the type of the service type. + * @param serviceType the service type. + * @return The instance to be used, or {@code null} + * @throws org.apache.tamaya.ConfigException if there are multiple service implementations with the maximum priority. + */ + <T> T getService(Class<T> serviceType); + + /** + * Factory method to create a type, hereby a new instance is created on each access. + * If multiple implementations for the very serviceType exist then + * the one with the highest {@link javax.annotation.Priority} will be used as the base + * for creating subsequent instances. + * + * @param <T> the type of the service type. + * @param serviceType the service type. + * @return The new instance to be used, or {@code null} + * @throws org.apache.tamaya.ConfigException if there are multiple service implementations with the maximum priority. + */ + <T> T create(Class<T> serviceType); + + /** + * Access a list current services, given its type. The bootstrap mechanism should + * order the instance for precedence, hereby the most significant should be + * first in order. + * + * @param serviceType + * the service type. + * @param <T> the type of the list element returned by this method + * @return The instance to be used, never {@code null} + */ + <T> List<T> getServices(Class<T> serviceType); + + /** + * Loads resources from the current runtime context. This method allows to use runtime + * specific code to load resources, e.g. within OSGI environments. + * @param resource the resource, not {@code null}. + * @param cl the desired classloader context, if null, the current thread context classloader is used. + * @return the resources found + * @throws IOException if load fails. + */ + Enumeration<URL> getResources(String resource, ClassLoader cl) throws IOException; + + /** + * Loads a resource from the current runtime context. This method allows to use runtime + * specific code to load a resource, e.g. within OSGI environments. + * @param resource the resource, not {@code null}. + * @param cl the desired classloader context, if null, the current thread context classloader is used. + * @return the resource found, or {@code null}. + */ + URL getResource(String resource, ClassLoader cl); +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/ServiceContextManager.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/ServiceContextManager.java b/code/old/api/src/main/java/org/apache/tamaya/spi/ServiceContextManager.java new file mode 100644 index 0000000..f58c27a --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/ServiceContextManager.java @@ -0,0 +1,118 @@ +/* + * 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.spi; + +import java.util.Objects; +import java.util.ServiceLoader; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.tamaya.ConfigException; + + +/** + * This singleton provides access to the services available in the current {@link ServiceContext}. The + * behaviour can be adapted, by calling {@link ServiceContextManager#set(ServiceContext)} before accessing any + * services. + */ +public final class ServiceContextManager { + + /** The logger used. */ + private static final Logger LOG = Logger.getLogger(ServiceContextManager.class.getName()); + + /** + * The ServiceProvider used. + */ + private static volatile ServiceContext serviceContextProviderDelegate; + + /** + * Private singletons constructor. + */ + private ServiceContextManager() { + } + + /** + * Load the {@link ServiceContext} to be used. + * + * @return {@link ServiceContext} to be used for loading the services. + */ + private static ServiceContext loadDefaultServiceProvider() { + ServiceContext highestServiceContext = null; + try { + int highestOrdinal = 0; + for (ServiceContext serviceContext : ServiceLoader.load(ServiceContext.class)) { + if(highestServiceContext==null){ + highestServiceContext = serviceContext; + }else if (serviceContext.ordinal() > highestOrdinal) { + highestServiceContext = serviceContext; + highestOrdinal = serviceContext.ordinal(); + } + } + } catch (Exception e) { + throw new ConfigException("ServiceContext not loadable", e); + } + if (highestServiceContext==null){ + throw new ConfigException("No ServiceContext found"); + } + LOG.info("Using Service Context of type: " + highestServiceContext.getClass().getName()); + return highestServiceContext; + } + + /** + * Replace the current {@link ServiceContext} in use. + * + * @param serviceContextProvider the new {@link ServiceContext}, not {@code null}. + * @return the currently used context after setting it. + */ + public static ServiceContext set(ServiceContext serviceContextProvider) { + Objects.requireNonNull(serviceContextProvider); + ServiceContext currentContext = ServiceContextManager.serviceContextProviderDelegate; + + synchronized (ServiceContextManager.class) { + if (ServiceContextManager.serviceContextProviderDelegate == null) { + ServiceContextManager.serviceContextProviderDelegate = serviceContextProvider; + LOG.log(Level.INFO, "Using ServiceProvider: " + serviceContextProvider.getClass().getName()); + } else { + LOG.log(Level.WARNING, "Replacing ServiceProvider " + + ServiceContextManager.serviceContextProviderDelegate.getClass().getName() + + " with: " + serviceContextProvider.getClass().getName()); + ServiceContextManager.serviceContextProviderDelegate = serviceContextProvider; + } + } + + return currentContext; + } + + /** + * Ge {@link ServiceContext}. If necessary the {@link ServiceContext} will be laziliy loaded. + * + * @return the {@link ServiceContext} used. + */ + public static ServiceContext getServiceContext() { + if (serviceContextProviderDelegate == null) { + synchronized (ServiceContextManager.class) { + if (serviceContextProviderDelegate == null) { + serviceContextProviderDelegate = loadDefaultServiceProvider(); + } + } + } + return serviceContextProviderDelegate; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/9bc56a38/code/old/api/src/main/java/org/apache/tamaya/spi/package-info.java ---------------------------------------------------------------------- diff --git a/code/old/api/src/main/java/org/apache/tamaya/spi/package-info.java b/code/old/api/src/main/java/org/apache/tamaya/spi/package-info.java new file mode 100644 index 0000000..49dbab9 --- /dev/null +++ b/code/old/api/src/main/java/org/apache/tamaya/spi/package-info.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +/** + * This package contains the Apache Tamaya SPI artifacts. + */ +@org.osgi.annotation.versioning.Version("0.4") +package org.apache.tamaya.spi; \ No newline at end of file