You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tamaya.apache.org by an...@apache.org on 2018/11/18 21:21:25 UTC
[21/22] incubator-tamaya git commit: TAMAYA-354 Support atomic
configuration, similar to config JSR.
TAMAYA-354 Support atomic configuration, similar to config JSR.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/5f3f86b0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/5f3f86b0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/5f3f86b0
Branch: refs/heads/master
Commit: 5f3f86b01582b19debbe98dd4bf056e48a3654cd
Parents: 21808ea
Author: Anatole Tresch <at...@gmail.com>
Authored: Sun Nov 18 22:15:47 2018 +0100
Committer: Anatole Tresch <at...@gmail.com>
Committed: Sun Nov 18 22:15:47 2018 +0100
----------------------------------------------------------------------
.../java/org/apache/tamaya/Configuration.java | 166 ++++++++++++++-
.../apache/tamaya/ConfigurationSnapshot.java | 92 ++++++++
.../org/apache/tamaya/spi/ChangeSupport.java | 41 ++++
.../apache/tamaya/spi/ConfigurationBuilder.java | 2 +-
.../apache/tamaya/spi/ConfigurationContext.java | 1 -
.../org/apache/tamaya/spi/PropertySource.java | 47 ++++
.../org/apache/tamaya/TestConfiguration.java | 5 +
.../tamaya/spisupport/DefaultConfiguration.java | 11 +-
.../spisupport/DefaultConfigurationBuilder.java | 6 +-
.../spisupport/DefaultConfigurationContext.java | 6 +-
.../DefaultConfigurationSnapshot.java | 212 +++++++++++++++++++
.../DefaultPropertySourceSnapshot.java | 211 ++++++++++++++++++
.../spisupport/PropertySourceChangeSupport.java | 171 +++++++++++++++
.../propertysource/BasePropertySource.java | 53 ++++-
.../propertysource/BuildablePropertySource.java | 5 +-
.../propertysource/CLIPropertySource.java | 6 +
.../EnvironmentPropertySource.java | 6 +
.../JavaConfigurationPropertySource.java | 10 +-
.../propertysource/MapPropertySource.java | 40 ++--
.../PropertiesResourcePropertySource.java | 69 ++++--
.../propertysource/SimplePropertySource.java | 6 +
.../propertysource/SystemPropertySource.java | 110 +++-------
.../propertysource/WrappedPropertySource.java | 29 +++
.../DefaultConfigurationBuilderTest.java | 12 +-
.../DefaultConfigurationSnapshotTest.java | 93 ++++++++
.../spisupport/DefaultConfigurationTest.java | 48 ++++-
.../DefaultPropertySourceSnapshotTest.java | 111 ++++++++++
27 files changed, 1417 insertions(+), 152 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/api/src/main/java/org/apache/tamaya/Configuration.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/Configuration.java b/code/api/src/main/java/org/apache/tamaya/Configuration.java
index e84add0..6b15a05 100644
--- a/code/api/src/main/java/org/apache/tamaya/Configuration.java
+++ b/code/api/src/main/java/org/apache/tamaya/Configuration.java
@@ -23,10 +23,7 @@ import org.apache.tamaya.spi.ConfigurationContext;
import org.apache.tamaya.spi.ConfigurationProviderSpi;
import org.apache.tamaya.spi.ServiceContextManager;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
+import java.util.*;
import java.util.function.Function;
import java.util.function.UnaryOperator;
@@ -68,6 +65,16 @@ public interface Configuration {
/**
* Access a property.
*
+ * @param keys the property's keys, in order of evaluation, not {@code null}.
+ * @return the property's createValue.
+ */
+ default String get(Iterable<String> keys){
+ return get(keys, TypeLiteral.of(String.class));
+ }
+
+ /**
+ * Access a property.
+ *
* @param key the property's key, not {@code null}.
* @param defaultValue createValue to be returned, if no createValue is present, not {@code null}
* @return the property's keys.
@@ -77,6 +84,17 @@ public interface Configuration {
}
/**
+ * Access a property.
+ *
+ * @param keys the property's keys, in order of evaluation, not {@code null}.
+ * @param defaultValue createValue to be returned, if no createValue is present, not {@code null}
+ * @return the property's keys.
+ */
+ default String getOrDefault(Iterable<String> keys, String defaultValue){
+ return getOrDefault(keys, TypeLiteral.of(String.class), defaultValue);
+ }
+
+ /**
* Access a String property, using an an {@link Optional} instance.
*
* @param key the property's key, not {@code null}.
@@ -87,6 +105,16 @@ public interface Configuration {
}
/**
+ * Access a String property, using an an {@link Optional} instance.
+ *
+ * @param keys the property's keys, in evaluation order, not {@code null}.
+ * @return the property's keys.
+ */
+ default Optional<String> getOptional(Iterable<String> keys){
+ return Optional.ofNullable(getOrDefault(keys, String.class, null));
+ }
+
+ /**
* Access a property, using an an {@link Optional} instance.
*
* @param key the property's key, not {@code null}.
@@ -101,6 +129,18 @@ public interface Configuration {
/**
* Access a property, using an an {@link Optional} instance.
*
+ * @param keys the property's keys, in evaluation order, not {@code null}.
+ * @param type the target type, not null.
+ * @param <T> the type of the class modeled by the type parameter
+ * @return the property's keys.
+ */
+ default <T> Optional<T> getOptional(Iterable<String> keys, Class<T> type){
+ return Optional.ofNullable(getOrDefault(keys, TypeLiteral.of(type), null));
+ }
+
+ /**
+ * Access a property, using an an {@link Optional} instance.
+ *
* @param key the property's key, not {@code null}.
* @param type the target type, not null.
* @param <T> the type of the class modeled by the type parameter
@@ -111,6 +151,18 @@ public interface Configuration {
}
/**
+ * Access a property, using an an {@link Optional} instance.
+ *
+ * @param keys the property's keys, in evaluation order, not {@code null}.
+ * @param type the target type, not null.
+ * @param <T> the type of the class modeled by the type parameter
+ * @return the property's keys.
+ */
+ default <T> Optional<T> getOptional(Iterable<String> keys, TypeLiteral<T> type){
+ return Optional.ofNullable(getOrDefault(keys, type, null));
+ }
+
+ /**
* Gets the property keys as type T. This will implicitly require a corresponding {@link
* org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T
* fromMap for the given String keys.
@@ -133,6 +185,22 @@ public interface Configuration {
* fromMap for the given String keys.
*
* @param <T> the type of the class modeled by the type parameter
+ * @param keys the property's keys, in evaluation order, not {@code null}.
+ * @param type The target type required, not {@code null}.
+ * @param defaultValue createValue to be used, if no createValue is present, not {@code null}
+ * @return the property createValue, never {@code null}.
+ * @throws ConfigException if the keys could not be converted to the required target type.
+ */
+ default <T> T getOrDefault(Iterable<String> keys, Class<T> type, T defaultValue){
+ return getOrDefault(keys, TypeLiteral.of(type), defaultValue);
+ }
+
+ /**
+ * Gets the property keys as type T. This will implicitly require a corresponding {@link
+ * org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T
+ * fromMap for the given String keys.
+ *
+ * @param <T> the type of the class modeled by the type parameter
* @param key the property's absolute, or relative path, e.g. @code
* a/b/c/d.myProperty}.
* @param type The target type required, not {@code null}.
@@ -144,6 +212,23 @@ public interface Configuration {
}
/**
+ * Gets the property keys as type T. This will implicitly require a corresponding {@link
+ * org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T
+ * fromMap for the given String keys.
+ *
+ * @param <T> the type of the class modeled by the type parameter
+ * @param keys the property's keys, in evaluation order, not {@code null}.
+ * @param type The target type required, not {@code null}.
+ * @return the property createValue, never {@code null}.
+ * @throws ConfigException if the keys could not be converted to the required target type.
+ */
+ default <T> T get(Iterable<String> keys, Class<T> type){
+ return get(keys, TypeLiteral.of(type));
+ }
+
+
+
+ /**
* Get the property keys as type T. This will implicitly require a corresponding {@link
* org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T
* literals for the given key.
@@ -163,6 +248,27 @@ public interface Configuration {
* literals for the given key.
*
* @param <T> the type of the type literal
+ * @param keys the property's keys, in evaluation order, not {@code null}.
+ * @param type The target type required, not {@code null}.
+ * @return the property createValue, never {@code null}.
+ * @throws ConfigException if the keys could not be converted to the required target type.
+ */
+ default <T> T get(Iterable<String> keys, TypeLiteral<T> type){
+ for(String k:keys){
+ T t = getOrDefault(k, type, null);
+ if(t!=null){
+ return t;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the property keys as type T. This will implicitly require a corresponding {@link
+ * org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T
+ * literals for the given key.
+ *
+ * @param <T> the type of the type literal
* @param key the property's absolute, or relative path, e.g.
* {@code a/b/c/d.myProperty}, not {@code null}.
* @param type The target type required, not {@code null}.
@@ -173,6 +279,28 @@ public interface Configuration {
<T> T getOrDefault(String key, TypeLiteral<T> type, T defaultValue);
/**
+ * Get the property keys as type T. This will implicitly require a corresponding {@link
+ * org.apache.tamaya.spi.PropertyConverter} to be available that is capable of providing type T
+ * literals for the given key.
+ *
+ * @param <T> the type of the type literal
+ * @param keys the property's keys, in evaluation order, not {@code null}.
+ * @param type The target type required, not {@code null}.
+ * @param defaultValue default createValue to be used, if no createValue is present.
+ * @return the property createValue, never null.
+ * @throws ConfigException if the keys could not be converted to the required target type.
+ */
+ default <T> T getOrDefault(Iterable<String> keys, TypeLiteral<T> type, T defaultValue){
+ for(String k:keys){
+ T t = getOrDefault(k, type, null);
+ if(t!=null){
+ return t;
+ }
+ }
+ return defaultValue;
+ }
+
+ /**
* Access all currently known configuration properties as a full {@code Map<String,String>}.
* Be aware that entries from non scannable parts of the registered {@link org.apache.tamaya.spi.PropertySource}
* instances may not be contained in the result, but nevertheless be accessible by calling one of the
@@ -240,6 +368,24 @@ public interface Configuration {
ConfigurationContext getContext();
/**
+ * Create a snapshot, which contains the given keys.
+ *
+ * @param keys the keys, not null. If empty a full snapshot with all known keys is returned.
+ * @return a corresponding snapshot instance.
+ */
+ ConfigurationSnapshot getSnapshot(Iterable<String> keys);
+
+ /**
+ * Create a snapshot, which contains all known keys.
+ *
+ * @param keys the target key. If empty a full snapshot with all known keys is returned.
+ * @return a corresponding snapshot instance.
+ */
+ default ConfigurationSnapshot getSnapshot(String... keys){
+ return getSnapshot(Arrays.asList(keys));
+ }
+
+ /**
* Create a new builder using this instance as its base.
* @return a new builder, never null.
*/
@@ -356,8 +502,18 @@ public interface Configuration {
}
@Override
+ public ConfigurationSnapshot getSnapshot(Iterable<String> keys) {
+ return ConfigurationSnapshot.EMPTY;
+ }
+
+ @Override
+ public ConfigurationSnapshot getSnapshot(String... keys) {
+ return ConfigurationSnapshot.EMPTY;
+ }
+
+ @Override
public String toString(){
- return "Configuration<empty>";
+ return "Configuration<EMPTY>";
}
};
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/api/src/main/java/org/apache/tamaya/ConfigurationSnapshot.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/ConfigurationSnapshot.java b/code/api/src/main/java/org/apache/tamaya/ConfigurationSnapshot.java
new file mode 100644
index 0000000..06b8a3a
--- /dev/null
+++ b/code/api/src/main/java/org/apache/tamaya/ConfigurationSnapshot.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya;
+
+import org.apache.tamaya.spi.ConfigurationContext;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * An immutable configuration snapshot containing the given keys only.
+ */
+public interface ConfigurationSnapshot extends Configuration{
+
+
+ /**
+ * The requested keys. Note that not all keys must be accessible as a property.
+ * @return the requested keys.
+ */
+ Set<String> getKeys();
+
+ /**
+ * Get the timestamp, when this snapshot has been taken.
+ * @return the timestamp
+ */
+ long getTimestamp();
+
+ /**
+ * An empty snapshot.
+ */
+ ConfigurationSnapshot EMPTY = new ConfigurationSnapshot() {
+
+ @Override
+ public <T> T get(String key, TypeLiteral<T> type) {
+ return null;
+ }
+
+ @Override
+ public <T> T getOrDefault(String key, TypeLiteral<T> type, T defaultValue) {
+ return defaultValue;
+ }
+
+ @Override
+ public Map<String, String> getProperties() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public ConfigurationContext getContext() {
+ return ConfigurationContext.EMPTY;
+ }
+
+ @Override
+ public ConfigurationSnapshot getSnapshot(Iterable<String> keys) {
+ return this;
+ }
+
+ @Override
+ public Set<String> getKeys() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public long getTimestamp() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "ConfigurationSnapshot<EMPTY>";
+ }
+ };
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/api/src/main/java/org/apache/tamaya/spi/ChangeSupport.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/ChangeSupport.java b/code/api/src/main/java/org/apache/tamaya/spi/ChangeSupport.java
new file mode 100644
index 0000000..43ef685
--- /dev/null
+++ b/code/api/src/main/java/org/apache/tamaya/spi/ChangeSupport.java
@@ -0,0 +1,41 @@
+/*
+ * 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.function.BiConsumer;
+
+/**
+ * Enum type that describges the config change capabilities of a property source.
+ */
+@Experimental
+public enum ChangeSupport {
+ /**
+ * Config change is supported, this config source supports registering ConfigChangeListeners.
+ * {@link PropertySource#addChangeListener(BiConsumer)} .
+ */
+ SUPPORTED,
+ /**
+ * Config change is not supported. Configuration values may change, though changes are not reported.
+ */
+ UNSUPPORTED,
+ /**
+ * Configuration properties of this property source cannot change for the lifetime of this {@link PropertySource}.
+ */
+ IMMUTABLE
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/api/src/main/java/org/apache/tamaya/spi/ConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/ConfigurationBuilder.java b/code/api/src/main/java/org/apache/tamaya/spi/ConfigurationBuilder.java
index 7ce4547..b4d67ce 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/ConfigurationBuilder.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/ConfigurationBuilder.java
@@ -180,7 +180,7 @@ public interface ConfigurationBuilder {
*
* @return the current registered property converters.
*/
- Map<TypeLiteral<?>, Collection<PropertyConverter<?>>> getPropertyConverter();
+ Map<TypeLiteral<?>, List<PropertyConverter<?>>> getPropertyConverter();
/**
* Increases the priority of the given property source, by moving it towards the end
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/api/src/main/java/org/apache/tamaya/spi/ConfigurationContext.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/ConfigurationContext.java b/code/api/src/main/java/org/apache/tamaya/spi/ConfigurationContext.java
index a9ecda1..86c3831 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/ConfigurationContext.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/ConfigurationContext.java
@@ -189,5 +189,4 @@ public interface ConfigurationContext {
}
};
-
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
----------------------------------------------------------------------
diff --git a/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java b/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
index 9ede6ce..b25bbb4 100644
--- a/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
+++ b/code/api/src/main/java/org/apache/tamaya/spi/PropertySource.java
@@ -23,6 +23,8 @@ import org.apache.tamaya.Configuration;
import java.util.Collections;
import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
/**
@@ -172,4 +174,49 @@ public interface PropertySource{
return true;
}
+ /**
+ * Get the support for reporting changes to property sources provided by this instance. This support
+ * type should never change during a property source's lifetime.
+ *
+ * @return the change support of this property source, not null.
+ */
+ @Experimental
+ default ChangeSupport getChangeSupport(){
+ return ChangeSupport.UNSUPPORTED;
+ }
+
+ /**
+ * Get the current version. A new version signals that it is known that properties have changed for this property
+ * source. This is especially useful, when {@link #getChangeSupport()} is {@link ChangeSupport#SUPPORTED}.
+ * The content and format of the version String is imeplemtation specific. We recommend to add information
+ * such as the loading timestamp, the source systems read or whatever is appropriate. By default this
+ * method returns {@code "N/A"}.
+ * @return the version this property source, never null.
+ */
+ @Experimental
+ default String getVersion(){
+ return "N/A";
+ }
+
+ /**
+ * Add a change listener for this properrty source.
+ * @param l the listner, not null.
+ */
+ @Experimental
+ default void addChangeListener(BiConsumer<Set<String>, PropertySource> l){}
+
+ /**
+ * Removes a change listener for this properrty source.
+ * @param l the listner, not null.
+ */
+ @Experimental
+ default void removeChangeListener(BiConsumer<Set<String>, PropertySource> l){}
+
+ /**
+ * Removes all registered change listeners, if any.
+ */
+ @Experimental
+ default void removeAllChangeListeners(){}
+
+
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/api/src/test/java/org/apache/tamaya/TestConfiguration.java
----------------------------------------------------------------------
diff --git a/code/api/src/test/java/org/apache/tamaya/TestConfiguration.java b/code/api/src/test/java/org/apache/tamaya/TestConfiguration.java
index bb68697..cd6eeaf 100644
--- a/code/api/src/test/java/org/apache/tamaya/TestConfiguration.java
+++ b/code/api/src/test/java/org/apache/tamaya/TestConfiguration.java
@@ -99,6 +99,11 @@ public class TestConfiguration implements Configuration {
}
@Override
+ public ConfigurationSnapshot getSnapshot(Iterable<String> keys) {
+ return ConfigurationSnapshot.EMPTY;
+ }
+
+ @Override
public Map<String, String> getProperties() {
// run toString on each createValue of the (key, createValue) setCurrent in VALUES
return VALUES.entrySet().stream().collect(
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java
index f5f65e3..47a3b4c 100644
--- a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfiguration.java
@@ -18,11 +18,7 @@
*/
package org.apache.tamaya.spisupport;
-import org.apache.tamaya.ConfigException;
-import org.apache.tamaya.ConfigOperator;
-import org.apache.tamaya.ConfigQuery;
-import org.apache.tamaya.Configuration;
-import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.*;
import org.apache.tamaya.spi.*;
import java.util.*;
@@ -263,6 +259,11 @@ public class DefaultConfiguration implements Configuration {
}
@Override
+ public ConfigurationSnapshot getSnapshot(Iterable<String> keys) {
+ return new DefaultConfigurationSnapshot(this, keys);
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilder.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilder.java
index 7be4fd8..1276daa 100644
--- a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilder.java
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilder.java
@@ -42,7 +42,7 @@ public class DefaultConfigurationBuilder implements ConfigurationBuilder {
protected ServiceContext serviceContext = ServiceContextManager.getServiceContext();
protected List<PropertyFilter> propertyFilters = new ArrayList<>();
protected List<PropertySource> propertySources = new ArrayList<>();
- protected Map<TypeLiteral<?>, Collection<PropertyConverter<?>>> propertyConverters = new HashMap<>();
+ protected Map<TypeLiteral<?>, List<PropertyConverter<?>>> propertyConverters = new HashMap<>();
protected MetadataProvider metaDataProvider = serviceContext.create(MetadataProvider.class, DefaultMetaDataProvider::new);
/**
@@ -293,7 +293,7 @@ public class DefaultConfigurationBuilder implements ConfigurationBuilder {
checkBuilderState();
Objects.requireNonNull(type);
Objects.requireNonNull(propertyConverters);
- Collection<PropertyConverter<?>> converters = this.propertyConverters.get(type);
+ List<PropertyConverter<?>> converters = this.propertyConverters.get(type);
if(converters==null){
converters = new ArrayList<>();
this.propertyConverters.put(type, converters);
@@ -345,7 +345,7 @@ public class DefaultConfigurationBuilder implements ConfigurationBuilder {
}
@Override
- public Map<TypeLiteral<?>, Collection<PropertyConverter<?>>> getPropertyConverter() {
+ public Map<TypeLiteral<?>, List<PropertyConverter<?>>> getPropertyConverter() {
return this.propertyConverters;
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContext.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContext.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContext.java
index f24be88..a6d9612 100644
--- a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContext.java
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationContext.java
@@ -75,7 +75,7 @@ public class DefaultConfigurationContext implements ConfigurationContext {
immutablePropertyFilters = Collections.unmodifiableList(propertyFilters);
// Finally add the converters
- for(Map.Entry<TypeLiteral<?>, Collection<PropertyConverter<?>>> en:builder.getPropertyConverter().entrySet()) {
+ for(Map.Entry<TypeLiteral<?>, List<PropertyConverter<?>>> en:builder.getPropertyConverter().entrySet()) {
for (@SuppressWarnings("rawtypes") PropertyConverter converter : en.getValue()) {
this.propertyConverterManager.register(en.getKey(), converter);
}
@@ -86,7 +86,7 @@ public class DefaultConfigurationContext implements ConfigurationContext {
public DefaultConfigurationContext(ServiceContext serviceContext,
List<PropertyFilter> propertyFilters, List<PropertySource> propertySources,
- Map<TypeLiteral<?>, Collection<PropertyConverter<?>>> propertyConverters,
+ Map<TypeLiteral<?>, List<PropertyConverter<?>>> propertyConverters,
MetadataProvider metaDataProvider) {
this.serviceContext = Objects.requireNonNull(serviceContext);
this.immutablePropertyFilters = Collections.unmodifiableList(new ArrayList<>(propertyFilters));
@@ -94,7 +94,7 @@ public class DefaultConfigurationContext implements ConfigurationContext {
this.metaDataProvider = Objects.requireNonNull(metaDataProvider);
this.metaDataProvider.init(this);
propertyConverterManager = new PropertyConverterManager(serviceContext);
- for(Map.Entry<TypeLiteral<?>, Collection<PropertyConverter<?>>> en:propertyConverters.entrySet()) {
+ for(Map.Entry<TypeLiteral<?>, List<PropertyConverter<?>>> en:propertyConverters.entrySet()) {
for (@SuppressWarnings("rawtypes") PropertyConverter converter : en.getValue()) {
this.propertyConverterManager.register(en.getKey(), converter);
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationSnapshot.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationSnapshot.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationSnapshot.java
new file mode 100644
index 0000000..4d86ce6
--- /dev/null
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultConfigurationSnapshot.java
@@ -0,0 +1,212 @@
+/*
+ * 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.spisupport;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationSnapshot;
+import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.PropertyConverter;
+
+import java.io.Serializable;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * /**
+ * Configuration implementation that stores all current values of a given (possibly dynamic, contextual and non server
+ * capable instance) and is fully serializable. Note that hereby only the scannable key/createValue pairs are considered.
+ */
+public class DefaultConfigurationSnapshot implements ConfigurationSnapshot, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The properties frozen.
+ */
+ private Configuration snapshot;
+ private long frozenAt = System.nanoTime();
+ private UUID id = UUID.randomUUID();
+ private transient ConfigurationContext context;
+ private Set<String> keys = new HashSet<>();
+
+ /**
+ * Constructor.
+ *
+ * @param config The base configuration.
+ * @param keys The keys to evaluate, not null.
+ */
+ public DefaultConfigurationSnapshot(Configuration config, Iterable<String> keys) {
+ for(String k:keys) {
+ this.keys.add(k);
+ }
+ ConfigurationContext ctx = config.getContext();
+ MetadataProvider metadataProvider = ctx.getServiceContext().getService(MetadataProvider.class,
+ DefaultMetaDataProvider::new);
+ context = new DefaultConfigurationContext(ctx.getServiceContext(),
+ ctx.getPropertyFilters(),
+ ctx.getPropertySources().stream()
+ .map(ps -> DefaultPropertySourceSnapshot.of(ps, this.keys)).collect(Collectors.toList()),
+ ctx.getPropertyConverters(),
+ metadataProvider);
+ this.snapshot = new DefaultConfiguration(context);
+ if(this.keys.isEmpty()){
+ this.keys.addAll(this.snapshot.getProperties().keySet());
+ }
+ this.keys = Collections.unmodifiableSet(this.keys);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param config The base configuration.
+ */
+ public DefaultConfigurationSnapshot(Configuration config) {
+ ConfigurationContext ctx = config.getContext();
+ MetadataProvider metadataProvider = ctx.getServiceContext().getService(MetadataProvider.class,
+ DefaultMetaDataProvider::new);
+ context = new DefaultConfigurationContext(ctx.getServiceContext(),
+ ctx.getPropertyFilters(),
+ ctx.getPropertySources().stream()
+ .map(ps -> new DefaultPropertySourceSnapshot(ps)).collect(Collectors.toList()),
+ ctx.getPropertyConverters(),
+ metadataProvider);
+ this.snapshot = new DefaultConfiguration(context);
+ this.keys = Collections.unmodifiableSet(this.snapshot.getProperties().keySet());
+ }
+
+
+ @Override
+ public ConfigurationSnapshot getSnapshot(Iterable<String> keys) {
+ return new DefaultConfigurationSnapshot(this, keys);
+ }
+
+ /**
+ * Get the evaluated keys of this frozen coinfiguration.
+ * @return the keys, not null.
+ */
+ public Set<String> getKeys() {
+ return keys;
+ }
+
+ @Override
+ public String get(String key) {
+ return this.snapshot.get(key);
+ }
+
+ @Override
+ public String getOrDefault(String key, String defaultValue) {
+ return this.snapshot.getOrDefault(key, defaultValue);
+ }
+
+ @Override
+ public <T> T getOrDefault(String key, Class<T> type, T defaultValue) {
+ return this.snapshot.getOrDefault(key, type, defaultValue);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T get(String key, Class<T> type) {
+ return snapshot.get(key, type);
+ }
+
+ /**
+ * Accesses the current String createValue for the given key and tries to convert it
+ * using the {@link PropertyConverter} instances provided by the current
+ * {@link ConfigurationContext}.
+ *
+ * @param key the property's absolute, or relative path, e.g. @code
+ * a/b/c/d.myProperty}.
+ * @param type The target type required, not null.
+ * @param <T> the createValue type
+ * @return the converted createValue, never null.
+ */
+ @Override
+ public <T> T get(String key, TypeLiteral<T> type) {
+ return snapshot.get(key, type);
+ }
+
+ @Override
+ public <T> T getOrDefault(String key, TypeLiteral<T> type, T defaultValue) {
+ return snapshot.getOrDefault(key, type, defaultValue);
+ }
+
+ @Override
+ public Map<String, String> getProperties() {
+ return snapshot.getProperties();
+ }
+
+ @Override
+ public ConfigurationContext getContext() {
+ return snapshot.getContext();
+ }
+
+ /**
+ * <p>Returns the moment in time when this frozen configuration has been created.</p>
+ *
+ * <p>The time is taken from {@linkplain System#currentTimeMillis()}</p>
+ *
+ * @see System#currentTimeMillis()
+ * @return the moment in time when this configuration has been created
+ */
+ @Override
+ public long getTimestamp() {
+ return frozenAt;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ DefaultConfigurationSnapshot that = (DefaultConfigurationSnapshot) o;
+
+ if (frozenAt != that.frozenAt) {
+ return false;
+ }
+ return Objects.equals(snapshot, that.snapshot);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(frozenAt, snapshot);
+ }
+
+ @Override
+ public String toString() {
+ return "FrozenConfiguration{" +
+ "id=" + getId() + "," +
+ "frozenAt=" + frozenAt + "," +
+ "config=" + snapshot +
+ '}';
+ }
+
+ /**
+ * <p>Returns the unique id of this frozen configuration.</p>
+ *
+ * @return the unique id of this frozen configuration, never {@code null}
+ */
+ public UUID getId() {
+ return id;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultPropertySourceSnapshot.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultPropertySourceSnapshot.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultPropertySourceSnapshot.java
new file mode 100644
index 0000000..7c14f5a
--- /dev/null
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/DefaultPropertySourceSnapshot.java
@@ -0,0 +1,211 @@
+/*
+ * 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.spisupport;
+
+import org.apache.tamaya.spi.ChangeSupport;
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+
+import java.io.Serializable;
+import java.util.*;
+import java.util.logging.Logger;
+
+/**
+ * PropertySource implementation that stores all current values of a given (possibly dynamic, contextual and non server
+ * capable instance) and is fully serializable. Note that hereby only the scannable key/createValue pairs are considered.
+ */
+public class DefaultPropertySourceSnapshot implements PropertySource, Serializable {
+ private static final long serialVersionUID = -6373137316556444171L;
+ private static final int MAX_SYNCH_CHECKS = 10;
+ private static final Logger LOG = Logger.getLogger(DefaultPropertySourceSnapshot.class.getName());
+
+ /**
+ * The PropertySource's name.
+ */
+ private String name;
+ /**
+ * The ordinal.
+ */
+ private int ordinal;
+ /**
+ * The properties read.
+ */
+ private Map<String, PropertyValue> properties = new HashMap<>();
+
+ private Set<String> keys = new HashSet<>();
+
+ private long frozenAt = System.currentTimeMillis();
+
+ /**
+ * Constructor.
+ *
+ * @param propertySource The base PropertySource.
+ */
+ public DefaultPropertySourceSnapshot(PropertySource propertySource) {
+ this(propertySource, propertySource.getProperties().keySet());
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param propertySource The base PropertySource.
+ * @param keys
+ */
+ public DefaultPropertySourceSnapshot(PropertySource propertySource, Iterable<String> keys) {
+ for(String k:keys){
+ this.keys.add(k);
+ }
+ if(this.keys.isEmpty()){
+ this.keys.addAll(getProperties().keySet());
+ }
+ this.keys = Collections.unmodifiableSet(this.keys);
+ this.ordinal = PropertySourceComparator.getOrdinal(propertySource);
+ this.name = propertySource.getName();
+ if(propertySource.getChangeSupport().equals(ChangeSupport.UNSUPPORTED) ||
+ propertySource.getChangeSupport().equals(ChangeSupport.IMMUTABLE)){
+ // simply get the keys and we are done. We cant do more...
+ this.properties = initProperties(propertySource, false);
+ }else{
+ this.properties = initProperties(propertySource, true);
+ }
+ }
+
+ private Map<String, PropertyValue> initProperties(PropertySource propertySource, boolean checkVersion) {
+ Map<String, PropertyValue> properties = new HashMap<>();
+ if(!checkVersion){
+ // Simply collect values and we are done
+ for(String key:keys) {
+ PropertyValue val = propertySource.get(key);
+ if(val != null) {
+ properties.put(key, val);
+ }
+ }
+ }else {
+ // Collect values, but ensure, the propert
+ String version = propertySource.getVersion();
+ String newVersion = null;
+ int checksDone = 0;
+ while (!Objects.equals(newVersion, version)) {
+ for (String key : keys) {
+ PropertyValue val = propertySource.get(key);
+ if (val != null) {
+ properties.put(key, val);
+ }
+ }
+ newVersion = propertySource.getVersion();
+ if (checksDone++ > MAX_SYNCH_CHECKS) {
+ LOG.info("Property Source is instable, will abort freeze, but inconsistent config may be possible: " + propertySource.getName());
+ break;
+ }
+
+ }
+ }
+ return Collections.unmodifiableMap(properties);
+ }
+
+ /**
+ * Creates a new FrozenPropertySource instance based on a PropertySource and the target key set given. This method
+ * uses all keys available in the property map.
+ *
+ * @param propertySource the property source to be frozen, not null.
+ * @return the frozen property source.
+ */
+ public static DefaultPropertySourceSnapshot of(PropertySource propertySource) {
+ Set<String> keySet = propertySource.getProperties().keySet();
+ return DefaultPropertySourceSnapshot.of(propertySource, keySet);
+ }
+
+ /**
+ * Creates a new FrozenPropertySource instance based on a PropertySource and the target key set given.
+ *
+ * @param propertySource the property source to be frozen, not null.
+ * @param keys the keys to be evaluated for the snapshot. Only these keys will be contained in the resulting
+ * snapshot.
+ * @return the frozen property source.
+ */
+ public static DefaultPropertySourceSnapshot of(PropertySource propertySource, Iterable<String> keys) {
+ if (propertySource instanceof DefaultPropertySourceSnapshot) {
+ DefaultPropertySourceSnapshot fps = (DefaultPropertySourceSnapshot) propertySource;
+ if(fps.getKeys().equals(keys)){
+ return fps;
+ }
+ }
+ return new DefaultPropertySourceSnapshot(propertySource, keys);
+ }
+
+ public Set<String> getKeys() {
+ return keys;
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ public int getOrdinal() {
+ return this.ordinal;
+ }
+
+ /**
+ * Get the creation timestamp of this instance.
+ * @return the creation timestamp
+ */
+ public long getFrozenAt(){
+ return frozenAt;
+ }
+
+ @Override
+ public PropertyValue get(String key) {
+ return this.properties.get(key);
+ }
+
+ @Override
+ public Map<String, PropertyValue> getProperties() {
+ return properties;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof DefaultPropertySourceSnapshot)) {
+ return false;
+ }
+ DefaultPropertySourceSnapshot that = (DefaultPropertySourceSnapshot) o;
+ return ordinal == that.ordinal && properties.equals(that.properties);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = ordinal;
+ result = 31 * result + properties.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "FrozenPropertySource{" +
+ "name=" + name +
+ ", ordinal=" + ordinal +
+ ", properties=" + properties +
+ ", frozenAt=" + frozenAt +
+ '}';
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertySourceChangeSupport.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertySourceChangeSupport.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertySourceChangeSupport.java
new file mode 100644
index 0000000..b587f91
--- /dev/null
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/PropertySourceChangeSupport.java
@@ -0,0 +1,171 @@
+/*
+ * 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.spisupport;
+
+import org.apache.tamaya.spi.ChangeSupport;
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+
+import java.util.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Simple support class for helping with change management on property sources.
+ */
+public final class PropertySourceChangeSupport {
+
+ private static final Logger LOG = Logger.getLogger(PropertySourceChangeSupport.class.getName());
+
+ private ChangeSupport changeSupport;
+ private PropertySource propertySource;
+ private AtomicLong version = new AtomicLong();
+ private List<BiConsumer<Set<String>, PropertySource>> listeners = new ArrayList<>();
+ private int oldHash = 0;
+ private Map<String, PropertyValue> valueMap;
+ private long timestamp;
+ private ScheduledFuture scheduleTask;
+
+ private static ScheduledExecutorService executorService = Executors.newScheduledThreadPool(4);
+
+ /**
+ * Create a new property change support instance.
+ * @param changeSupport the support type, not null.
+ * @param propertySource the propertySource, not null.
+ */
+ public PropertySourceChangeSupport(ChangeSupport changeSupport, PropertySource propertySource){
+ this.changeSupport = Objects.requireNonNull(changeSupport);
+ this.propertySource = Objects.requireNonNull(propertySource);
+ }
+
+ public ChangeSupport getChangeSupport() {
+ return changeSupport;
+ }
+
+ public String getVersion() {
+ return version.get() + ": timestamp="+timestamp;
+ }
+
+ public void addChangeListener(BiConsumer<Set<String>, PropertySource> l){
+ switch(changeSupport){
+ case SUPPORTED:
+ if(!listeners.contains(l)){
+ listeners.add(l);
+ }
+ break;
+ case UNSUPPORTED:
+ case IMMUTABLE:
+ default:
+ break;
+ }
+ }
+
+ public void removeChangeListener(BiConsumer<Set<String>, PropertySource> l){
+ listeners.remove(l);
+ }
+
+ public void removeAllChangeListeners(){
+ listeners.clear();
+ }
+
+ public long update(Map<String, PropertyValue> props){
+ Set<String> changedKeys = calculateChangedKeys(this.valueMap, props);
+ if(!changedKeys.isEmpty()) {
+ this.valueMap = props;
+ long newVersion = version.incrementAndGet();
+ fireListeners(changedKeys);
+ return newVersion;
+ }
+ return version.get();
+ }
+
+ private Set<String> calculateChangedKeys(Map<String, PropertyValue> valueMap, Map<String, PropertyValue> newValues) {
+ Set<String> result = new HashSet<>();
+ if(this.valueMap!=null) {
+ for (Map.Entry<String, PropertyValue> en : valueMap.entrySet()) {
+ if (!newValues.containsKey(en.getKey())) {
+ result.add(en.getKey()); // removed
+ }
+ }
+ }
+ for(Map.Entry<String, PropertyValue> en:newValues.entrySet()){
+ if(valueMap != null){
+ if(!valueMap.containsKey(en.getKey())) {
+ result.add(en.getKey()); // added
+ }if(!Objects.equals(valueMap.get(en.getKey()), en.getValue())){
+ result.add(en.getKey()); // changed
+ }
+ }else{
+ result.add(en.getKey()); // added
+ }
+ }
+ return result;
+ }
+
+ private void fireListeners(Set<String> changedKeys) {
+ for(BiConsumer<Set<String>, PropertySource> l:this.listeners){
+ try{
+ l.accept(changedKeys, propertySource);
+ }catch(Exception e){
+ LOG.log(Level.WARNING, "Failed to update listener on property source change: " + l, e);
+ }
+ }
+ }
+
+ public PropertyValue getValue(String key){
+ return valueMap.get(key);
+ }
+
+ public Map<String, PropertyValue> getProperties(){
+ if(valueMap==null){
+ return Collections.emptyMap();
+ }
+ return Collections.unmodifiableMap(valueMap);
+ }
+
+ public void scheduleChangeMonitor(Supplier<Map<String, PropertyValue>> propsSupplier, long duration, TimeUnit timeUnit){
+ scheduleTask = executorService.schedule(() -> {
+ update(propsSupplier.get());
+ }, duration, timeUnit);
+ }
+
+ public void cancelSchedule(){
+ if(scheduleTask!=null){
+ scheduleTask.cancel(false);
+ }
+ }
+
+ private int hashCode(Map<String, PropertyValue> valueMap) {
+ int result = 0;
+ for(Map.Entry<String,PropertyValue> en:valueMap.entrySet()) {
+ result = 31 * result + en.getKey().hashCode();
+ String value = en.getValue().getValue();
+ result = 31 * result + (value!=null?value.hashCode():0);
+ }
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/BasePropertySource.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/BasePropertySource.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/BasePropertySource.java
index bf75fb9..cca4d96 100644
--- a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/BasePropertySource.java
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/BasePropertySource.java
@@ -18,6 +18,7 @@
*/
package org.apache.tamaya.spisupport.propertysource;
+import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
@@ -37,6 +38,14 @@ public abstract class BasePropertySource implements PropertySource{
private volatile Integer ordinal;
/** The name of the property source. */
private String name;
+ /** The optional prefix. */
+ private String prefix;
+ /**
+ * If true, this property source does not return any properties. This is useful since this
+ * property source is applied by default, but can be switched off by setting the
+ * {@code tamaya.envprops.disable} system/environment property to {@code true}.
+ */
+ private boolean disabled = false;
/**
* Constructor.
@@ -66,7 +75,6 @@ public abstract class BasePropertySource implements PropertySource{
this.defaultOrdinal = defaultOrdinal;
}
-
/**
* Constructor, using a default ordinal of 0.
*/
@@ -76,6 +84,9 @@ public abstract class BasePropertySource implements PropertySource{
@Override
public String getName() {
+ if(disabled){
+ return name + "(disabled)";
+ }
return name;
}
@@ -142,6 +153,22 @@ public abstract class BasePropertySource implements PropertySource{
return val;
}
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public boolean isDisabled() {
+ return disabled;
+ }
+
+ public void setDisabled(boolean disabled) {
+ this.disabled = disabled;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -167,6 +194,30 @@ public abstract class BasePropertySource implements PropertySource{
protected String toStringValues() {
return " defaultOrdinal=" + defaultOrdinal + '\n' +
" ordinal=" + ordinal + '\n' +
+ " prefix=" + prefix + '\n' +
+ " disabled=" + disabled + '\n' +
" name='" + name + '\'' + '\n';
}
+
+ protected Map<String,PropertyValue> mapProperties(Map<String, String> props, long timestamp) {
+ Map<String,PropertyValue> result = new HashMap<>();
+ String timestampVal = String.valueOf(timestamp);
+ if (prefix == null) {
+ for (Map.Entry<String, String> en : props.entrySet()) {
+ result.put(en.getKey(),
+ PropertyValue.createValue(en.getKey(), en.getValue())
+ .setMeta("source", getName())
+ .setMeta("timestamp", timestampVal));
+ }
+ } else {
+ for (Map.Entry<String, String> en : props.entrySet()) {
+ result.put(prefix + en.getKey(),
+ PropertyValue.createValue(prefix + en.getKey(), en.getValue())
+ .setMeta("source", getName())
+ .setMeta("timestamp", timestampVal));
+ }
+ }
+ return result;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/BuildablePropertySource.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/BuildablePropertySource.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/BuildablePropertySource.java
index a5a5a05..df2a311 100644
--- a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/BuildablePropertySource.java
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/BuildablePropertySource.java
@@ -18,6 +18,7 @@
*/
package org.apache.tamaya.spisupport.propertysource;
+import org.apache.tamaya.spi.ChangeSupport;
import org.apache.tamaya.spi.PropertySource;
import org.apache.tamaya.spi.PropertyValue;
@@ -63,8 +64,8 @@ public class BuildablePropertySource implements PropertySource{
}
@Override
- public boolean isScannable() {
- return true;
+ public ChangeSupport getChangeSupport(){
+ return ChangeSupport.IMMUTABLE;
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/CLIPropertySource.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/CLIPropertySource.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/CLIPropertySource.java
index f7bf8a3..502af4b 100644
--- a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/CLIPropertySource.java
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/CLIPropertySource.java
@@ -18,6 +18,7 @@
*/
package org.apache.tamaya.spisupport.propertysource;
+import org.apache.tamaya.spi.ChangeSupport;
import org.apache.tamaya.spi.PropertyValue;
import java.util.*;
@@ -130,6 +131,11 @@ public class CLIPropertySource extends BasePropertySource {
}
@Override
+ public ChangeSupport getChangeSupport(){
+ return ChangeSupport.IMMUTABLE;
+ }
+
+ @Override
protected String toStringValues() {
return super.toStringValues() +
" args=" + Arrays.toString(args) + '\n';
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/EnvironmentPropertySource.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/EnvironmentPropertySource.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/EnvironmentPropertySource.java
index f16903f..5f981ec 100644
--- a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/EnvironmentPropertySource.java
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/EnvironmentPropertySource.java
@@ -18,6 +18,7 @@
*/
package org.apache.tamaya.spisupport.propertysource;
+import org.apache.tamaya.spi.ChangeSupport;
import org.apache.tamaya.spi.PropertyValue;
import java.util.Collections;
@@ -266,6 +267,11 @@ public class EnvironmentPropertySource extends BasePropertySource {
return disabled;
}
+ @Override
+ public ChangeSupport getChangeSupport(){
+ return ChangeSupport.IMMUTABLE;
+ }
+
/**
* <p>Provides access to the system properties used to configure
* {@linkplain EnvironmentPropertySource}.</p>
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/JavaConfigurationPropertySource.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/JavaConfigurationPropertySource.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/JavaConfigurationPropertySource.java
index b0348f6..0759918 100644
--- a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/JavaConfigurationPropertySource.java
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/JavaConfigurationPropertySource.java
@@ -19,10 +19,7 @@
package org.apache.tamaya.spisupport.propertysource;
import org.apache.tamaya.ConfigException;
-import org.apache.tamaya.spi.ClassloaderAware;
-import org.apache.tamaya.spi.PropertySource;
-import org.apache.tamaya.spi.PropertyValue;
-import org.apache.tamaya.spi.ServiceContextManager;
+import org.apache.tamaya.spi.*;
import org.apache.tamaya.spisupport.PropertySourceComparator;
import java.io.IOException;
@@ -127,6 +124,11 @@ public class JavaConfigurationPropertySource extends BasePropertySource implemen
}
@Override
+ public ChangeSupport getChangeSupport(){
+ return ChangeSupport.IMMUTABLE;
+ }
+
+ @Override
public String toString() {
return "JavaConfigurationPropertySource{" +
"enabled=" + enabled +
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/MapPropertySource.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/MapPropertySource.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/MapPropertySource.java
index a4a9bd7..e93e79f 100644
--- a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/MapPropertySource.java
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/MapPropertySource.java
@@ -16,6 +16,7 @@
*/
package org.apache.tamaya.spisupport.propertysource;
+import org.apache.tamaya.spi.ChangeSupport;
import org.apache.tamaya.spi.PropertyValue;
import java.util.Collections;
@@ -47,37 +48,33 @@ public class MapPropertySource extends BasePropertySource {
/**
* Creates a new instance, hereby using the default mechanism for evaluating the property source's
- * priority, but applying a custom mapping {@code prefix} to the entries provided.
+ * priority, but applying a custom mapping {@code rootContext} to the entries provided.
*
- * @param name unique name of this source.
+ * @param name unique name of this source.
* @param props the properties
* @param prefix the prefix context mapping, or null (for no mapping).
*/
- public MapPropertySource(String name, Map<String, String> props, String prefix) {
- super(name);
- if (prefix == null) {
- for (Map.Entry<String, String> en : props.entrySet()) {
- this.props.put(en.getKey(),
- PropertyValue.of(en.getKey(), en.getValue(), name));
- }
- } else {
- for (Map.Entry<String, String> en : props.entrySet()) {
- this.props.put(prefix + en.getKey(),
- PropertyValue.of(prefix + en.getKey(), en.getValue(), name));
- }
- }
+ public MapPropertySource(String name, Properties props, String prefix) {
+ this(name, getMap(props), prefix);
}
/**
* Creates a new instance, hereby using the default mechanism for evaluating the property source's
- * priority, but applying a custom mapping {@code rootContext} to the entries provided.
+ * priority, but applying a custom mapping {@code prefix} to the entries provided.
*
- * @param name unique name of this source.
+ * @param name unique name of this source.
* @param props the properties
* @param prefix the prefix context mapping, or null (for no mapping).
*/
- public MapPropertySource(String name, Properties props, String prefix) {
- this(name, getMap(props), prefix);
+ public MapPropertySource(String name, Map<String, String> props, String prefix) {
+ super(name);
+ setPrefix(prefix);
+ this.props.putAll(mapProperties(props, System.currentTimeMillis()));
+ }
+
+ @Override
+ public Map<String, PropertyValue> getProperties() {
+ return Collections.unmodifiableMap(this.props);
}
/**
@@ -93,10 +90,9 @@ public class MapPropertySource extends BasePropertySource {
return result;
}
-
@Override
- public Map<String, PropertyValue> getProperties() {
- return Collections.unmodifiableMap(this.props);
+ public ChangeSupport getChangeSupport(){
+ return ChangeSupport.IMMUTABLE;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/PropertiesResourcePropertySource.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/PropertiesResourcePropertySource.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/PropertiesResourcePropertySource.java
index e9f70cf..f9704d7 100644
--- a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/PropertiesResourcePropertySource.java
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/PropertiesResourcePropertySource.java
@@ -18,23 +18,30 @@
*/
package org.apache.tamaya.spisupport.propertysource;
+import org.apache.tamaya.spi.ChangeSupport;
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertyValue;
import org.apache.tamaya.spi.ServiceContextManager;
+import org.apache.tamaya.spisupport.PropertySourceChangeSupport;
import java.io.InputStream;
import java.net.URL;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.function.BiConsumer;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Simple {@link org.apache.tamaya.spi.PropertySource}, with a fixed ordinal that reads a .properties file from a given URL.
*/
-public class PropertiesResourcePropertySource extends MapPropertySource {
+public class PropertiesResourcePropertySource extends BasePropertySource {
/** The logger used. */
private static final Logger LOGGER = Logger.getLogger(PropertiesResourcePropertySource.class.getName());
+ private volatile PropertySourceChangeSupport cachedProperties = new PropertySourceChangeSupport(
+ ChangeSupport.SUPPORTED, this);
+
/**
* Creates a new instance.
* @param url the resource URL, not null.
@@ -49,7 +56,11 @@ public class PropertiesResourcePropertySource extends MapPropertySource {
* @param url the resource URL, not null.
*/
public PropertiesResourcePropertySource(URL url, String prefix){
- super(url.toExternalForm(), loadProps(url), prefix);
+ super(url.toExternalForm());
+ setPrefix(prefix);
+ this.cachedProperties.update(loadProps(url));
+ this.cachedProperties.scheduleChangeMonitor(() -> loadProps(url),
+ 120, TimeUnit.SECONDS);
}
/**
@@ -58,7 +69,7 @@ public class PropertiesResourcePropertySource extends MapPropertySource {
* @param path the resource path, not null.
*/
public PropertiesResourcePropertySource(String path, String prefix){
- super(path, loadProps(path, Thread.currentThread().getContextClassLoader()), prefix);
+ this(path, prefix, ServiceContextManager.getDefaultClassLoader());
}
/**
@@ -68,7 +79,11 @@ public class PropertiesResourcePropertySource extends MapPropertySource {
* @param cl the class loader.
*/
public PropertiesResourcePropertySource(String path, String prefix, ClassLoader cl){
- super(path, loadProps(path, cl), prefix);
+ super(path);
+ setPrefix(prefix);
+ this.cachedProperties.update(loadProps(path, cl));
+ this.cachedProperties.scheduleChangeMonitor(() -> loadProps(path, cl),
+ 120, TimeUnit.SECONDS);
}
/**
@@ -76,7 +91,7 @@ public class PropertiesResourcePropertySource extends MapPropertySource {
* @param path the resource classpath, not null.
* @return the loaded properties.
*/
- private static Map<String, String> loadProps(String path, ClassLoader cl) {
+ private Map<String, PropertyValue> loadProps(String path, ClassLoader cl) {
URL url = ServiceContextManager.getServiceContext(cl).getResource(path);
return loadProps(url);
}
@@ -86,22 +101,48 @@ public class PropertiesResourcePropertySource extends MapPropertySource {
* @param url the resource URL, not null.
* @return the loaded properties.
*/
- private static Map<String, String> loadProps(URL url) {
- Map<String,String> result = new HashMap<>();
+ private Map<String, PropertyValue> loadProps(URL url) {
if(url!=null) {
try (InputStream is = url.openStream()) {
Properties props = new Properties();
props.load(is);
- for (Map.Entry<?,?> en : props.entrySet()) {
- result.put(en.getKey().toString(), en.getValue().toString());
- }
+ return mapProperties(MapPropertySource.getMap(props), System.currentTimeMillis());
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Failed to read properties from " + url, e);
}
}else{
LOGGER.log(Level.WARNING, "No properties found at " + url);
}
- return result;
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public void addChangeListener(BiConsumer<Set<String>, PropertySource> l) {
+ this.cachedProperties.addChangeListener(l);
+ }
+
+ @Override
+ public void removeChangeListener(BiConsumer<Set<String>, PropertySource> l) {
+ this.cachedProperties.removeChangeListener(l);
+ }
+
+ @Override
+ public void removeAllChangeListeners() {
+ this.cachedProperties.removeAllChangeListeners();
+ }
+
+ @Override
+ public Map<String, PropertyValue> getProperties() {
+ return cachedProperties.getProperties();
}
+ @Override
+ public String getVersion() {
+ return cachedProperties.getVersion();
+ }
+
+ @Override
+ public ChangeSupport getChangeSupport() {
+ return ChangeSupport.SUPPORTED;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/SimplePropertySource.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/SimplePropertySource.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/SimplePropertySource.java
index 690a809..8a7567b 100644
--- a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/SimplePropertySource.java
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/SimplePropertySource.java
@@ -19,6 +19,7 @@
package org.apache.tamaya.spisupport.propertysource;
import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.spi.ChangeSupport;
import org.apache.tamaya.spi.PropertyValue;
import java.io.File;
@@ -122,6 +123,11 @@ public class SimplePropertySource extends BasePropertySource {
return this.properties;
}
+ @Override
+ public ChangeSupport getChangeSupport(){
+ return ChangeSupport.IMMUTABLE;
+ }
+
/**
* loads the Properties from the given URL
*
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/SystemPropertySource.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/SystemPropertySource.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/SystemPropertySource.java
index f3e9dd1..57c18b2 100644
--- a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/SystemPropertySource.java
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/SystemPropertySource.java
@@ -18,12 +18,16 @@
*/
package org.apache.tamaya.spisupport.propertysource;
+import org.apache.tamaya.spi.ChangeSupport;
import org.apache.tamaya.spi.PropertyValue;
+import org.apache.tamaya.spisupport.PropertySourceChangeSupport;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* This {@link org.apache.tamaya.spi.PropertySource} manages the system properties. You can disable this feature by
@@ -36,25 +40,10 @@ public class SystemPropertySource extends BasePropertySource {
*/
public static final int DEFAULT_ORDINAL = 1000;
- private volatile Map<String,PropertyValue> cachedProperties;
+ private volatile PropertySourceChangeSupport cachedProperties = new PropertySourceChangeSupport(
+ ChangeSupport.SUPPORTED, this);
+ private AtomicInteger savedHashcode = new AtomicInteger();
- /**
- * previous System.getProperties().hashCode()
- * so we can check if we need to reload
- */
- private volatile int previousHash;
-
- /**
- * Prefix that allows system properties to virtually be mapped on specified sub section.
- */
- private String prefix;
-
- /**
- * If true, this property source does not return any properties. This is useful since this
- * property source is applied by default, but can be switched off by setting the
- * {@code tamaya.envprops.disable} system/environment property to {@code true}.
- */
- private boolean disabled = false;
/**
* Creates a new instance. Also initializes the {@code prefix} and {@code disabled} properties
@@ -67,8 +56,8 @@ public class SystemPropertySource extends BasePropertySource {
public SystemPropertySource(){
super("system-properties", DEFAULT_ORDINAL);
initFromSystemProperties();
- if(!disabled){
- cachedProperties = Collections.unmodifiableMap(loadProperties());
+ if(!isDisabled()){
+ reload();
}
}
@@ -83,8 +72,9 @@ public class SystemPropertySource extends BasePropertySource {
private void initFromSystemProperties() {
String value = System.getProperty("tamaya.sysprops.prefix");
if(value==null){
- prefix = System.getenv("tamaya.sysprops.prefix");
+ value = System.getenv("tamaya.sysprops.prefix");
}
+ setPrefix(value);
value = System.getProperty("tamaya.sysprops.disable");
if(value==null){
value = System.getenv("tamaya.sysprops.disable");
@@ -96,7 +86,7 @@ public class SystemPropertySource extends BasePropertySource {
value = System.getenv("tamaya.defaults.disable");
}
if(value!=null && !value.isEmpty()) {
- this.disabled = Boolean.parseBoolean(value);
+ setDisabled(Boolean.parseBoolean(value));
}
}
@@ -114,7 +104,7 @@ public class SystemPropertySource extends BasePropertySource {
* @param ordinal the ordinal to be used.
*/
public SystemPropertySource(String prefix, int ordinal){
- this.prefix = prefix;
+ setPrefix(prefix);
setOrdinal(ordinal);
}
@@ -123,86 +113,48 @@ public class SystemPropertySource extends BasePropertySource {
* @param prefix the prefix to be used, or null.
*/
public SystemPropertySource(String prefix){
- this.prefix = prefix;
+ setPrefix(prefix);
}
private Map<String, PropertyValue> loadProperties() {
- Properties sysProps = System.getProperties();
- previousHash = System.getProperties().hashCode();
- final String prefix = this.prefix;
- Map<String, PropertyValue> entries = new HashMap<>();
- for (Map.Entry<Object,Object> entry : sysProps.entrySet()) {
- if(entry.getKey() instanceof String && entry.getValue() instanceof String) {
- if (prefix == null) {
- entries.put((String) entry.getKey(),
- PropertyValue.of((String) entry.getKey(),
- (String) entry.getValue(),
- getName()));
- } else {
- entries.put(prefix + entry.getKey(),
- PropertyValue.of(prefix + entry.getKey(),
- (String) entry.getValue(),
- getName()));
- }
- }
- }
- return entries;
- }
-
- @Override
- public String getName() {
- if(disabled){
- return super.getName() + "(disabled)";
- }
- return super.getName();
+ Map<String, String> props = MapPropertySource.getMap(System.getProperties());
+ return mapProperties(props, System.currentTimeMillis());
}
@Override
public PropertyValue get(String key) {
- if(disabled){
+ if(isDisabled()){
return null;
}
reload();
- String prefix = this.prefix;
- if(prefix==null) {
- String value = System.getProperty(key);
- if(value == null){
- return null;
- }
- return PropertyValue.of(key, value, getName());
+ return this.cachedProperties.getValue(key);
+ }
+
+ public void reload() {
+ int hashCode = System.getProperties().hashCode();
+ if(hashCode!=this.savedHashcode.get()) {
+ this.savedHashcode.set(hashCode);
+ this.cachedProperties.update(loadProperties());
}
- return PropertyValue.of(key, System.getProperty(key.substring(prefix.length())), getName());
}
@Override
public Map<String, PropertyValue> getProperties() {
- if(disabled){
+ if(isDisabled()){
return Collections.emptyMap();
}
reload();
- return this.cachedProperties;
+ return cachedProperties.getProperties();
}
- public void reload() {
- // only need to reload and fill our map if something has changed
- // synchronization was removed, Instance was marked as volatile. In the worst case it
- // is reloaded twice, but the values will be the same.
- if (previousHash != System.getProperties().hashCode()) {
- Map<String, PropertyValue> properties = loadProperties();
- this.cachedProperties = Collections.unmodifiableMap(properties);
- }
+ public String getVersion(){
+ return cachedProperties.getVersion();
}
@Override
- public boolean isScannable() {
- return true;
+ public ChangeSupport getChangeSupport() {
+ return ChangeSupport.SUPPORTED;
}
- @Override
- protected String toStringValues() {
- return super.toStringValues() +
- " prefix=" + prefix + '\n' +
- " disabled=" + disabled + '\n';
- }
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/WrappedPropertySource.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/WrappedPropertySource.java b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/WrappedPropertySource.java
index feaaf7b..265dbb4 100644
--- a/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/WrappedPropertySource.java
+++ b/code/spi-support/src/main/java/org/apache/tamaya/spisupport/propertysource/WrappedPropertySource.java
@@ -18,12 +18,15 @@
*/
package org.apache.tamaya.spisupport.propertysource;
+import org.apache.tamaya.spi.ChangeSupport;
import org.apache.tamaya.spi.PropertySource;
import org.apache.tamaya.spi.PropertyValue;
import org.apache.tamaya.spisupport.PropertySourceComparator;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
+import java.util.function.BiConsumer;
/**
* Property source effectively managed by the configuration context, allowing resetting of ordinal and its
@@ -94,6 +97,31 @@ class WrappedPropertySource implements PropertySource{
return delegate.isScannable();
}
+ @Override
+ public ChangeSupport getChangeSupport() {
+ return delegate.getChangeSupport();
+ }
+
+ @Override
+ public String getVersion() {
+ return delegate.getVersion();
+ }
+
+ @Override
+ public void addChangeListener(BiConsumer<Set<String>, PropertySource> l) {
+ delegate.addChangeListener(l);
+ }
+
+ @Override
+ public void removeChangeListener(BiConsumer<Set<String>, PropertySource> l) {
+ delegate.removeChangeListener(l);
+ }
+
+ @Override
+ public void removeAllChangeListeners() {
+ delegate.removeAllChangeListeners();
+ }
+
public PropertySource getDelegate() {
return delegate;
}
@@ -119,6 +147,7 @@ class WrappedPropertySource implements PropertySource{
"name=" + getName() +
", ordinal=" + getOrdinal() +
", scannable=" + isScannable() +
+ ", changeSupport=" + getChangeSupport() +
", loadedAt=" + loaded +
", delegate-class=" + delegate.getClass().getName() +
'}';
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/test/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilderTest.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/test/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilderTest.java b/code/spi-support/src/test/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilderTest.java
index a4487e7..a756b14 100644
--- a/code/spi-support/src/test/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilderTest.java
+++ b/code/spi-support/src/test/java/org/apache/tamaya/spisupport/DefaultConfigurationBuilderTest.java
@@ -18,8 +18,8 @@
*/
package org.apache.tamaya.spisupport;
-import java.util.Arrays;
-import java.util.Collection;
+import java.util.*;
+
import org.apache.tamaya.Configuration;
import org.apache.tamaya.ConfigurationProvider;
import org.apache.tamaya.TypeLiteral;
@@ -27,10 +27,6 @@ import org.apache.tamaya.spi.ConfigurationBuilder;
import org.apache.tamaya.spi.*;
import org.junit.Test;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Map;
-
import static org.assertj.core.api.Assertions.*;
/**
@@ -312,7 +308,7 @@ public class DefaultConfigurationBuilderTest {
.addPropertyConverters(TypeLiteral.of(String.class), converter1, converter2);
Configuration cfg = b.build();
ConfigurationContext ctx = cfg.getContext();
- Map<TypeLiteral<?>, Collection<PropertyConverter<?>>> buildConverters = b.getPropertyConverter();
+ Map<TypeLiteral<?>, List<PropertyConverter<?>>> buildConverters = b.getPropertyConverter();
assertThat(ctx.getPropertyConverters(TypeLiteral.of(String.class)).contains(converter1)).isTrue();
assertThat(ctx.getPropertyConverters(TypeLiteral.of(String.class)).contains(converter2)).isTrue();
assertThat(ctx.getPropertyConverters()).hasSize(1);
@@ -346,7 +342,7 @@ public class DefaultConfigurationBuilderTest {
.addPropertyConverters(TypeLiteral.of(String.class), Arrays.asList(converter1, converter2));
Configuration cfg = b.build();
ConfigurationContext ctx = cfg.getContext();
- Map<TypeLiteral<?>, Collection<PropertyConverter<?>>> buildConverters = b.getPropertyConverter();
+ Map<TypeLiteral<?>, List<PropertyConverter<?>>> buildConverters = b.getPropertyConverter();
assertThat(ctx.getPropertyConverters(TypeLiteral.of(String.class)).contains(converter1)).isTrue();
assertThat(ctx.getPropertyConverters(TypeLiteral.of(String.class)).contains(converter2)).isTrue();
assertThat(ctx.getPropertyConverters()).hasSize(1);
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/5f3f86b0/code/spi-support/src/test/java/org/apache/tamaya/spisupport/DefaultConfigurationSnapshotTest.java
----------------------------------------------------------------------
diff --git a/code/spi-support/src/test/java/org/apache/tamaya/spisupport/DefaultConfigurationSnapshotTest.java b/code/spi-support/src/test/java/org/apache/tamaya/spisupport/DefaultConfigurationSnapshotTest.java
new file mode 100644
index 0000000..b351c91
--- /dev/null
+++ b/code/spi-support/src/test/java/org/apache/tamaya/spisupport/DefaultConfigurationSnapshotTest.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.spisupport;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationSnapshot;
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+
+public class DefaultConfigurationSnapshotTest {
+
+ @Test
+ public void getFrozenAtReturnsTheCorrectTimestamp() throws InterruptedException {
+ Configuration source = Mockito.mock(Configuration.class);
+ Mockito.when(source.getContext()).thenReturn(ConfigurationContext.EMPTY);
+ Mockito.when(source.getSnapshot(Mockito.anyCollection())).thenReturn(ConfigurationSnapshot.EMPTY);
+ Mockito.when(source.getSnapshot()).thenReturn(ConfigurationSnapshot.EMPTY);
+ Mockito.when(source.getProperties()).thenReturn(Collections.emptyMap());
+
+ long poiStart = System.nanoTime();
+ Thread.sleep(10L);
+ DefaultConfigurationSnapshot fc = new DefaultConfigurationSnapshot(source);
+ Thread.sleep(10L);
+
+ long poiEnd = System.nanoTime();
+
+ assertTrue(fc.getTimestamp()>poiStart);
+ assertTrue(fc.getTimestamp()<poiEnd);
+ }
+
+
+ @Test
+ public void idMustBeNotNull() {
+ Configuration source = Mockito.mock(Configuration.class);
+
+ Mockito.when(source.getContext()).thenReturn(ConfigurationContext.EMPTY);
+ Mockito.when(source.getProperties()).thenReturn(Collections.emptyMap());
+
+ DefaultConfigurationSnapshot fc = new DefaultConfigurationSnapshot(source);
+
+ assertNotNull(fc);
+ }
+
+ /*
+ * All tests for equals() and hashCode() go here...
+ */
+ @Test
+ public void twoFrozenAreDifferentIfTheyHaveADifferentIdAndFrozenAtTimestamp() {
+ Map<String, String> properties = new HashMap<>();
+ properties.put("key", "createValue");
+
+ Configuration configuration = Mockito.mock(Configuration.class);
+ Mockito.when(configuration.getContext()).thenReturn(ConfigurationContext.EMPTY);
+ doReturn(properties).when(configuration).getProperties();
+
+ DefaultConfigurationSnapshot fcA = new DefaultConfigurationSnapshot(configuration);
+ DefaultConfigurationSnapshot fcB = new DefaultConfigurationSnapshot(configuration);
+
+ assertNotEquals(fcA, fcB);
+ }
+
+ /*
+ * END OF ALL TESTS for equals() and hashCode()
+ */
+}
\ No newline at end of file