You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tamaya.apache.org by jo...@apache.org on 2014/12/28 16:12:37 UTC
[4/4] incubator-tamaya git commit: Added a programmatic callback for
changesets.
Added a programmatic callback for changesets.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/a1777439
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/a1777439
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/a1777439
Branch: refs/heads/0.1-prototype
Commit: a1777439892646023e62f8ce08c4bcaf109b4aca
Parents: dbca179
Author: John D. Ament <jo...@apache.org>
Authored: Sun Dec 28 09:39:46 2014 -0500
Committer: John D. Ament <jo...@apache.org>
Committed: Sun Dec 28 09:39:46 2014 -0500
----------------------------------------------------------------------
.../java/org/apache/tamaya/ConfigChangeSet.java | 167 +++++++++
.../apache/tamaya/ConfigChangeSetBuilder.java | 356 ++++++++++++++++++
.../java/org/apache/tamaya/Configuration.java | 18 +-
.../java/org/apache/tamaya/PropertySource.java | 38 ++
.../tamaya/spi/ConfigChangeSetCallback.java | 33 ++
.../tamaya/spi/ConfigurationFactorySpi.java | 16 +
.../tamaya/core/config/ConfigChangeSet.java | 169 ---------
.../core/config/ConfigChangeSetBuilder.java | 359 -------------------
.../core/properties/AbstractPropertySource.java | 20 ++
9 files changed, 647 insertions(+), 529 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a1777439/api/src/main/java/org/apache/tamaya/ConfigChangeSet.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/ConfigChangeSet.java b/api/src/main/java/org/apache/tamaya/ConfigChangeSet.java
new file mode 100644
index 0000000..dda7701
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/ConfigChangeSet.java
@@ -0,0 +1,167 @@
+/*
+ * 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.beans.PropertyChangeEvent;
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * Event that contains a set current changes that were applied or could be applied.
+ * This class is immutable and thread-safe. To create instances use
+ * {@link ConfigChangeSetBuilder}.
+ *
+ * Created by Anatole on 22.10.2014.
+ */
+public final class ConfigChangeSet implements Serializable{
+
+ private static final long serialVersionUID = 1l;
+ /** The base property provider/configuration. */
+ private PropertySource propertySource;
+ /** The base version, usable for optimistic locking. */
+ private String baseVersion;
+ /** The recorded changes. */
+ private Map<String,PropertyChangeEvent> changes = new HashMap<>();
+
+ /**
+ * Get an empty change set for the given provider.
+ * @param propertyProvider The base property provider/configuration, not null.
+ * @return an empty ConfigChangeSet instance.
+ */
+ public static ConfigChangeSet emptyChangeSet(PropertySource propertyProvider){
+ return new ConfigChangeSet(propertyProvider, Collections.emptySet());
+ }
+
+ /**
+ * Constructor used by {@link ConfigChangeSetBuilder}.
+ * @param propertySource The base property provider/configuration, not null.
+ * @param changes The recorded changes, not null.
+ */
+ ConfigChangeSet(PropertySource propertySource, Collection<PropertyChangeEvent> changes) {
+ this.propertySource = Objects.requireNonNull(propertySource);
+ changes.forEach((c) -> this.changes.put(c.getPropertyName(), c));
+ }
+
+ /**
+ * Get the underlying property provider/configuration.
+ * @return the underlying property provider/configuration, never null.
+ */
+ public PropertySource getPropertySource(){
+ return this.propertySource;
+ }
+
+ /**
+ * Get the base version, usable for optimistic locking.
+ * @return the base version.
+ */
+ public String getBaseVersion(){
+ return baseVersion;
+ }
+
+ /**
+ * Get the changes recorded.
+ * @return the recorded changes, never null.
+ */
+ public Collection<PropertyChangeEvent> getEvents(){
+ return Collections.unmodifiableCollection(this.changes.values());
+ }
+
+ /**
+ * Access the number current removed entries.
+ * @return the number current removed entries.
+ */
+ public int getRemovedSize() {
+ return (int) this.changes.values().stream().filter((e) -> e.getNewValue() == null).count();
+ }
+
+ /**
+ * Access the number current added entries.
+ * @return the number current added entries.
+ */
+ public int getAddedSize() {
+ return (int) this.changes.values().stream().filter((e) -> e.getOldValue() == null).count();
+ }
+
+ /**
+ * Access the number current updated entries.
+ * @return the number current updated entries.
+ */
+ public int getUpdatedSize() {
+ return (int) this.changes.values().stream().filter((e) -> e.getOldValue()!=null && e.getNewValue()!=null).count();
+ }
+
+
+ /**
+ * Checks if the given key was removed.
+ * @param key the target key, not null.
+ * @return true, if the given key was removed.
+ */
+ public boolean isRemoved(String key) {
+ PropertyChangeEvent change = this.changes.get(key);
+ return change != null && change.getNewValue() == null;
+ }
+
+ /**
+ * Checks if the given key was added.
+ * @param key the target key, not null.
+ * @return true, if the given key was added.
+ */
+ public boolean isAdded(String key) {
+ PropertyChangeEvent change = this.changes.get(key);
+ return change != null && change.getOldValue() == null;
+ }
+
+ /**
+ * Checks if the given key was updated.
+ * @param key the target key, not null.
+ * @return true, if the given key was updated.
+ */
+ public boolean isUpdated(String key) {
+ PropertyChangeEvent change = this.changes.get(key);
+ return change != null && change.getOldValue() != null && change.getNewValue() != null;
+ }
+
+ /**
+ * Checks if the given key is added, or updated AND NOT removed.
+ * @param key the target key, not null.
+ * @return true, if the given key was added, or updated BUT NOT removed.
+ */
+ public boolean containsKey(String key) {
+ PropertyChangeEvent change = this.changes.get(key);
+ return change != null && change.getNewValue() != null;
+ }
+
+ /**
+ * CHecks if the current change set does not contain any changes.
+ * @return tru, if the change set is empty.
+ */
+ public boolean isEmpty(){
+ return this.changes.isEmpty();
+ }
+
+
+ @Override
+ public String toString() {
+ return "ConfigChangeSet{" +
+ "properties=" + propertySource +
+ ", baseVersion=" + baseVersion +
+ ", changes=" + changes +
+ '}';
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a1777439/api/src/main/java/org/apache/tamaya/ConfigChangeSetBuilder.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/ConfigChangeSetBuilder.java b/api/src/main/java/org/apache/tamaya/ConfigChangeSetBuilder.java
new file mode 100644
index 0000000..a5ef042
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/ConfigChangeSetBuilder.java
@@ -0,0 +1,356 @@
+/*
+ * 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.beans.PropertyChangeEvent;
+import java.util.*;
+import java.util.function.Function;
+
+/**
+ * Models a set current changes to be applied to a configuration/property provider. Such a set can be applied
+ * to any {@link org.apache.tamaya.PropertySource} instance. If the provider is mutable it may check the
+ * version given and applyChanges the changes to the provider/configuration, including triggering current regarding
+ * change events.
+ * <p>
+ * For appropriate conversion a {@code Function<String, Codec>} can be applied, which performs correct conversion,
+ * when changed values are set. This function enables connecting e.g. setters on a configuration template with
+ * the corresponding conversion logic, so the template calls are correctly converted back.
+ */
+public final class ConfigChangeSetBuilder {
+ /**
+ * The recorded changes.
+ */
+ final SortedMap<String, PropertyChangeEvent> delta = new TreeMap<>();
+ /**
+ * The underlying configuration/provider.
+ */
+ PropertySource source;
+
+ /**
+ * Constructor.
+ *
+ * @param source the underlying configuration/provider, not null.
+ */
+ private ConfigChangeSetBuilder(PropertySource source) {
+ this.source = Objects.requireNonNull(source);
+ }
+
+ /**
+ * Creates a new instance current this builder.
+ *
+ * @param source the underlying property provider/configuration, not null.
+ * @return the builder for chaining.
+ */
+ public static ConfigChangeSetBuilder of(PropertySource source) {
+ return new ConfigChangeSetBuilder(source);
+ }
+
+
+ /**
+ * Creates a new instance current this builder.
+ *
+ * @param configuration the base configuration, not null.
+ * @return the builder for chaining.
+ */
+ public static ConfigChangeSetBuilder of(Configuration configuration) {
+ return new ConfigChangeSetBuilder(configuration);
+ }
+
+ /**
+ * This method records all changes to be applied to the base property provider/configuration to
+ * achieve the given target state.
+ *
+ * @param newState the new target state, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigChangeSetBuilder addChanges(PropertySource newState) {
+ compare(newState, this.source).forEach((c) -> this.delta.put(c.getPropertyName(), c));
+ return this;
+ }
+
+ /**
+ * Get the current values, also considering any changes recorded within this change set.
+ *
+ * @param key the key current the entry, not null.
+ * @return the keys, or null.
+ */
+ public String get(String key) {
+ PropertyChangeEvent change = this.delta.get(key);
+ if (change != null && !(change.getNewValue() == null)) {
+ return (String) change.getNewValue();
+ }
+ return null;
+ }
+
+ /**
+ * Marks the given key(s) fromMap the configuration/properties to be removed.
+ *
+ * @param key the key current the entry, not null.
+ * @param otherKeys additional keys to be removed (convenience), not null.
+ * @return the builder for chaining.
+ */
+ public ConfigChangeSetBuilder remove(String key, String... otherKeys) {
+ String oldValue = this.source.get(key).orElse(null);
+ if (oldValue == null) {
+ this.delta.remove(key);
+ }
+ this.delta.put(key, new PropertyChangeEvent(this.source, key, oldValue, null));
+ for (String addKey : otherKeys) {
+ oldValue = this.source.get(addKey).orElse(null);
+ if (oldValue == null) {
+ this.delta.remove(addKey);
+ }
+ this.delta.put(addKey, new PropertyChangeEvent(this.source, addKey, oldValue, null));
+ }
+ return this;
+ }
+
+ /**
+ * Applies the given keys.
+ *
+ * @param key the key current the entry, not null.
+ * @param value the keys to be applied, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigChangeSetBuilder put(String key, boolean value) {
+ this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
+ return this;
+ }
+
+ /**
+ s* Applies the given keys.
+ *
+ * @param key the key current the entry, not null.
+ * @param value the keys to be applied, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigChangeSetBuilder put(String key, byte value) {
+ this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
+ return this;
+ }
+
+ /**
+ * Applies the given keys.
+ *
+ * @param key the key current the entry, not null.
+ * @param value the keys to be applied, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigChangeSetBuilder put(String key, char value) {
+ this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
+ return this;
+ }
+
+ /**
+ * Applies the given keys.
+ *
+ * @param key the key current the entry, not null.
+ * @param value the keys to be applied, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigChangeSetBuilder put(String key, short value) {
+ this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
+ return this;
+ }
+
+ /**
+ * Applies the given keys.
+ *
+ * @param key the key current the entry, not null.
+ * @param value the keys to be applied, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigChangeSetBuilder put(String key, int value) {
+ this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
+ return this;
+ }
+
+ /**
+ * Applies the given keys.
+ *
+ * @param key the key current the entry, not null.
+ * @param value the keys to be applied, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigChangeSetBuilder put(String key, long value) {
+ this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
+ return this;
+ }
+
+ /**
+ * Applies the given keys.
+ *
+ * @param key the key current the entry, not null.
+ * @param value the keys to be applied, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigChangeSetBuilder put(String key, float value) {
+ this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
+ return this;
+ }
+
+ /**
+ * Applies the given keys.
+ *
+ * @param key the key current the entry, not null.
+ * @param value the keys to be applied, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigChangeSetBuilder put(String key, double value) {
+ this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
+ return this;
+ }
+
+
+ /**
+ * Applies the given keys.
+ *
+ * @param key the key current the entry, not null.
+ * @param value the keys to be applied, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigChangeSetBuilder put(String key, String value) {
+ this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
+ return this;
+ }
+
+ /**
+ * Applies the given keys.
+ *
+ * @param key the key current the entry, not null.
+ * @param value the keys to be applied, not null.
+ * @return the builder for chaining.
+ * @throws org.apache.tamaya.ConfigException if no matching Codec could be found.
+ */
+ public <T> ConfigChangeSetBuilder put(String key, Class<T> type, T value) {
+ put(key, type, value, null);
+ return this;
+ }
+
+ /**
+ * Applies the given keys.
+ *
+ * @param key the key current the entry, not null.
+ * @param value the keys to be applied, not null.
+ * @param adapter the codec to be used, if set overrides any other codecs that may apply. If null an appropriate
+ * codec is tried to be evaluated as needed.
+ * @return the builder for chaining.
+ * @throws org.apache.tamaya.ConfigException if no matching Codec could be found.
+ */
+ public <T> ConfigChangeSetBuilder put(String key, Class<T> type, T value, Function<T,String> adapter) {
+ this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), adapter.apply(Objects.requireNonNull(value))));
+ return this;
+ }
+
+
+ /**
+ * Apply all the given values to the base configuration/properties.
+ * Note that all values passed must be convertible to String, either
+ * <ul>
+ * <li>the registered codecs provider provides codecs for the corresponding keys, or </li>
+ * <li>default codecs are present for the given type, or</li>
+ * <li>the value is an instanceof String</li>
+ * </ul>
+ *
+ * @param changes the changes to be applied, not null.
+ * @return the builder for chaining.
+ */
+ public ConfigChangeSetBuilder putAll(Map<String, String> changes) {
+ changes.putAll(changes);
+ return this;
+ }
+
+ /**
+ * This method will create a change set that clears all entries fromMap the given base configuration/properties.
+ *
+ * @return the builder for chaining.
+ */
+ public ConfigChangeSetBuilder deleteAll() {
+ this.delta.clear();
+ this.source.getProperties().forEach((k, v) ->
+ this.delta.put(k, new PropertyChangeEvent(this.source, k, v, null)));
+ return this;
+ }
+
+ /**
+ * Checks if the change set is empty, i.e. does not contain any changes.
+ *
+ * @return true, if the set is empty.
+ */
+ public boolean isEmpty() {
+ return this.delta.isEmpty();
+ }
+
+ /**
+ * Resets this change set instance. This will clear all changes done to this builder, so the
+ * set will be empty.
+ */
+ public void reset() {
+ this.delta.clear();
+ }
+
+ /**
+ * Builds the corresponding change set.
+ *
+ * @return the new change set, never null.
+ */
+ public ConfigChangeSet build() {
+ return new ConfigChangeSet(this.source, Collections.unmodifiableCollection(this.delta.values()));
+ }
+
+ /**
+ * Compares the two property config/configurations and creates a collection current all changes
+ * that must be appied to render {@code map1} into {@code map2}.
+ *
+ * @param map1 the source map, not null.
+ * @param map2 the target map, not null.
+ * @return a collection current change events, never null.
+ */
+ public static Collection<PropertyChangeEvent> compare(PropertySource map1, PropertySource map2) {
+ List<PropertyChangeEvent> changes = new ArrayList<>();
+ for (Map.Entry<String, String> en : map1.getProperties().entrySet()) {
+ Optional<String> val = map2.get(en.getKey());
+ if (!val.isPresent()) {
+ changes.add(new PropertyChangeEvent(map1, en.getKey(), null, en.getValue()));
+ } else if (!val.get().equals(en.getValue())) {
+ changes.add(new PropertyChangeEvent(map1, en.getKey(), val.get(), en.getValue()));
+ }
+ }
+ for (Map.Entry<String, String> en : map2.getProperties().entrySet()) {
+ Optional<String> val = map1.get(en.getKey());
+ if (!val.isPresent()) {
+ changes.add(new PropertyChangeEvent(map1, en.getKey(), null, en.getValue()));
+ } else if (!val.equals(Optional.ofNullable(en.getValue()))) {
+ changes.add(new PropertyChangeEvent(map1, en.getKey(), val.get(), en.getValue()));
+ }
+ }
+ return changes;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "PropertyChangeEventBuilder [source=" + source + ", " +
+ ", delta=" + delta + "]";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a1777439/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 73eb41a..0999b1f 100644
--- a/api/src/main/java/org/apache/tamaya/Configuration.java
+++ b/api/src/main/java/org/apache/tamaya/Configuration.java
@@ -18,6 +18,7 @@
*/
package org.apache.tamaya;
+import org.apache.tamaya.spi.ConfigChangeSetCallback;
import org.apache.tamaya.spi.ConfigurationFactorySpi;
import org.apache.tamaya.spi.ConfigurationSpi;
import org.apache.tamaya.spi.ServiceContext;
@@ -61,13 +62,28 @@ public interface Configuration extends PropertyMapSupplier,PropertySource {
}
@Override
+ public void update(ConfigChangeSet changeSet) {
+
+ }
+
+ @Override
+ public void registerForUpdate(ConfigChangeSetCallback callback) {
+
+ }
+
+ @Override
+ public void removeForUpdate(ConfigChangeSetCallback callback) {
+
+ }
+
+ @Override
public Map<String, String> getProperties() {
return Collections.emptyMap();
}
@Override
public String toString(){
- return "PropertySource [name=<empty>]";
+ return "Configuration [name=<empty>]";
}
};
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a1777439/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 f4b01ae..152411a 100644
--- a/api/src/main/java/org/apache/tamaya/PropertySource.java
+++ b/api/src/main/java/org/apache/tamaya/PropertySource.java
@@ -18,7 +18,10 @@
*/
package org.apache.tamaya;
+import org.apache.tamaya.spi.ConfigChangeSetCallback;
+
import java.util.*;
+import java.util.concurrent.Callable;
import java.util.function.Function;
import java.util.function.UnaryOperator;
@@ -58,6 +61,21 @@ public interface PropertySource extends PropertyMapSupplier {
}
@Override
+ public void update(ConfigChangeSet changeSet) {
+
+ }
+
+ @Override
+ public void registerForUpdate(ConfigChangeSetCallback callback) {
+
+ }
+
+ @Override
+ public void removeForUpdate(ConfigChangeSetCallback callback) {
+
+ }
+
+ @Override
public Map<String, String> getProperties() {
return Collections.emptyMap();
}
@@ -125,5 +143,25 @@ public interface PropertySource extends PropertyMapSupplier {
return query.apply(this);
}
+ /**
+ * Upon receiving a ConfigChangeSet, the PropertySource will be updated to include
+ * any of the listed changes within
+ *
+ * @param changeSet the changes to be invoked
+ */
+ void update(ConfigChangeSet changeSet);
+
+ /**
+ * Whenever this PropertySource is updated, any registered callables will be invoked
+ * @param callback
+ */
+ void registerForUpdate(ConfigChangeSetCallback callback);
+
+ /**
+ * Removes a callback to be invoked.
+ * @param callback
+ */
+ void removeForUpdate(ConfigChangeSetCallback callback);
+
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a1777439/api/src/main/java/org/apache/tamaya/spi/ConfigChangeSetCallback.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/spi/ConfigChangeSetCallback.java b/api/src/main/java/org/apache/tamaya/spi/ConfigChangeSetCallback.java
new file mode 100644
index 0000000..889b8c4
--- /dev/null
+++ b/api/src/main/java/org/apache/tamaya/spi/ConfigChangeSetCallback.java
@@ -0,0 +1,33 @@
+/*
+ * 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.ConfigChangeSet;
+
+/**
+ * A callback to be notified whenever a change comes in
+ */
+@FunctionalInterface
+public interface ConfigChangeSetCallback {
+ /**
+ * Method to be invoked on change. Includes the ConfigChangeSet.
+ * @param changeSet
+ */
+ public void onChange(ConfigChangeSet changeSet);
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a1777439/api/src/main/java/org/apache/tamaya/spi/ConfigurationFactorySpi.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/tamaya/spi/ConfigurationFactorySpi.java b/api/src/main/java/org/apache/tamaya/spi/ConfigurationFactorySpi.java
index 3b167cc..a0a91d3 100644
--- a/api/src/main/java/org/apache/tamaya/spi/ConfigurationFactorySpi.java
+++ b/api/src/main/java/org/apache/tamaya/spi/ConfigurationFactorySpi.java
@@ -18,6 +18,7 @@
*/
package org.apache.tamaya.spi;
+import org.apache.tamaya.ConfigChangeSet;
import org.apache.tamaya.Configuration;
import org.apache.tamaya.PropertySource;
@@ -47,6 +48,21 @@ public interface ConfigurationFactorySpi {
}
@Override
+ public void update(ConfigChangeSet changeSet) {
+ propertySource.update(changeSet);
+ }
+
+ @Override
+ public void registerForUpdate(ConfigChangeSetCallback callback) {
+ propertySource.registerForUpdate(callback);
+ }
+
+ @Override
+ public void removeForUpdate(ConfigChangeSetCallback callback) {
+ propertySource.removeForUpdate(callback);
+ }
+
+ @Override
public Map<String, String> getProperties() {
return propertySource.getProperties();
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a1777439/core/src/main/java/org/apache/tamaya/core/config/ConfigChangeSet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/config/ConfigChangeSet.java b/core/src/main/java/org/apache/tamaya/core/config/ConfigChangeSet.java
deleted file mode 100644
index 7ef3477..0000000
--- a/core/src/main/java/org/apache/tamaya/core/config/ConfigChangeSet.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.config;
-
-import org.apache.tamaya.PropertySource;
-
-import java.beans.PropertyChangeEvent;
-import java.io.Serializable;
-import java.util.*;
-
-/**
- * Event that contains a set current changes that were applied or could be applied.
- * This class is immutable and thread-safe. To create instances use
- * {@link ConfigChangeSetBuilder}.
- *
- * Created by Anatole on 22.10.2014.
- */
-public final class ConfigChangeSet implements Serializable{
-
- private static final long serialVersionUID = 1l;
- /** The base property provider/configuration. */
- private PropertySource propertySource;
- /** The base version, usable for optimistic locking. */
- private String baseVersion;
- /** The recorded changes. */
- private Map<String,PropertyChangeEvent> changes = new HashMap<>();
-
- /**
- * Get an empty change set for the given provider.
- * @param propertyProvider The base property provider/configuration, not null.
- * @return an empty ConfigChangeSet instance.
- */
- public static ConfigChangeSet emptyChangeSet(PropertySource propertyProvider){
- return new ConfigChangeSet(propertyProvider, Collections.emptySet());
- }
-
- /**
- * Constructor used by {@link ConfigChangeSetBuilder}.
- * @param propertySource The base property provider/configuration, not null.
- * @param changes The recorded changes, not null.
- */
- ConfigChangeSet(PropertySource propertySource, Collection<PropertyChangeEvent> changes) {
- this.propertySource = Objects.requireNonNull(propertySource);
- changes.forEach((c) -> this.changes.put(c.getPropertyName(), c));
- }
-
- /**
- * Get the underlying property provider/configuration.
- * @return the underlying property provider/configuration, never null.
- */
- public PropertySource getPropertySource(){
- return this.propertySource;
- }
-
- /**
- * Get the base version, usable for optimistic locking.
- * @return the base version.
- */
- public String getBaseVersion(){
- return baseVersion;
- }
-
- /**
- * Get the changes recorded.
- * @return the recorded changes, never null.
- */
- public Collection<PropertyChangeEvent> getEvents(){
- return Collections.unmodifiableCollection(this.changes.values());
- }
-
- /**
- * Access the number current removed entries.
- * @return the number current removed entries.
- */
- public int getRemovedSize() {
- return (int) this.changes.values().stream().filter((e) -> e.getNewValue() == null).count();
- }
-
- /**
- * Access the number current added entries.
- * @return the number current added entries.
- */
- public int getAddedSize() {
- return (int) this.changes.values().stream().filter((e) -> e.getOldValue() == null).count();
- }
-
- /**
- * Access the number current updated entries.
- * @return the number current updated entries.
- */
- public int getUpdatedSize() {
- return (int) this.changes.values().stream().filter((e) -> e.getOldValue()!=null && e.getNewValue()!=null).count();
- }
-
-
- /**
- * Checks if the given key was removed.
- * @param key the target key, not null.
- * @return true, if the given key was removed.
- */
- public boolean isRemoved(String key) {
- PropertyChangeEvent change = this.changes.get(key);
- return change != null && change.getNewValue() == null;
- }
-
- /**
- * Checks if the given key was added.
- * @param key the target key, not null.
- * @return true, if the given key was added.
- */
- public boolean isAdded(String key) {
- PropertyChangeEvent change = this.changes.get(key);
- return change != null && change.getOldValue() == null;
- }
-
- /**
- * Checks if the given key was updated.
- * @param key the target key, not null.
- * @return true, if the given key was updated.
- */
- public boolean isUpdated(String key) {
- PropertyChangeEvent change = this.changes.get(key);
- return change != null && change.getOldValue() != null && change.getNewValue() != null;
- }
-
- /**
- * Checks if the given key is added, or updated AND NOT removed.
- * @param key the target key, not null.
- * @return true, if the given key was added, or updated BUT NOT removed.
- */
- public boolean containsKey(String key) {
- PropertyChangeEvent change = this.changes.get(key);
- return change != null && change.getNewValue() != null;
- }
-
- /**
- * CHecks if the current change set does not contain any changes.
- * @return tru, if the change set is empty.
- */
- public boolean isEmpty(){
- return this.changes.isEmpty();
- }
-
-
- @Override
- public String toString() {
- return "ConfigChangeSet{" +
- "properties=" + propertySource +
- ", baseVersion=" + baseVersion +
- ", changes=" + changes +
- '}';
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a1777439/core/src/main/java/org/apache/tamaya/core/config/ConfigChangeSetBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/config/ConfigChangeSetBuilder.java b/core/src/main/java/org/apache/tamaya/core/config/ConfigChangeSetBuilder.java
deleted file mode 100644
index 0b536e0..0000000
--- a/core/src/main/java/org/apache/tamaya/core/config/ConfigChangeSetBuilder.java
+++ /dev/null
@@ -1,359 +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.config;
-
-import org.apache.tamaya.Configuration;
-import org.apache.tamaya.PropertySource;
-
-import java.beans.PropertyChangeEvent;
-import java.util.*;
-import java.util.function.Function;
-
-/**
- * Models a set current changes to be applied to a configuration/property provider. Such a set can be applied
- * to any {@link org.apache.tamaya.PropertySource} instance. If the provider is mutable it may check the
- * version given and applyChanges the changes to the provider/configuration, including triggering current regarding
- * change events.
- * <p>
- * For appropriate conversion a {@code Function<String, Codec>} can be applied, which performs correct conversion,
- * when changed values are set. This function enables connecting e.g. setters on a configuration template with
- * the corresponding conversion logic, so the template calls are correctly converted back.
- */
-public final class ConfigChangeSetBuilder {
- /**
- * The recorded changes.
- */
- final SortedMap<String, PropertyChangeEvent> delta = new TreeMap<>();
- /**
- * The underlying configuration/provider.
- */
- PropertySource source;
-
- /**
- * Constructor.
- *
- * @param source the underlying configuration/provider, not null.
- */
- private ConfigChangeSetBuilder(PropertySource source) {
- this.source = Objects.requireNonNull(source);
- }
-
- /**
- * Creates a new instance current this builder.
- *
- * @param source the underlying property provider/configuration, not null.
- * @return the builder for chaining.
- */
- public static ConfigChangeSetBuilder of(PropertySource source) {
- return new ConfigChangeSetBuilder(source);
- }
-
-
- /**
- * Creates a new instance current this builder.
- *
- * @param configuration the base configuration, not null.
- * @return the builder for chaining.
- */
- public static ConfigChangeSetBuilder of(Configuration configuration) {
- return new ConfigChangeSetBuilder(configuration);
- }
-
- /**
- * This method records all changes to be applied to the base property provider/configuration to
- * achieve the given target state.
- *
- * @param newState the new target state, not null.
- * @return the builder for chaining.
- */
- public ConfigChangeSetBuilder addChanges(PropertySource newState) {
- compare(newState, this.source).forEach((c) -> this.delta.put(c.getPropertyName(), c));
- return this;
- }
-
- /**
- * Get the current values, also considering any changes recorded within this change set.
- *
- * @param key the key current the entry, not null.
- * @return the keys, or null.
- */
- public String get(String key) {
- PropertyChangeEvent change = this.delta.get(key);
- if (change != null && !(change.getNewValue() == null)) {
- return (String) change.getNewValue();
- }
- return null;
- }
-
- /**
- * Marks the given key(s) fromMap the configuration/properties to be removed.
- *
- * @param key the key current the entry, not null.
- * @param otherKeys additional keys to be removed (convenience), not null.
- * @return the builder for chaining.
- */
- public ConfigChangeSetBuilder remove(String key, String... otherKeys) {
- String oldValue = this.source.get(key).orElse(null);
- if (oldValue == null) {
- this.delta.remove(key);
- }
- this.delta.put(key, new PropertyChangeEvent(this.source, key, oldValue, null));
- for (String addKey : otherKeys) {
- oldValue = this.source.get(addKey).orElse(null);
- if (oldValue == null) {
- this.delta.remove(addKey);
- }
- this.delta.put(addKey, new PropertyChangeEvent(this.source, addKey, oldValue, null));
- }
- return this;
- }
-
- /**
- * Applies the given keys.
- *
- * @param key the key current the entry, not null.
- * @param value the keys to be applied, not null.
- * @return the builder for chaining.
- */
- public ConfigChangeSetBuilder put(String key, boolean value) {
- this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
- return this;
- }
-
- /**
- s* Applies the given keys.
- *
- * @param key the key current the entry, not null.
- * @param value the keys to be applied, not null.
- * @return the builder for chaining.
- */
- public ConfigChangeSetBuilder put(String key, byte value) {
- this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
- return this;
- }
-
- /**
- * Applies the given keys.
- *
- * @param key the key current the entry, not null.
- * @param value the keys to be applied, not null.
- * @return the builder for chaining.
- */
- public ConfigChangeSetBuilder put(String key, char value) {
- this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
- return this;
- }
-
- /**
- * Applies the given keys.
- *
- * @param key the key current the entry, not null.
- * @param value the keys to be applied, not null.
- * @return the builder for chaining.
- */
- public ConfigChangeSetBuilder put(String key, short value) {
- this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
- return this;
- }
-
- /**
- * Applies the given keys.
- *
- * @param key the key current the entry, not null.
- * @param value the keys to be applied, not null.
- * @return the builder for chaining.
- */
- public ConfigChangeSetBuilder put(String key, int value) {
- this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
- return this;
- }
-
- /**
- * Applies the given keys.
- *
- * @param key the key current the entry, not null.
- * @param value the keys to be applied, not null.
- * @return the builder for chaining.
- */
- public ConfigChangeSetBuilder put(String key, long value) {
- this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
- return this;
- }
-
- /**
- * Applies the given keys.
- *
- * @param key the key current the entry, not null.
- * @param value the keys to be applied, not null.
- * @return the builder for chaining.
- */
- public ConfigChangeSetBuilder put(String key, float value) {
- this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
- return this;
- }
-
- /**
- * Applies the given keys.
- *
- * @param key the key current the entry, not null.
- * @param value the keys to be applied, not null.
- * @return the builder for chaining.
- */
- public ConfigChangeSetBuilder put(String key, double value) {
- this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
- return this;
- }
-
-
- /**
- * Applies the given keys.
- *
- * @param key the key current the entry, not null.
- * @param value the keys to be applied, not null.
- * @return the builder for chaining.
- */
- public ConfigChangeSetBuilder put(String key, String value) {
- this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), String.valueOf(value)));
- return this;
- }
-
- /**
- * Applies the given keys.
- *
- * @param key the key current the entry, not null.
- * @param value the keys to be applied, not null.
- * @return the builder for chaining.
- * @throws org.apache.tamaya.ConfigException if no matching Codec could be found.
- */
- public <T> ConfigChangeSetBuilder put(String key, Class<T> type, T value) {
- put(key, type, value, null);
- return this;
- }
-
- /**
- * Applies the given keys.
- *
- * @param key the key current the entry, not null.
- * @param value the keys to be applied, not null.
- * @param adapter the codec to be used, if set overrides any other codecs that may apply. If null an appropriate
- * codec is tried to be evaluated as needed.
- * @return the builder for chaining.
- * @throws org.apache.tamaya.ConfigException if no matching Codec could be found.
- */
- public <T> ConfigChangeSetBuilder put(String key, Class<T> type, T value, Function<T,String> adapter) {
- this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key).orElse(null), adapter.apply(Objects.requireNonNull(value))));
- return this;
- }
-
-
- /**
- * Apply all the given values to the base configuration/properties.
- * Note that all values passed must be convertible to String, either
- * <ul>
- * <li>the registered codecs provider provides codecs for the corresponding keys, or </li>
- * <li>default codecs are present for the given type, or</li>
- * <li>the value is an instanceof String</li>
- * </ul>
- *
- * @param changes the changes to be applied, not null.
- * @return the builder for chaining.
- */
- public ConfigChangeSetBuilder putAll(Map<String, String> changes) {
- changes.putAll(changes);
- return this;
- }
-
- /**
- * This method will create a change set that clears all entries fromMap the given base configuration/properties.
- *
- * @return the builder for chaining.
- */
- public ConfigChangeSetBuilder deleteAll() {
- this.delta.clear();
- this.source.getProperties().forEach((k, v) ->
- this.delta.put(k, new PropertyChangeEvent(this.source, k, v, null)));
- return this;
- }
-
- /**
- * Checks if the change set is empty, i.e. does not contain any changes.
- *
- * @return true, if the set is empty.
- */
- public boolean isEmpty() {
- return this.delta.isEmpty();
- }
-
- /**
- * Resets this change set instance. This will clear all changes done to this builder, so the
- * set will be empty.
- */
- public void reset() {
- this.delta.clear();
- }
-
- /**
- * Builds the corresponding change set.
- *
- * @return the new change set, never null.
- */
- public ConfigChangeSet build() {
- return new ConfigChangeSet(this.source, Collections.unmodifiableCollection(this.delta.values()));
- }
-
- /**
- * Compares the two property config/configurations and creates a collection current all changes
- * that must be appied to render {@code map1} into {@code map2}.
- *
- * @param map1 the source map, not null.
- * @param map2 the target map, not null.
- * @return a collection current change events, never null.
- */
- public static Collection<PropertyChangeEvent> compare(PropertySource map1, PropertySource map2) {
- List<PropertyChangeEvent> changes = new ArrayList<>();
- for (Map.Entry<String, String> en : map1.getProperties().entrySet()) {
- Optional<String> val = map2.get(en.getKey());
- if (!val.isPresent()) {
- changes.add(new PropertyChangeEvent(map1, en.getKey(), null, en.getValue()));
- } else if (!val.get().equals(en.getValue())) {
- changes.add(new PropertyChangeEvent(map1, en.getKey(), val.get(), en.getValue()));
- }
- }
- for (Map.Entry<String, String> en : map2.getProperties().entrySet()) {
- Optional<String> val = map1.get(en.getKey());
- if (!val.isPresent()) {
- changes.add(new PropertyChangeEvent(map1, en.getKey(), null, en.getValue()));
- } else if (!val.equals(Optional.ofNullable(en.getValue()))) {
- changes.add(new PropertyChangeEvent(map1, en.getKey(), val.get(), en.getValue()));
- }
- }
- return changes;
- }
-
- /*
- * (non-Javadoc)
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return "PropertyChangeEventBuilder [source=" + source + ", " +
- ", delta=" + delta + "]";
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a1777439/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 fbfd6df..6564e5b 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,9 @@ package org.apache.tamaya.core.properties;
import java.io.Serializable;
import java.util.*;
+import org.apache.tamaya.ConfigChangeSet;
import org.apache.tamaya.PropertySource;
+import org.apache.tamaya.spi.ConfigChangeSetCallback;
/**
* Abstract base class for implementing a {@link org.apache.tamaya.PropertySource}.
@@ -39,6 +41,8 @@ public abstract class AbstractPropertySource implements PropertySource, Serializ
*/
private volatile Set<String> sources = new HashSet<>();
+ private volatile Set<ConfigChangeSetCallback> callbacks = new LinkedHashSet<>();
+
/**
* Constructor.
*/
@@ -82,6 +86,22 @@ public abstract class AbstractPropertySource implements PropertySource, Serializ
return b.append('}').toString();
}
+ @Override
+ public void update(ConfigChangeSet changeSet) {
+ //TODO how do we want to update this guy?
+ this.callbacks.parallelStream().forEach((c) -> c.onChange(changeSet));
+ }
+
+ @Override
+ public void registerForUpdate(ConfigChangeSetCallback callback) {
+ this.callbacks.add(callback);
+ }
+
+ @Override
+ public void removeForUpdate(ConfigChangeSetCallback callback) {
+ this.callbacks.remove(callback);
+ }
+
protected String printContents(StringBuilder b){
Map<String,String> sortMap = getProperties();
if(!(sortMap instanceof SortedMap)){