TAMAYA-19: Streamlined API and impl.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/a60570e8 Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/a60570e8 Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/a60570e8 Branch: refs/heads/master Commit: a60570e8e9e561dd2c02c7d0978e846d4d9dd27e Parents: 0b5d4fe Author: anatole <anat...@apache.org> Authored: Fri Dec 26 01:49:55 2014 +0100 Committer: anatole <anat...@apache.org> Committed: Fri Dec 26 01:49:55 2014 +0100 ---------------------------------------------------------------------- .../org/apache/tamaya/AggregationPolicy.java | 131 --- .../java/org/apache/tamaya/Configuration.java | 37 +- .../java/org/apache/tamaya/PropertySource.java | 45 - .../tamaya/annotation/ConfiguredProperty.java | 2 +- .../org/apache/tamaya/annotation/WithCodec.java | 45 - .../tamaya/annotation/WithConfigOperator.java | 2 +- .../tamaya/annotation/WithPropertyAdapter.java | 45 + .../java/org/apache/tamaya/spi/CodecSpi.java | 89 -- .../tamaya/spi/DefaultServiceComparator.java | 85 -- .../spi/DefaultServiceContextProvider.java | 9 - .../java/org/apache/tamaya/spi/Orderable.java | 34 - .../org/apache/tamaya/spi/OrdinalProvider.java | 37 - .../apache/tamaya/spi/PropertyAdapterSpi.java | 72 ++ .../tamaya/TestConfigServiceSingletonSpi.java | 15 - .../TestPropertyAdaptersSingletonSpi.java | 66 +- .../services/org.apache.tamaya.spi.CodecSpi | 19 - .../org.apache.tamaya.spi.PropertyAdapterSpi | 19 + .../core/config/FreezedConfiguration.java | 4 +- .../core/internal/config/DefaultCodecSpi.java | 169 ---- .../config/DefaultPropertyAdapterSpi.java | 168 ++++ .../config/FallbackSimpleConfigProvider.java | 2 +- .../core/internal/config/FileConfiguration.java | 2 - .../internal/resources/io/AntPathMatcher.java | 4 +- .../AbstractClasspathAwarePropertySource.java | 3 - .../core/properties/AbstractPropertySource.java | 3 +- .../core/properties/AggregationPolicy.java | 133 +++ .../properties/BuildablePropertySource.java | 2 - .../properties/EnvironmentPropertySource.java | 3 - .../core/properties/URLBasedPropertySource.java | 1 - .../tamaya/core/spi/CodecProviderSpi.java | 36 - .../core/spi/DefaultServiceComparator.java | 85 ++ .../core/spi/DefaultServiceContextProvider.java | 112 +++ .../org/apache/tamaya/core/spi/Orderable.java | 34 + .../apache/tamaya/core/spi/OrdinalProvider.java | 37 + .../core/spi/PropertyAdapterProviderSpi.java | 36 + .../services/org.apache.tamaya.spi.CodecSpi | 19 - .../org.apache.tamaya.spi.PropertyAdapterSpi | 19 + .../apache/tamaya/ucs/UC1ReadProperties.java | 5 +- .../apache/tamaya/ucs/UC2CombineProperties.java | 5 +- docs/src/main/asciidoc/design/2_API.adoc | 469 ++++++++++ .../main/asciidoc/design/2_CoreConcepts.adoc | 849 ------------------- docs/src/main/asciidoc/design/3_Core.adoc | 356 ++++++++ docs/src/main/asciidoc/design/3_Extensions.adoc | 841 ------------------ docs/src/main/asciidoc/design/4_Extensions.adoc | 841 ++++++++++++++++++ .../asciidoc/usecases/se/combine-configs.adoc | 14 + .../se/context-dependent-configuration.adoc | 7 + .../usecases/se/dynamic-provisioning.adoc | 17 + .../usecases/se/external-configuration.adoc | 6 + docs/src/main/asciidoc/usecases/se/formats.adoc | 7 + .../main/asciidoc/usecases/se/injection.adoc | 31 + docs/src/main/asciidoc/usecases/se/java8.adoc | 13 + .../main/asciidoc/usecases/se/locations.adoc | 9 + .../main/asciidoc/usecases/se/management.adoc | 7 + .../usecases/se/minimal-propertysource.adoc | 6 + .../usecases/se/multiple-configurations.adoc | 14 + .../usecases/se/scannable-properties.adoc | 4 + .../asciidoc/usecases/se/service-context.adoc | 14 + .../asciidoc/usecases/se/simple-access.adoc | 18 + .../usecases/se/simple-property-access.adoc | 7 + .../main/asciidoc/usecases/se/templates.adoc | 11 + .../usecases/se/type-safe-properties.adoc | 10 + .../usecases/se/value-placeholders.adoc | 8 + docs/src/main/asciidoc/usecases/usecases.adoc | 19 + 63 files changed, 2695 insertions(+), 2517 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/api/src/main/java/org/apache/tamaya/AggregationPolicy.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/tamaya/AggregationPolicy.java b/api/src/main/java/org/apache/tamaya/AggregationPolicy.java deleted file mode 100644 index c0f7cc0..0000000 --- a/api/src/main/java/org/apache/tamaya/AggregationPolicy.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.tamaya; - -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 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/a60570e8/api/src/main/java/org/apache/tamaya/Configuration.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/tamaya/Configuration.java b/api/src/main/java/org/apache/tamaya/Configuration.java index 543a515..8254e3a 100644 --- a/api/src/main/java/org/apache/tamaya/Configuration.java +++ b/api/src/main/java/org/apache/tamaya/Configuration.java @@ -22,7 +22,6 @@ import org.apache.tamaya.spi.ConfigurationSpi; import org.apache.tamaya.spi.ServiceContext; import java.util.*; -import java.util.function.Consumer; import java.util.function.UnaryOperator; /** @@ -126,10 +125,10 @@ public interface Configuration extends PropertySource { * @throws IllegalArgumentException if the keys could not be converted to the required target * type, or no such property exists. */ - default <T> Optional<T> getAdapted(String key, Codec<T> adapter){ + default <T> Optional<T> getAdapted(String key, PropertyAdapter<T> adapter){ Optional<String> value = get(key); if(value.isPresent()) { - return Optional.ofNullable(adapter.deserialize(value.get())); + return Optional.ofNullable(adapter.adapt(value.get())); } return Optional.empty(); } @@ -137,7 +136,7 @@ public interface Configuration extends PropertySource { /** * Get the property keys as type T. This will implicitly require a corresponding {@link - * Codec} to be available that is capable current providing type T + * PropertyAdapter} to be available that is capable current providing type T * fromMap the given String keys. * * @param key the property's absolute, or relative path, e.g. @code @@ -148,7 +147,7 @@ public interface Configuration extends PropertySource { * type. */ default <T> Optional<T> get(String key, Class<T> type){ - return getAdapted(key, Codec.getInstance(type)); + return getAdapted(key, PropertyAdapter.getInstance(type)); } /** @@ -227,7 +226,6 @@ public interface Configuration extends PropertySource { * @param configurations overriding configurations to be used for evaluating the values for injection into {@code instance}, not null. * If no such config is passed, the default configurationa provided by the current * registered providers are used. - * @return the corresponding typed Configuration instance, never null. * @throws ConfigException if the configuration could not be resolved. */ public static void configure(Object instance, Configuration... configurations){ @@ -247,31 +245,4 @@ public interface Configuration extends PropertySource { return ServiceContext.getInstance().getSingleton(ConfigurationSpi.class).evaluateValue(expression, configurations); } - /** - * Add a ConfigChangeListener to the given PropertySource instance. - * @param l the listener, not null. - */ - public static void addChangeListener(Consumer<ConfigChangeSet> l){ - ServiceContext.getInstance().getSingleton(ConfigurationSpi.class).addChangeListener(l); - } - - /** - * Removes a ConfigChangeListener from the given PropertySource instance. - * @param l the listener, not null. - */ - public static void removeChangeListener(Consumer<ConfigChangeSet> l){ - ServiceContext.getInstance().getSingleton(ConfigurationSpi.class).removeChangeListener(l); - } - - /** - * Method to publish changes on a {@link org.apache.tamaya.PropertySource} to all interested parties. - * Basically this method gives an abstraction on the effective event bus design fo listeners. In a CDI context - * the CDI enterprise event bus should be used internally to do the work, whereas in a SE only environment - * a more puristic approach would be useful. - * @param configChange the change to be published, not null. - */ - public static void publishChange(ConfigChangeSet configChange){ - ServiceContext.getInstance().getSingleton(ConfigurationSpi.class).publishChange(configChange); - } - } http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/api/src/main/java/org/apache/tamaya/PropertySource.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/tamaya/PropertySource.java b/api/src/main/java/org/apache/tamaya/PropertySource.java index 2cd3af7..d0c5bc1 100644 --- a/api/src/main/java/org/apache/tamaya/PropertySource.java +++ b/api/src/main/java/org/apache/tamaya/PropertySource.java @@ -111,36 +111,6 @@ public interface PropertySource { } /** - * Reloads the {@link PropertySource}. - */ - default ConfigChangeSet load() { - // by default do nothing - return ConfigChangeSet.emptyChangeSet(this); - } - - /** - * Allows to evaluate if the provider is mutable. - * - * @return true, if the provider is mutable. - * @see #applyChanges(ConfigChangeSet) - */ - default boolean isMutable() { - return false; - } - - /** - * Apply a config change to this item. Hereby the change must be related to the same instance. - * - * @param change the config change - * @throws ConfigException if an unrelated change was passed. - * @throws UnsupportedOperationException when the configuration is not writable. - * @see #isMutable() - */ - default void applyChanges(ConfigChangeSet change) { - throw new UnsupportedOperationException("Config/properties not mutable: " + this); - } - - /** * Convert the this PropertyProvider instance to a {@link org.apache.tamaya.Configuration}. * * @return the configuration, never null. @@ -158,26 +128,11 @@ public interface PropertySource { } @Override - public boolean isMutable() { - return PropertySource.this.isMutable(); - } - - @Override - public void applyChanges(ConfigChangeSet changes) { - PropertySource.this.applyChanges(changes); - } - - @Override public boolean isEmpty() { return PropertySource.this.isEmpty(); } @Override - public ConfigChangeSet load() { - return PropertySource.this.load(); - } - - @Override public Optional<String> get(String key) { return PropertySource.this.get(key); } http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/api/src/main/java/org/apache/tamaya/annotation/ConfiguredProperty.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/tamaya/annotation/ConfiguredProperty.java b/api/src/main/java/org/apache/tamaya/annotation/ConfiguredProperty.java index a29ef8b..21d4e3a 100644 --- a/api/src/main/java/org/apache/tamaya/annotation/ConfiguredProperty.java +++ b/api/src/main/java/org/apache/tamaya/annotation/ConfiguredProperty.java @@ -25,7 +25,7 @@ import java.lang.annotation.*; * a configuration template method. Hereby this annotation can be used in multiple ways and combined * with other annotations such as {@link org.apache.tamaya.annotation.DefaultValue}, * {@link org.apache.tamaya.annotation.WithLoadPolicy}, {@link org.apache.tamaya.annotation.WithConfig}, - * {@link org.apache.tamaya.annotation.WithConfigOperator}, {@link WithCodec}. + * {@link org.apache.tamaya.annotation.WithConfigOperator}, {@link WithPropertyAdapter}. * * Below the most simple variant current a configured class is given: * {@code http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/api/src/main/java/org/apache/tamaya/annotation/WithCodec.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/tamaya/annotation/WithCodec.java b/api/src/main/java/org/apache/tamaya/annotation/WithCodec.java deleted file mode 100644 index 465d7b3..0000000 --- a/api/src/main/java/org/apache/tamaya/annotation/WithCodec.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.tamaya.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.apache.tamaya.Codec; - -/** - * Annotation to define a type adapter to be used before injecting a configured keys, or for applying changes. - * This will override any other adapter for performing the type conversion before - * injecting the field keys. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(value = { ElementType.FIELD, ElementType.METHOD }) -public @interface WithCodec { - - /** - * Define a custom adapter or codec that should be used to deserialize the configuration entry injected. This overrides any - * general org.apache.tamaya.core.internal registered. If no adapter is defined (default) and no corresponding adapter is - * registered, it is handled as a deployment error. - */ - @SuppressWarnings("rawtypes") - Class<? extends Codec> value(); - -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/api/src/main/java/org/apache/tamaya/annotation/WithConfigOperator.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/tamaya/annotation/WithConfigOperator.java b/api/src/main/java/org/apache/tamaya/annotation/WithConfigOperator.java index 0ede2c2..9f6c4f5 100644 --- a/api/src/main/java/org/apache/tamaya/annotation/WithConfigOperator.java +++ b/api/src/main/java/org/apache/tamaya/annotation/WithConfigOperator.java @@ -36,7 +36,7 @@ import java.util.function.UnaryOperator; public @interface WithConfigOperator { /** - * Define a custom adapter that should be used to deserialize the configuration entry injected. This overrides any + * Define a custom adapter that should be used to adapt the configuration entry injected. This overrides any * general org.apache.tamaya.core.internal registered. If no adapter is defined (default) and no corresponding adapter is * registered, it is handled as a deployment error. */ http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/api/src/main/java/org/apache/tamaya/annotation/WithPropertyAdapter.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/tamaya/annotation/WithPropertyAdapter.java b/api/src/main/java/org/apache/tamaya/annotation/WithPropertyAdapter.java new file mode 100644 index 0000000..fa9cfdf --- /dev/null +++ b/api/src/main/java/org/apache/tamaya/annotation/WithPropertyAdapter.java @@ -0,0 +1,45 @@ +/* + * 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.annotation; + +import org.apache.tamaya.PropertyAdapter; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to define a type adapter to be used before injecting a configured keys, or for applying changes. + * This will override any other adapter for performing the type conversion before + * injecting the field keys. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value = { ElementType.FIELD, ElementType.METHOD }) +public @interface WithPropertyAdapter { + + /** + * Define a custom adapter or codec that should be used to adapt the configuration entry injected. This overrides any + * general org.apache.tamaya.core.internal registered. If no adapter is defined (default) and no corresponding adapter is + * registered, it is handled as a deployment error. + */ + @SuppressWarnings("rawtypes") + Class<? extends PropertyAdapter> value(); + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/api/src/main/java/org/apache/tamaya/spi/CodecSpi.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/tamaya/spi/CodecSpi.java b/api/src/main/java/org/apache/tamaya/spi/CodecSpi.java deleted file mode 100644 index 7a0670b..0000000 --- a/api/src/main/java/org/apache/tamaya/spi/CodecSpi.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.tamaya.spi; - -import org.apache.tamaya.Codec; -import org.apache.tamaya.annotation.WithCodec; - -import java.util.Objects; -import java.util.function.Function; - -/** - * SPI that is used by the {@link org.apache.tamaya.Codecs} singleton as delegation instance. - */ -public interface CodecSpi { - - /** - * Registers a new PropertyAdapter for the given target type, hereby replacing any existing adapter for - * this type. - * @param targetType The target class, not null. - * @param adapter The adapter, not null. - * @param <T> The target type - * @return any adapter replaced with the new adapter, or null. - */ - <T> Codec<T> register(Class<T> targetType, Codec<T> adapter); - - default <T> Codec<T> register(Class<T> targetType, Function<String,T> decoder, Function<T, String> encoder){ - Objects.requireNonNull(targetType); - Objects.requireNonNull(decoder); - Objects.requireNonNull(encoder); - return register(targetType, new Codec<T>(){ - - @Override - public T deserialize(String value) { - return decoder.apply(value); - } - - @Override - public String serialize(T value) { - return encoder.apply(value); - } - - @Override - public String toString(){ - return "Codec(decoder="+decoder.getClass().getName()+", encoder="+encoder.getClass().getName()+")"; - } - }); - } - - /** - * Get an adapter converting to the given target type. - * @param targetType the target type class - * @return true, if the given target type is supported. - */ - default <T> Codec<T> getAdapter(Class<T> targetType){ - return getCodec(targetType, null); - } - - /** - * Get an adapter converting to the given target type. - * @param targetType the target type class - * @param <T> the target type - * @return the corresponding adapter, never null. - * @throws org.apache.tamaya.ConfigException if the target type is not supported. - */ - <T> Codec<T> getCodec(Class<T> targetType, WithCodec annotation); - - /** - * Checks if the given target type is supported, i.e. a adapter is registered and accessible. - * @param targetType the target type class - * @return true, if the given target type is supported. - */ - boolean isTargetTypeSupported(Class<?> targetType); -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/api/src/main/java/org/apache/tamaya/spi/DefaultServiceComparator.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/tamaya/spi/DefaultServiceComparator.java b/api/src/main/java/org/apache/tamaya/spi/DefaultServiceComparator.java deleted file mode 100644 index c53a52d..0000000 --- a/api/src/main/java/org/apache/tamaya/spi/DefaultServiceComparator.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.tamaya.spi; - -import java.util.*; - -/** - * Simple comparator based on a Collection of {@link org.apache.tamaya.spi.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/a60570e8/api/src/main/java/org/apache/tamaya/spi/DefaultServiceContextProvider.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/tamaya/spi/DefaultServiceContextProvider.java b/api/src/main/java/org/apache/tamaya/spi/DefaultServiceContextProvider.java index 295bab7..e1d1740 100644 --- a/api/src/main/java/org/apache/tamaya/spi/DefaultServiceContextProvider.java +++ b/api/src/main/java/org/apache/tamaya/spi/DefaultServiceContextProvider.java @@ -33,12 +33,6 @@ class DefaultServiceContextProvider implements ServiceContext { 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) { @@ -94,9 +88,6 @@ class DefaultServiceContextProvider implements ServiceContext { 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; http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/api/src/main/java/org/apache/tamaya/spi/Orderable.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/tamaya/spi/Orderable.java b/api/src/main/java/org/apache/tamaya/spi/Orderable.java deleted file mode 100644 index 56a99d7..0000000 --- a/api/src/main/java/org/apache/tamaya/spi/Orderable.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.tamaya.spi; - -/** - * 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/a60570e8/api/src/main/java/org/apache/tamaya/spi/OrdinalProvider.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/tamaya/spi/OrdinalProvider.java b/api/src/main/java/org/apache/tamaya/spi/OrdinalProvider.java deleted file mode 100644 index aad8618..0000000 --- a/api/src/main/java/org/apache/tamaya/spi/OrdinalProvider.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.tamaya.spi; - -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 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/a60570e8/api/src/main/java/org/apache/tamaya/spi/PropertyAdapterSpi.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/tamaya/spi/PropertyAdapterSpi.java b/api/src/main/java/org/apache/tamaya/spi/PropertyAdapterSpi.java new file mode 100644 index 0000000..a1222a4 --- /dev/null +++ b/api/src/main/java/org/apache/tamaya/spi/PropertyAdapterSpi.java @@ -0,0 +1,72 @@ +/* + * 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.PropertyAdapter; +import org.apache.tamaya.annotation.WithPropertyAdapter; + + +/** + * Manager for {@link org.apache.tamaya.Configuration} instances. Implementations must register an instance + * using the {@link org.apache.tamaya.spi.ServiceContextManager} mechanism in place (by default this is based on the {@link java.util.ServiceLoader}. + * The {@link org.apache.tamaya.Configuration} Singleton in the API delegates its corresponding calls to the + * instance returned by the current bootstrap service in place. + * + * @see org.apache.tamaya.Configuration + * @see org.apache.tamaya.spi.ServiceContextManager + */ +public interface PropertyAdapterSpi { + + + /** + * Registers a new PropertyAdapter for the given target type, hereby replacing any existing adapter for + * this type. + * @param targetType The target class, not null. + * @param adapter The adapter, not null. + * @param <T> The target type + * @return any adapter replaced with the new adapter, or null. + */ + <T> PropertyAdapter<T> register(Class<T> targetType, PropertyAdapter<T> adapter); + + /** + * Get an adapter converting to the given target type. + * @param targetType the target type class + * @return true, if the given target type is supported. + */ + default <T> PropertyAdapter<T> getAdapter(Class<T> targetType){ + return getPropertyAdapter(targetType, null); + } + + /** + * Get an adapter converting to the given target type. + * @param targetType the target type class + * @param <T> the target type + * @return the corresponding adapter, never null. + * @throws org.apache.tamaya.ConfigException if the target type is not supported. + */ + <T> PropertyAdapter<T> getPropertyAdapter(Class<T> targetType, WithPropertyAdapter annotation); + + /** + * Checks if the given target type is supported, i.e. a adapter is registered and accessible. + * @param targetType the target type class + * @return true, if the given target type is supported. + */ + boolean isTargetTypeSupported(Class<?> targetType); +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/api/src/test/java/org/apache/tamaya/TestConfigServiceSingletonSpi.java ---------------------------------------------------------------------- diff --git a/api/src/test/java/org/apache/tamaya/TestConfigServiceSingletonSpi.java b/api/src/test/java/org/apache/tamaya/TestConfigServiceSingletonSpi.java index 0ec2aa0..858786d 100644 --- a/api/src/test/java/org/apache/tamaya/TestConfigServiceSingletonSpi.java +++ b/api/src/test/java/org/apache/tamaya/TestConfigServiceSingletonSpi.java @@ -87,19 +87,4 @@ public class TestConfigServiceSingletonSpi implements ConfigurationSpi { return expression; } - @Override - public void addChangeListener(Consumer<ConfigChangeSet> l) { - // ignore - } - - @Override - public void removeChangeListener(Consumer<ConfigChangeSet> l) { - // ignore - } - - @Override - public void publishChange(ConfigChangeSet configChangeSet) { - // ignore - } - } http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/api/src/test/java/org/apache/tamaya/TestPropertyAdaptersSingletonSpi.java ---------------------------------------------------------------------- diff --git a/api/src/test/java/org/apache/tamaya/TestPropertyAdaptersSingletonSpi.java b/api/src/test/java/org/apache/tamaya/TestPropertyAdaptersSingletonSpi.java index b27164c..65e6c1d 100644 --- a/api/src/test/java/org/apache/tamaya/TestPropertyAdaptersSingletonSpi.java +++ b/api/src/test/java/org/apache/tamaya/TestPropertyAdaptersSingletonSpi.java @@ -29,71 +29,71 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import org.apache.tamaya.annotation.WithCodec; -import org.apache.tamaya.spi.CodecSpi; +import org.apache.tamaya.annotation.WithPropertyAdapter; +import org.apache.tamaya.spi.PropertyAdapterSpi; /** - * Test implementation current {@link org.apache.tamaya.spi.CodecSpi}, which provides codecs + * Test implementation current {@link org.apache.tamaya.spi.PropertyAdapterSpi}, which provides propertyAdapters * for some basic types. */ @SuppressWarnings({"unchecked", "rawtypes"}) -public final class TestPropertyAdaptersSingletonSpi implements CodecSpi { +public final class TestPropertyAdaptersSingletonSpi implements PropertyAdapterSpi { - private Map<Class, Codec<?>> codecs = new ConcurrentHashMap<>(); + private Map<Class, PropertyAdapter<?>> propertyAdapters = new ConcurrentHashMap<>(); private TestPropertyAdaptersSingletonSpi(){ - register(char.class, (s) -> s.charAt(0), (ch) -> String.valueOf(ch)); - register(int.class, Integer::parseInt, Object::toString); - register(byte.class, Byte::parseByte, Object::toString); - register(short.class, Short::parseShort, Object::toString); - register(boolean.class, Boolean::parseBoolean, b -> String.valueOf(b)); - register(float.class, Float::parseFloat, f -> String.valueOf(f)); - register(double.class, Double::parseDouble, d -> String.valueOf(d)); + register(char.class, (s) -> s.charAt(0)); + register(int.class, Integer::parseInt); + register(byte.class, Byte::parseByte); + register(short.class, Short::parseShort); + register(boolean.class, Boolean::parseBoolean); + register(float.class, Float::parseFloat); + register(double.class, Double::parseDouble); - register(Character.class, (s) -> s.charAt(0), Object::toString); - register(Integer.class, Integer::valueOf, Object::toString); - register(Byte.class, Byte::valueOf, Object::toString); - register(Short.class, Short::valueOf, String::valueOf); - register(Boolean.class, Boolean::valueOf, String::valueOf); - register(Float.class, Float::valueOf, String::valueOf); - register(Double.class, Double::valueOf, String::valueOf); - register(BigDecimal.class, BigDecimal::new, String::valueOf); - register(BigInteger.class, BigInteger::new, String::valueOf); + register(Character.class, (s) -> s.charAt(0)); + register(Integer.class, Integer::valueOf); + register(Byte.class, Byte::valueOf); + register(Short.class, Short::valueOf); + register(Boolean.class, Boolean::valueOf); + register(Float.class, Float::valueOf); + register(Double.class, Double::valueOf); + register(BigDecimal.class, BigDecimal::new); + register(BigInteger.class, BigInteger::new); - register(Currency.class, Currency::getInstance, Object::toString); + register(Currency.class, Currency::getInstance); - register(LocalDate.class, LocalDate::parse, Object::toString); - register(LocalTime.class, LocalTime::parse, Object::toString); - register(LocalDateTime.class, LocalDateTime::parse, Object::toString); - register(ZoneId.class, ZoneId::of, ZoneId::getId); + register(LocalDate.class, LocalDate::parse); + register(LocalTime.class, LocalTime::parse); + register(LocalDateTime.class, LocalDateTime::parse); + register(ZoneId.class, ZoneId::of); } @Override - public <T> Codec<T> register(Class<T> targetType, Codec<T> codec){ + public <T> PropertyAdapter<T> register(Class<T> targetType, PropertyAdapter<T> codec){ Objects.requireNonNull(targetType); Objects.requireNonNull(codec); - return (Codec<T>) codecs.put(targetType, codec); + return (PropertyAdapter<T>) propertyAdapters.put(targetType, codec); } @Override - public <T> Codec<T> getCodec(Class<T> targetType, WithCodec annotation){ + public <T> PropertyAdapter<T> getPropertyAdapter(Class<T> targetType, WithPropertyAdapter annotation){ if(annotation!=null){ Class<?> adapterType = annotation.value(); - if(!adapterType.equals(Codec.class)){ + if(!adapterType.equals(PropertyAdapter.class)){ try{ - return (Codec<T>)adapterType.newInstance(); + return (PropertyAdapter<T>)adapterType.newInstance(); } catch(Exception e){ throw new ConfigException("Failed to load PropertyAdapter: " + adapterType, e); } } } - return (Codec<T>) codecs.get(targetType); + return (PropertyAdapter<T>) propertyAdapters.get(targetType); } @Override public boolean isTargetTypeSupported(Class<?> targetType){ - return codecs.containsKey(targetType); + return propertyAdapters.containsKey(targetType); } } http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/api/src/test/resources/META-INF/services/org.apache.tamaya.spi.CodecSpi ---------------------------------------------------------------------- diff --git a/api/src/test/resources/META-INF/services/org.apache.tamaya.spi.CodecSpi b/api/src/test/resources/META-INF/services/org.apache.tamaya.spi.CodecSpi deleted file mode 100644 index e9b04b4..0000000 --- a/api/src/test/resources/META-INF/services/org.apache.tamaya.spi.CodecSpi +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy current the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -org.apache.tamaya.TestPropertyAdaptersSingletonSpi http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/api/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertyAdapterSpi ---------------------------------------------------------------------- diff --git a/api/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertyAdapterSpi b/api/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertyAdapterSpi new file mode 100644 index 0000000..e9b04b4 --- /dev/null +++ b/api/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertyAdapterSpi @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy current the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +org.apache.tamaya.TestPropertyAdaptersSingletonSpi http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/core/src/main/java/org/apache/tamaya/core/config/FreezedConfiguration.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/config/FreezedConfiguration.java b/core/src/main/java/org/apache/tamaya/core/config/FreezedConfiguration.java index 240ccbe..43d6957 100644 --- a/core/src/main/java/org/apache/tamaya/core/config/FreezedConfiguration.java +++ b/core/src/main/java/org/apache/tamaya/core/config/FreezedConfiguration.java @@ -22,9 +22,7 @@ import org.apache.tamaya.*; import org.apache.tamaya.core.properties.PropertySourceBuilder; import java.io.Serializable; -import java.time.Instant; import java.util.Map; -import java.util.Objects; /** * Configuration implementation that stores all current values current a given (possibly dynamic, contextual and non remote @@ -41,7 +39,7 @@ final class FreezedConfiguration extends AbstractConfiguration implements Serial */ private FreezedConfiguration(Configuration config){ super(config.getName()); - this.properties = PropertySourceBuilder.of(config).buildFreezed(); + this.properties = PropertySourceBuilder.of(config).buildFrozen(); } public static final Configuration of(Configuration config){ http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultCodecSpi.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultCodecSpi.java b/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultCodecSpi.java deleted file mode 100644 index fbbf130..0000000 --- a/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultCodecSpi.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.tamaya.core.internal.config; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.ZoneId; -import java.util.Currency; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; - -import org.apache.tamaya.Codec; -import org.apache.tamaya.ConfigException; -import org.apache.tamaya.annotation.WithCodec; -import org.apache.tamaya.spi.CodecSpi; - -/** - * Default codecs singleton, which provides default codesc for all kind of classes out of the box, which will be - * instantiatable from configuration, if one of the following is given: - * <ul> - * <li>static factory methods using a String as simgle argument, called {@code of, valueOf, getInstance, instance, parse}</li> - * <li>have constructors taking a single String</li> - * </ul> - */ -@SuppressWarnings({"rawtypes", "unchecked"}) -public class DefaultCodecSpi implements CodecSpi { - - - private Map<Class,Codec> adapters = new ConcurrentHashMap<>(); - - public DefaultCodecSpi(){ - // Add default adapters - register(char.class, (s) -> s.charAt(0), (ch) -> String.valueOf(ch)); - register(byte.class, Byte::parseByte, Object::toString); - register(short.class, Short::parseShort, Object::toString); - register(int.class, Integer::parseInt, Object::toString); - register(long.class, Long::parseLong, Object::toString); - register(boolean.class, Boolean::parseBoolean, b -> String.valueOf(b)); - register(float.class, Float::parseFloat, f -> String.valueOf(f)); - register(double.class, Double::parseDouble, d -> String.valueOf(d)); - - register(Character.class, (s) -> s.charAt(0), Object::toString); - register(Byte.class, Byte::valueOf, Object::toString); - register(Short.class, Short::valueOf, String::valueOf); - register(Integer.class, Integer::valueOf, Object::toString); - register(Long.class, Long::valueOf, Object::toString); - register(Boolean.class, Boolean::valueOf, b -> String.valueOf(b)); - register(Float.class, Float::valueOf, f -> String.valueOf(f)); - register(Double.class, Double::valueOf, d -> String.valueOf(d)); - register(BigDecimal.class, BigDecimal::new, String::valueOf); - register(BigInteger.class, BigInteger::new, String::valueOf); - - register(Currency.class, Currency::getInstance, Object::toString); - - register(LocalDate.class, LocalDate::parse, Object::toString); - register(LocalTime.class, LocalTime::parse, Object::toString); - register(LocalDateTime.class, LocalDateTime::parse, Object::toString); - register(ZoneId.class, ZoneId::of, ZoneId::getId); - } - - @Override - public <T> Codec<T> register(Class<T> targetType, Codec<T> adapter){ - return adapters.put(targetType, adapter); - } - - @Override - public <T> Codec<T> getCodec(Class<T> targetType, WithCodec adapterAnnot){ - Codec codec = null; - Class<? extends Codec> configuredCodec = null; - if(adapterAnnot != null){ - configuredCodec = adapterAnnot.value(); - if(!configuredCodec.equals(Codec.class)){ - try{ - codec = configuredCodec.newInstance(); - } - catch(Exception e){ - throw new ConfigException("Invalid codec configured.", e); - } - } - } - if(codec == null){ - codec = adapters.get(targetType); - } - if(codec == null){ - codec = getDefaultCodec(targetType); - } - if(codec == null){ - throw new ConfigException("No Codec found for " + targetType.getName()); - } - return codec; - } - - private <T> Codec getDefaultCodec(Class<T> targetType) { - Function<String, T> decoder = null; - Method factoryMethod = getFactoryMethod(targetType, "of", "valueOf", "instanceOf", "getInstance", "from", "parse"); - if(factoryMethod!=null){ - decoder = (s) -> { - try{ - factoryMethod.setAccessible(true); - return targetType.cast(factoryMethod.invoke(s)); - } - catch (Exception e){ - throw new ConfigException("Failed to decode '"+s+"'", e); - } - }; - } - if(decoder==null) { - try { - Constructor<T> constr = targetType.getDeclaredConstructor(String.class); - decoder = (s) -> { - try{ - constr.setAccessible(true); - return constr.newInstance(s); - } - catch (Exception e){ - throw new ConfigException("Failed to decode '"+s+"'", e); - } - }; - } catch (Exception e) { - // ignore, TODO log finest - } - } - if(decoder!=null) { - return register(targetType, decoder, String::valueOf); - } - return null; - } - - private Method getFactoryMethod(Class<?> type, String... methodNames) { - Method m; - for(String name:methodNames){ - try{ - m = type.getDeclaredMethod(name, String.class); - return m; - } - catch(Exception e){ - // ignore, TODO log finest - } - } - return null; - } - - @Override - public boolean isTargetTypeSupported(Class<?> targetType){ - return adapters.containsKey(targetType); - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultPropertyAdapterSpi.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultPropertyAdapterSpi.java b/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultPropertyAdapterSpi.java new file mode 100644 index 0000000..f1b14e0 --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/internal/config/DefaultPropertyAdapterSpi.java @@ -0,0 +1,168 @@ +/* + * 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.internal.config; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.util.Currency; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tamaya.ConfigException; +import org.apache.tamaya.PropertyAdapter; +import org.apache.tamaya.annotation.WithPropertyAdapter; +import org.apache.tamaya.spi.PropertyAdapterSpi; + +/** + * Default codecs singleton, which provides default codesc for all kind of classes out of the box, which will be + * instantiatable from configuration, if one of the following is given: + * <ul> + * <li>static factory methods using a String as simgle argument, called {@code of, valueOf, getInstance, instance, parse}</li> + * <li>have constructors taking a single String</li> + * </ul> + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +public class DefaultPropertyAdapterSpi implements PropertyAdapterSpi { + + + private Map<Class,PropertyAdapter> adapters = new ConcurrentHashMap<>(); + + public DefaultPropertyAdapterSpi(){ + // Add default adapters + register(char.class, (s) -> s.charAt(0)); + register(byte.class, Byte::parseByte); + register(short.class, Short::parseShort); + register(int.class, Integer::parseInt); + register(long.class, Long::parseLong); + register(boolean.class, Boolean::parseBoolean); + register(float.class, Float::parseFloat); + register(double.class, Double::parseDouble); + + register(Character.class, (s) -> s.charAt(0)); + register(Byte.class, Byte::valueOf); + register(Short.class, Short::valueOf); + register(Integer.class, Integer::valueOf); + register(Long.class, Long::valueOf); + register(Boolean.class, Boolean::valueOf); + register(Float.class, Float::valueOf); + register(Double.class, Double::valueOf); + register(BigDecimal.class, BigDecimal::new); + register(BigInteger.class, BigInteger::new); + + register(Currency.class, Currency::getInstance); + + register(LocalDate.class, LocalDate::parse); + register(LocalTime.class, LocalTime::parse); + register(LocalDateTime.class, LocalDateTime::parse); + register(ZoneId.class, ZoneId::of); + } + + @Override + public <T> PropertyAdapter<T> register(Class<T> targetType, PropertyAdapter<T> adapter){ + return adapters.put(targetType, adapter); + } + + @Override + public <T> PropertyAdapter<T> getPropertyAdapter(Class<T> targetType, WithPropertyAdapter adapterAnnot){ + PropertyAdapter codec = null; + Class<? extends PropertyAdapter> configuredCodec = null; + if(adapterAnnot != null){ + configuredCodec = adapterAnnot.value(); + if(!configuredCodec.equals(PropertyAdapter.class)){ + try{ + codec = configuredCodec.newInstance(); + } + catch(Exception e){ + throw new ConfigException("Invalid codec configured.", e); + } + } + } + if(codec == null){ + codec = adapters.get(targetType); + } + if(codec == null){ + codec = getDefaultPropertyAdapter(targetType); + } + if(codec == null){ + throw new ConfigException("No Codec found for " + targetType.getName()); + } + return codec; + } + + private <T> PropertyAdapter getDefaultPropertyAdapter(Class<T> targetType) { + PropertyAdapter<T> decoder = null; + Method factoryMethod = getFactoryMethod(targetType, "of", "valueOf", "instanceOf", "getInstance", "from", "parse"); + if(factoryMethod!=null){ + decoder = (s) -> { + try{ + factoryMethod.setAccessible(true); + return targetType.cast(factoryMethod.invoke(s)); + } + catch (Exception e){ + throw new ConfigException("Failed to decode '"+s+"'", e); + } + }; + } + if(decoder==null) { + try { + Constructor<T> constr = targetType.getDeclaredConstructor(String.class); + decoder = (s) -> { + try{ + constr.setAccessible(true); + return constr.newInstance(s); + } + catch (Exception e){ + throw new ConfigException("Failed to decode '"+s+"'", e); + } + }; + } catch (Exception e) { + // ignore, TODO log finest + } + } + if(decoder!=null) { + return register(targetType, decoder); + } + return null; + } + + private Method getFactoryMethod(Class<?> type, String... methodNames) { + Method m; + for(String name:methodNames){ + try{ + m = type.getDeclaredMethod(name, String.class); + return m; + } + catch(Exception e){ + // ignore, TODO log finest + } + } + return null; + } + + @Override + public boolean isTargetTypeSupported(Class<?> targetType){ + return adapters.containsKey(targetType); + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/core/src/main/java/org/apache/tamaya/core/internal/config/FallbackSimpleConfigProvider.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/config/FallbackSimpleConfigProvider.java b/core/src/main/java/org/apache/tamaya/core/internal/config/FallbackSimpleConfigProvider.java index 42140c7..7f997e5 100644 --- a/core/src/main/java/org/apache/tamaya/core/internal/config/FallbackSimpleConfigProvider.java +++ b/core/src/main/java/org/apache/tamaya/core/internal/config/FallbackSimpleConfigProvider.java @@ -1,7 +1,7 @@ package org.apache.tamaya.core.internal.config; -import org.apache.tamaya.AggregationPolicy; import org.apache.tamaya.Configuration; +import org.apache.tamaya.core.properties.AggregationPolicy; import org.apache.tamaya.core.properties.PropertySourceBuilder; import org.apache.tamaya.core.spi.ConfigurationProviderSpi; http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/core/src/main/java/org/apache/tamaya/core/internal/config/FileConfiguration.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/config/FileConfiguration.java b/core/src/main/java/org/apache/tamaya/core/internal/config/FileConfiguration.java index 661bf64..8286768 100644 --- a/core/src/main/java/org/apache/tamaya/core/internal/config/FileConfiguration.java +++ b/core/src/main/java/org/apache/tamaya/core/internal/config/FileConfiguration.java @@ -3,10 +3,8 @@ package org.apache.tamaya.core.internal.config; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.UUID; import org.apache.tamaya.Configuration; -import org.apache.tamaya.MetaInfo; /** * Implementation of Configuration which the information is from xml or properties files. http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/core/src/main/java/org/apache/tamaya/core/internal/resources/io/AntPathMatcher.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/resources/io/AntPathMatcher.java b/core/src/main/java/org/apache/tamaya/core/internal/resources/io/AntPathMatcher.java index 0fd542b..43d2a20 100644 --- a/core/src/main/java/org/apache/tamaya/core/internal/resources/io/AntPathMatcher.java +++ b/core/src/main/java/org/apache/tamaya/core/internal/resources/io/AntPathMatcher.java @@ -286,7 +286,7 @@ class AntPathMatcher { if (tokenized == null) { tokenized = tokenizePath(pattern); if (cachePatterns == null && this.tokenizedPatternCache.size() >= CACHE_TURNOFF_THRESHOLD) { - // Try to deserialize to the runtime situation that we're encountering: + // Try to adapt to the runtime situation that we're encountering: // There are obviously too many different patterns coming in here... // So let's turn off the cache since the patterns are unlikely to be reoccurring. deactivatePatternCache(); @@ -340,7 +340,7 @@ class AntPathMatcher { if (matcher == null) { matcher = new AntPathStringMatcher(pattern); if (cachePatterns == null && this.stringMatcherCache.size() >= CACHE_TURNOFF_THRESHOLD) { - // Try to deserialize to the runtime situation that we're encountering: + // Try to adapt to the runtime situation that we're encountering: // There are obviously too many different patterns coming in here... // So let's turn off the cache since the patterns are unlikely to be reoccurring. deactivatePatternCache(); http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/core/src/main/java/org/apache/tamaya/core/properties/AbstractClasspathAwarePropertySource.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/properties/AbstractClasspathAwarePropertySource.java b/core/src/main/java/org/apache/tamaya/core/properties/AbstractClasspathAwarePropertySource.java index 58fb301..47eb150 100644 --- a/core/src/main/java/org/apache/tamaya/core/properties/AbstractClasspathAwarePropertySource.java +++ b/core/src/main/java/org/apache/tamaya/core/properties/AbstractClasspathAwarePropertySource.java @@ -22,9 +22,6 @@ import org.apache.tamaya.core.resource.Resource; import org.apache.tamaya.spi.ServiceContext; import org.apache.tamaya.core.resource.ResourceLoader; -import org.apache.tamaya.MetaInfo; -import org.apache.tamaya.MetaInfoBuilder; - import java.util.*; public abstract class AbstractClasspathAwarePropertySource extends AbstractPropertySource { http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/core/src/main/java/org/apache/tamaya/core/properties/AbstractPropertySource.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/properties/AbstractPropertySource.java b/core/src/main/java/org/apache/tamaya/core/properties/AbstractPropertySource.java index 6fe3df0..fbfd6df 100644 --- a/core/src/main/java/org/apache/tamaya/core/properties/AbstractPropertySource.java +++ b/core/src/main/java/org/apache/tamaya/core/properties/AbstractPropertySource.java @@ -21,7 +21,6 @@ package org.apache.tamaya.core.properties; import java.io.Serializable; import java.util.*; -import org.apache.tamaya.MetaInfo; import org.apache.tamaya.PropertySource; /** @@ -78,7 +77,7 @@ public abstract class AbstractPropertySource implements PropertySource, Serializ @Override public String toString(){ StringBuilder b = new StringBuilder(getClass().getSimpleName()).append("{\n"); - b.append(" ").append("(").append(MetaInfo.NAME).append(" = ").append(getName()).append(")\n"); + b.append(" ").append("(").append(getName()).append(" = ").append(getName()).append(")\n"); printContents(b); return b.append('}').toString(); } http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/core/src/main/java/org/apache/tamaya/core/properties/AggregationPolicy.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/properties/AggregationPolicy.java b/core/src/main/java/org/apache/tamaya/core/properties/AggregationPolicy.java new file mode 100644 index 0000000..99be931 --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/properties/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/a60570e8/core/src/main/java/org/apache/tamaya/core/properties/BuildablePropertySource.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/properties/BuildablePropertySource.java b/core/src/main/java/org/apache/tamaya/core/properties/BuildablePropertySource.java index 33eb2a6..847fbe9 100644 --- a/core/src/main/java/org/apache/tamaya/core/properties/BuildablePropertySource.java +++ b/core/src/main/java/org/apache/tamaya/core/properties/BuildablePropertySource.java @@ -17,13 +17,11 @@ */ package org.apache.tamaya.core.properties; -import org.apache.tamaya.MetaInfo; import org.apache.tamaya.PropertySource; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.UUID; /** * Created by Anatole on 07.12.2014. http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/core/src/main/java/org/apache/tamaya/core/properties/EnvironmentPropertySource.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/properties/EnvironmentPropertySource.java b/core/src/main/java/org/apache/tamaya/core/properties/EnvironmentPropertySource.java index 9958f8d..d0b2172 100644 --- a/core/src/main/java/org/apache/tamaya/core/properties/EnvironmentPropertySource.java +++ b/core/src/main/java/org/apache/tamaya/core/properties/EnvironmentPropertySource.java @@ -18,9 +18,6 @@ */ package org.apache.tamaya.core.properties; -import org.apache.tamaya.MetaInfoBuilder; -import org.apache.tamaya.core.properties.AbstractPropertySource; - import java.util.Map; class EnvironmentPropertySource extends AbstractPropertySource { http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/core/src/main/java/org/apache/tamaya/core/properties/URLBasedPropertySource.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/properties/URLBasedPropertySource.java b/core/src/main/java/org/apache/tamaya/core/properties/URLBasedPropertySource.java index 8086c23..1d79537 100644 --- a/core/src/main/java/org/apache/tamaya/core/properties/URLBasedPropertySource.java +++ b/core/src/main/java/org/apache/tamaya/core/properties/URLBasedPropertySource.java @@ -18,7 +18,6 @@ */ package org.apache.tamaya.core.properties; -import org.apache.tamaya.AggregationPolicy; import org.apache.tamaya.ConfigException; import org.apache.tamaya.core.internal.resources.io.UrlResource; import org.apache.tamaya.core.resource.Resource; http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/core/src/main/java/org/apache/tamaya/core/spi/CodecProviderSpi.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/spi/CodecProviderSpi.java b/core/src/main/java/org/apache/tamaya/core/spi/CodecProviderSpi.java deleted file mode 100644 index b814037..0000000 --- a/core/src/main/java/org/apache/tamaya/core/spi/CodecProviderSpi.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.tamaya.core.spi; - -import org.apache.tamaya.Codec; - -/** - * This service provides different {@link org.apache.tamaya.Codec} instances for types. - */ -public interface CodecProviderSpi { - - /** - * 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> Codec<T> getCodec(Class<T> type); - -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a60570e8/core/src/main/java/org/apache/tamaya/core/spi/DefaultServiceComparator.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/spi/DefaultServiceComparator.java b/core/src/main/java/org/apache/tamaya/core/spi/DefaultServiceComparator.java new file mode 100644 index 0000000..2fb719c --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/spi/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 org.apache.tamaya.core.spi; + +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; + } +}