tamaya-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ple...@apache.org
Subject [22/50] [abbrv] incubator-tamaya-extensions git commit: Simplified events module, adapted documentation as well. Removed model dependency from events, since events is the more general module here.
Date Mon, 26 Sep 2016 22:19:03 GMT
Simplified events module, adapted documentation as well.
Removed model dependency from events, since events is the more general module here.


Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/commit/384b09eb
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/tree/384b09eb
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/diff/384b09eb

Branch: refs/heads/master
Commit: 384b09eb8cc3dca3d4699a4353b4f6a420904623
Parents: c87ace0
Author: anatole <anatole@apache.org>
Authored: Wed Dec 16 08:37:17 2015 +0100
Committer: Oliver B. Fischer <plexus@apache.org>
Committed: Tue Sep 27 00:18:31 2016 +0200

----------------------------------------------------------------------
 .../tamaya/events/ChangeNotification.java       |  66 -----
 .../org/apache/tamaya/events/ChangeType.java    |  28 ++
 .../org/apache/tamaya/events/ConfigEvent.java   |  58 ++++
 .../tamaya/events/ConfigEventListener.java      |   5 +-
 .../tamaya/events/ConfigEventManager.java       | 112 ++++++--
 .../apache/tamaya/events/ConfigListener.java    |  31 ---
 .../tamaya/events/ConfigurationChange.java      | 222 +++++++++++++++
 .../events/ConfigurationChangeBuilder.java      | 272 +++++++++++++++++++
 .../events/ConfigurationContextChange.java      | 208 ++++++++++++++
 .../ConfigurationContextChangeBuilder.java      | 173 ++++++++++++
 .../tamaya/events/ConfigurationObserver.java    | 107 --------
 .../tamaya/events/PropertySourceChange.java     | 242 +++++++++++++++++
 .../events/PropertySourceChangeBuilder.java     | 258 ++++++++++++++++++
 .../apache/tamaya/events/delta/ChangeType.java  |  28 --
 .../events/delta/ConfigurationChange.java       | 216 ---------------
 .../delta/ConfigurationChangeBuilder.java       | 262 ------------------
 .../delta/ConfigurationContextChange.java       | 192 -------------
 .../ConfigurationContextChangeBuilder.java      | 159 -----------
 .../events/delta/PropertySourceChange.java      | 236 ----------------
 .../delta/PropertySourceChangeBuilder.java      | 258 ------------------
 .../folderobserver/FileChangeListener.java      |   3 +-
 .../ObservingPropertySourceProvider.java        |   8 +-
 .../internal/DefaultConfigChangeObserver.java   | 107 ++++++++
 .../internal/DefaultConfigEventManagerSpi.java  | 162 ++++++++---
 .../internal/DefaultConfigObserverSpi.java      | 158 -----------
 ...faultConfigurationContextChangeListener.java |  57 ++--
 .../events/internal/LoggingConfigListener.java  |  14 +-
 .../org/apache/tamaya/events/package-info.java  |   3 +-
 .../tamaya/events/spi/BaseConfigEvent.java      |  69 +++++
 .../events/spi/ConfigEventManagerSpi.java       |  83 +++++-
 .../tamaya/events/spi/ConfigObserverSpi.java    |  71 -----
 ...org.apache.tamaya.events.ConfigEventListener |   2 +-
 ...g.apache.tamaya.events.spi.ConfigObserverSpi |   2 +-
 .../events/ChangeableGlobalPropertySource.java  |  62 +++++
 .../ChangeableThreadLocalPropertySource.java    |  57 ++++
 .../tamaya/events/ConfigEventManagerTest.java   |  25 +-
 .../org/apache/tamaya/events/SimpleEvent.java   |  13 +
 .../events/delta/ConfigurationChangeTest.java   |   4 +-
 .../delta/ConfigurationContextChangeTest.java   |   9 +-
 .../events/delta/PropertySourceChangeTest.java  |   5 +-
 .../DefaultConfigEventManagerSpiTest.java       |  19 +-
 41 files changed, 2151 insertions(+), 1915 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/ChangeNotification.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/ChangeNotification.java b/src/main/java/org/apache/tamaya/events/ChangeNotification.java
deleted file mode 100644
index 73a4fa9..0000000
--- a/src/main/java/org/apache/tamaya/events/ChangeNotification.java
+++ /dev/null
@@ -1,66 +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.events;
-
-import java.beans.PropertyChangeEvent;
-import java.util.Collection;
-
-
-/**
- * Event that contains a set current changes that were applied or could be applied.
- * @param <T> the event type
- */
-public interface ChangeNotification<T>{
-
-    /**
-     * Get the underlying property provider/configuration.
-     * @return the underlying property provider/configuration, never null.
-     */
-    T getResource();
-
-    /**
-     * Get the version relative to the observed resource. The version is required to be unique for
-     * each change emmitted for a resource. There is no further requirement how this uniqueness is
-     * modelled, so returning a UUID is cometely valid.
-     * @return the base version.
-     */
-    String getVersion();
-
-    /**
-     * Get the timestamp in millis from the current epoch. it is expected that the timestamp and the version are unique to
-     * identify a changeset.
-     * @return the timestamp, when this changeset was created.
-     */
-    long getTimestamp();
-
-    /**
-     * Get the changes recorded.
-     * @return the recorded changes, never null.
-     */
-    Collection<PropertyChangeEvent> getChanges();
-
-    /**
-     * Checks if the given key is added, or updated OR removed.
-     * @param key the target key (can also be a regular expression), that matches the requested keys,
-     *            not null.
-     * @return true, if the given key was added, or updated BUT NOT removed.
-     */
-    boolean isKeyAffected(String key);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/ChangeType.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/ChangeType.java b/src/main/java/org/apache/tamaya/events/ChangeType.java
new file mode 100644
index 0000000..4363579
--- /dev/null
+++ b/src/main/java/org/apache/tamaya/events/ChangeType.java
@@ -0,0 +1,28 @@
+/*
+ * 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.events;
+
+/**
+ * Created by Anatole on 20.02.2015.
+ */
+public enum ChangeType {
+    NEW,
+    DELETED,
+    UPDATED,
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/ConfigEvent.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/ConfigEvent.java b/src/main/java/org/apache/tamaya/events/ConfigEvent.java
new file mode 100644
index 0000000..b56145e
--- /dev/null
+++ b/src/main/java/org/apache/tamaya/events/ConfigEvent.java
@@ -0,0 +1,58 @@
+/*
+ * 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.events;
+
+import java.beans.PropertyChangeEvent;
+import java.util.Collection;
+
+
+/**
+ * Event that contains a set current changes that were applied or could be applied.
+ * @param <T> the resource type.
+ */
+public interface ConfigEvent<T>{
+
+    /**
+     * Access the type of resource. This allows to easily determine the resource an event wants to observe.
+     * @return the resource type.
+     */
+    Class<T> getResourceType();
+
+    /**
+     * Get the underlying property provider/configuration.
+     * @return the underlying property provider/configuration, never null.
+     */
+    T getResource();
+
+    /**
+     * Get the version relative to the observed resource. The version is required to be unique for
+     * each change emmitted for a resource. There is no further requirement how this uniqueness is
+     * modelled, so returning a UUID is a completely valid strategy.
+     * @return the base version.
+     */
+    String getVersion();
+
+    /**
+     * Get the timestamp in millis from the current epoch. it is expected that the timestamp and the version are unique to
+     * identify a changeset.
+     * @return the timestamp, when this changeset was created.
+     */
+    long getTimestamp();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/ConfigEventListener.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/ConfigEventListener.java b/src/main/java/org/apache/tamaya/events/ConfigEventListener.java
index dde5175..de635f8 100644
--- a/src/main/java/org/apache/tamaya/events/ConfigEventListener.java
+++ b/src/main/java/org/apache/tamaya/events/ConfigEventListener.java
@@ -20,14 +20,13 @@ package org.apache.tamaya.events;
 
 /**
  * Interface to be implemented for listening on changes on {@link org.apache.tamaya.Configuration} instances.
- * @param <T> the type listened to.
  */
 //@FunctionalInterface
-public interface ConfigEventListener<T> {
+public interface ConfigEventListener {
     /**
      * Called if an event occurred.
      * @param event the event, not null.
      */
-    void onConfigEvent(T event);
+    void onConfigEvent(ConfigEvent<?> event);
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/ConfigEventManager.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/ConfigEventManager.java b/src/main/java/org/apache/tamaya/events/ConfigEventManager.java
index 1095d48..f0bd0fa 100644
--- a/src/main/java/org/apache/tamaya/events/ConfigEventManager.java
+++ b/src/main/java/org/apache/tamaya/events/ConfigEventManager.java
@@ -42,12 +42,23 @@ public final class ConfigEventManager {
     }
 
     /**
-     * Add a listener for observing change events on {@link org.apache.tamaya.Configuration}. References of this
-     * component to the listeners must be managed as weak references.
-     *
+     * Adds a Config listener that listens to all kind of {@link ConfigEvent}.
+     * @param l the listener not null.
+     */
+    public static void addListener(ConfigEventListener l) {
+        if (SPI == null) {
+            throw new ConfigException("No SPI registered for " +
+                    ConfigEventManager.class.getName());
+        }
+        SPI.addListener(l);
+    }
+
+    /**
+     * Adds a Config listener that listens to all kind of {@link ConfigEvent}.
      * @param l the listener not null.
+     * @param eventType the event type to which this listener listens to.
      */
-    public static <T> void addListener(ConfigEventListener<T> l) {
+    public static <T extends ConfigEvent> void addListener(ConfigEventListener l, Class<T> eventType) {
         if (SPI == null) {
             throw new ConfigException("No SPI registered for " +
                     ConfigEventManager.class.getName());
@@ -56,12 +67,25 @@ public final class ConfigEventManager {
     }
 
     /**
-     * Add a listener for observing change events on {@link org.apache.tamaya.spi.PropertySource}. References of this
-     * component to the listeners must be managed as weak references.
+     * Removes a listener registered globally.
+     *
+     * @param l the listener not null.
+     */
+    public static void removeListener(ConfigEventListener l) {
+        if (SPI == null) {
+            throw new ConfigException("No SPI registered for " +
+                    ConfigEventManager.class.getName());
+        }
+        SPI.removeListener(l);
+    }
+
+    /**
+     * Removes a listener registered for the given event type.
      *
      * @param l the listener not null.
+     * @param eventType the event type to which this listener listens to.
      */
-    public static <T> void removeListener(ConfigEventListener<T> l) {
+    public static <T extends ConfigEvent> void removeListener(ConfigEventListener l, Class<T> eventType) {
         if (SPI == null) {
             throw new ConfigException("No SPI registered for " +
                     ConfigEventManager.class.getName());
@@ -70,38 +94,84 @@ public final class ConfigEventManager {
     }
 
     /**
-     * Access all registered ConfigEventListeners listening to the given event type.
+     * Access all registered ConfigEventListeners listening to a given event type.
      * @param type the event type
      * @param <T> type param
      * @return a list with the listeners found, never null.
      */
-    public static <T>
-        Collection<? extends ConfigEventListener<T>> getListeneters(Class<T> type) {
+    public static <T extends ConfigEvent>
+        Collection<? extends ConfigEventListener> getListeners(Class<T> type) {
         return SPI.getListeners(type);
     }
 
+    /**
+     * Access all registered ConfigEventListeners listening to a all kind of event types globally.
+     * @return a list with the listeners found, never null.
+     */
+    public static <T extends ConfigEvent>
+    Collection<? extends ConfigEventListener> getListeners() {
+        return SPI.getListeners();
+    }
 
     /**
-     * Publishes sn event to all interested listeners.
+     * Publishes a {@link ConfigurationChange} synchronously to all interested listeners.
      *
      * @param event the event, not null.
      */
-    public static void fireEvent(Object event) {
-        fireEvent(event, (Class)event.getClass());
+    public static <T> void fireEvent(ConfigEvent<?> event) {
+        SPI.fireEvent(event);
     }
 
     /**
-     * Publishes a {@link org.apache.tamaya.events.delta.ConfigurationChange} to all interested listeners.
+     * Publishes a {@link ConfigurationChange} asynchronously/multithreaded to all interested listeners.
      *
      * @param event the event, not null.
-     *              @param eventType the event type, the vent may be a subclass.
      */
-    public static <T> void fireEvent(T event, Class<T> eventType) {
-        if (SPI == null) {
-            throw new ConfigException("No SPI registered for " +
-                    ConfigEventManager.class.getName());
-        }
-        SPI.fireEvent(event, eventType);
+    public static <T> void fireEventAsynch(ConfigEvent<?> event) {
+        SPI.fireEventAsynch(event);
+    }
+
+    /**
+     * Start/Stop the change monitoring service, which will observe/reevaluate the current configuration regularly
+     * and triggers ConfigurationChange events is something changed. This is quite handy for publishing
+     * configuration changes to whatever systems are interested in. Hereby the origin of a configuration change
+     * can be on this machine, or also remotedly. FOr handling corresponding {@link ConfigEventListener} have
+     * to be registered, e.g. listening on {@link org.apache.tamaya.events.ConfigurationChange} events.
+     * @see #isChangeMonitoring()
+     * @see #getChangeMonitoringPeriod()
+     */
+    public static void enableChangeMonitoring(boolean enable) {
+        SPI.enableChangeMonitor(enable);
+    }
+
+    /**
+     * Check if the observer is running currently.
+     *
+     * @return true, if the change monitoring service is currently running.
+     * @see #enableChangeMonitoring(boolean)
+     */
+    public static boolean isChangeMonitoring() {
+        return SPI.isChangeMonitorActive();
+    }
+
+    /**
+     * Get the current check period to check for configuration changes.
+     *
+     * @return the check period in ms.
+     */
+    public long getChangeMonitoringPeriod(){
+        return SPI.getChangeMonitoringPeriod();
+    }
+
+    /**
+     * Sets the current monitoring period and restarts the monitor. You still have to enable the monitor if
+     * it is currently not enabled.
+     * @param millis
+     * @see #enableChangeMonitoring(boolean)
+     * @see #isChangeMonitoring()
+     */
+    public void setChangeMonitoringPeriod(long millis){
+        SPI.setChangeMonitoringPeriod(millis);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/ConfigListener.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/ConfigListener.java b/src/main/java/org/apache/tamaya/events/ConfigListener.java
deleted file mode 100644
index 3608921..0000000
--- a/src/main/java/org/apache/tamaya/events/ConfigListener.java
+++ /dev/null
@@ -1,31 +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.events;
-
-import org.apache.tamaya.events.delta.ConfigurationChange;
-
-/**
- * Simple observer interface that can be registered using the current {@code ServiceContext}.
- * This class will be called on each configuration change detected in the current environment.
- */
-// @FunctionalInterface
-public interface ConfigListener
-        extends ConfigEventListener<ConfigurationChange> {
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/ConfigurationChange.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/ConfigurationChange.java b/src/main/java/org/apache/tamaya/events/ConfigurationChange.java
new file mode 100644
index 0000000..a291084
--- /dev/null
+++ b/src/main/java/org/apache/tamaya/events/ConfigurationChange.java
@@ -0,0 +1,222 @@
+/*
+ * 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.events;
+
+import org.apache.tamaya.Configuration;
+
+import java.beans.PropertyChangeEvent;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * 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 PropertySourceChangeBuilder}.
+ *
+ * Created by Anatole on 22.10.2014.
+ */
+public final class ConfigurationChange implements ConfigEvent<Configuration>, Serializable{
+
+    private static final long serialVersionUID = 1L;
+    /** The base property provider/configuration. */
+    private FrozenConfiguration configuration;
+    /** The base version, usable for optimistic locking. */
+    private String version = UUID.randomUUID().toString();
+    /** The timestamp of the change set in millis from the epoch. */
+    private long timestamp = System.currentTimeMillis();
+    /** The recorded changes. */
+    private Map<String,PropertyChangeEvent> changes = new HashMap<>();
+
+    /**
+     * Get an empty change set for the given provider.
+     * @param configuration The configuration changed, not null.
+     * @return an empty ConfigurationChangeSet instance.
+     */
+    public static ConfigurationChange emptyChangeSet(Configuration configuration){
+        return ConfigurationChangeBuilder.of(configuration).build();
+    }
+
+    /**
+     * Constructor used by {@link PropertySourceChangeBuilder}.
+     * @param builder The builder used, not null.
+     */
+    ConfigurationChange(ConfigurationChangeBuilder builder) {
+        this.configuration = FrozenConfiguration.of(builder.source);
+        for(PropertyChangeEvent ev:builder.delta.values()){
+            this.changes.put(ev.getPropertyName(), ev);
+        }
+        if(builder.version!=null){
+            this.version = builder.version;
+        }
+        if(builder.timestamp!=null){
+            this.timestamp = builder.timestamp;
+        }
+    }
+
+    @Override
+    public Class<Configuration> getResourceType() {
+        return Configuration.class;
+    }
+
+    /**
+     * Get the underlying property provider/configuration.
+     * @return the underlying property provider/configuration, never null.
+     */
+    @Override
+    public Configuration getResource(){
+        return this.configuration;
+    }
+
+    /**
+     * Get the base version, usable for optimistic locking.
+     * @return the base version.
+     */
+    @Override
+    public String getVersion(){
+        return version;
+    }
+
+    /**
+     * Get the timestamp in millis from the current epoch. it is expected that the timestamp and the version are unique to
+     * identify a changeset.
+     * @return the timestamp, when this changeset was created.
+     */
+    @Override
+    public long getTimestamp(){
+        return timestamp;
+    }
+
+    /**
+     * Get the changes recorded.
+     * @return the recorded changes, never null.
+     */
+    public Collection<PropertyChangeEvent> getChanges(){
+        return Collections.unmodifiableCollection(this.changes.values());
+    }
+
+    /**
+     * Access the number current removed entries.
+     * @return the number current removed entries.
+     */
+    public int getRemovedSize() {
+        int removedCount = 0;
+        for(PropertyChangeEvent ev:this.changes.values()){
+            if(ev.getNewValue() == null){
+                removedCount++;
+            }
+        }
+        return removedCount;
+//        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() {
+        int addedCount = 0;
+        for(PropertyChangeEvent ev:this.changes.values()){
+            if(ev.getOldValue() == null &&
+                    ev.getNewValue() != null){
+                addedCount++;
+            }
+        }
+        return addedCount;
+//        return (int) this.changes.values().stream().filter((e) -> e.getOldValue() == null &&
+//                e.getNewValue() != null).count();
+    }
+
+    /**
+     * Access the number current updated entries.
+     * @return the number current updated entries.
+     */
+    public int getUpdatedSize() {
+        int updatedCount = 0;
+        for(PropertyChangeEvent ev:this.changes.values()){
+            if( ev.getOldValue()!=null && ev.getNewValue()!=null){
+                updatedCount++;
+            }
+        }
+        return updatedCount;
+//        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 isKeyAffected(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 "ConfigurationChange{" +
+                "configuration=" + configuration +
+                ", version='" + version + '\'' +
+                ", timestamp=" + timestamp +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/ConfigurationChangeBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/ConfigurationChangeBuilder.java b/src/main/java/org/apache/tamaya/events/ConfigurationChangeBuilder.java
new file mode 100644
index 0000000..78f60a9
--- /dev/null
+++ b/src/main/java/org/apache/tamaya/events/ConfigurationChangeBuilder.java
@@ -0,0 +1,272 @@
+/*
+ * 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.events;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+
+import java.beans.PropertyChangeEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * Models a set current changes applied to a {@link org.apache.tamaya.spi.PropertySource}. Consumers of these events
+ * can observing changes to property sources and
+ * <ol>
+ * <li>Check if their current configuration instance ({@link org.apache.tamaya.spi.ConfigurationContext}
+ * contains the changed {@link org.apache.tamaya.spi.PropertySource} (Note: the reference tova property source is never affected by a
+ * change, its only the data of the property source).</li>
+ * <li>If so corresponding action may be taken, such as reevaluating the configuration values (depending on
+ * the update policy) or reevaluating the complete {@link org.apache.tamaya.Configuration} to create a change
+ * event on configuration level.
+ * </ol>
+ */
+public final class ConfigurationChangeBuilder {
+    /**
+     * The recorded changes.
+     */
+    final SortedMap<String, PropertyChangeEvent> delta = new TreeMap<>();
+    /**
+     * The underlying configuration/provider.
+     */
+    Configuration source;
+    /**
+     * The version configured, or null, for generating a default.
+     */
+    String version;
+    /**
+     * The optional timestamp in millis of this epoch.
+     */
+    Long timestamp;
+
+    /**
+     * Constructor.
+     *
+     * @param configuration the underlying configuration, not null.
+     */
+    private ConfigurationChangeBuilder(Configuration configuration) {
+        this.source = Objects.requireNonNull(configuration);
+    }
+
+    /**
+     * Creates a new instance current this builder using the current COnfiguration as root resource.
+     *
+     * @return the builder for chaining.
+     */
+    public static ConfigurationChangeBuilder of() {
+        return new ConfigurationChangeBuilder(ConfigurationProvider.getConfiguration());
+    }
+
+    /**
+     * Creates a new instance current this builder.
+     *
+     * @param configuration the configuration changed, not null.
+     * @return the builder for chaining.
+     */
+    public static ConfigurationChangeBuilder of(Configuration configuration) {
+        return new ConfigurationChangeBuilder(configuration);
+    }
+
+    /**
+     * 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(Configuration map1, Configuration map2) {
+        List<PropertyChangeEvent> changes = new ArrayList<>();
+        for (Map.Entry<String, String> en : map1.getProperties().entrySet()) {
+            String val = map2.get(en.getKey());
+            if (val == null) {
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), null, en.getValue()));
+            } else if (!val.equals(en.getValue())) {
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), val, en.getValue()));
+            }
+        }
+        for (Map.Entry<String, String> en : map2.getProperties().entrySet()) {
+            String val = map1.get(en.getKey());
+            if (val == null) {
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), null, en.getValue()));
+            } else if (!val.equals(en.getValue())) {
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), val, en.getValue()));
+            }
+        }
+        return changes;
+    }
+
+    /*
+     * Apply a version/UUID to the set being built.
+     * @param version the version to apply, or null, to let the system generate a version for you.
+     * @return the builder for chaining.
+     */
+    public ConfigurationChangeBuilder setVersion(String version) {
+        this.version = version;
+        return this;
+    }
+
+    /*
+     * Apply given timestamp to the set being built.
+     * @param version the version to apply, or null, to let the system generate a version for you.
+     * @return the builder for chaining.
+     */
+    public ConfigurationChangeBuilder setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+        return this;
+    }
+
+    /**
+     * 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 ConfigurationChangeBuilder addChanges(Configuration newState) {
+        for (PropertyChangeEvent c : compare(newState, this.source)) {
+            this.delta.put(c.getPropertyName(), c);
+        }
+        return this;
+    }
+
+    /**
+     * Applies a single key/value change.
+     *
+     * @param key   the changed key
+     * @param value the new value.
+     * @return this instance for chining.
+     */
+    public ConfigurationChangeBuilder addChange(String key, String value) {
+        this.delta.put(key, new PropertyChangeEvent(this.source, key, this.source.get(key), value));
+        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 ConfigurationChangeBuilder removeKey(String key, String... otherKeys) {
+        String oldValue = this.source.get(key);
+        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);
+            if (oldValue == null) {
+                this.delta.remove(addKey);
+            }
+            this.delta.put(addKey, new PropertyChangeEvent(this.source, addKey, oldValue, null));
+        }
+        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 ConfigurationChangeBuilder 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 ConfigurationChangeBuilder removeAllKeys() {
+        this.delta.clear();
+        for (Map.Entry<String, String> en : this.source.getProperties().entrySet()) {
+            this.delta.put(en.getKey(), new PropertyChangeEvent(this.source, en.getKey(), en.getValue(), null));
+        }
+//        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 ConfigurationChange build() {
+        return new ConfigurationChange(this);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "ConfigurationChangeSetBuilder [config=" + source + ", " +
+                ", delta=" + delta + "]";
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/ConfigurationContextChange.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/ConfigurationContextChange.java b/src/main/java/org/apache/tamaya/events/ConfigurationContextChange.java
new file mode 100644
index 0000000..eda5ab1
--- /dev/null
+++ b/src/main/java/org/apache/tamaya/events/ConfigurationContextChange.java
@@ -0,0 +1,208 @@
+/*
+ * 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.events;
+
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.PropertySource;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * 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 PropertySourceChangeBuilder}.
+ *
+ * Created by Anatole on 22.10.2014.
+ */
+public final class ConfigurationContextChange implements ConfigEvent<ConfigurationContext>, Serializable{
+
+    private static final long serialVersionUID = 1L;
+    /** The base property provider/configuration. */
+    private List<PropertySourceChange> changedPropertySources = new ArrayList<>();
+    /** The base version, usable for optimistic locking. */
+    private String version = UUID.randomUUID().toString();
+    /** The timestamp of the change set in millis from the epoch. */
+    private long timestamp = System.currentTimeMillis();
+    /** The configuration context. */
+    private ConfigurationContext configurationContext;
+
+    /**
+     * Get an empty change set for the given provider.
+     * @return an empty ConfigurationContextChange instance.
+     */
+    public static ConfigurationContextChange emptyChangeSet(ConfigurationContext configurationContext){
+        return ConfigurationContextChangeBuilder.of(configurationContext).build();
+    }
+
+    /**
+     * Constructor used by {@link PropertySourceChangeBuilder}.
+     * @param builder The builder used, not null.
+     */
+    ConfigurationContextChange(ConfigurationContextChangeBuilder builder) {
+        this.changedPropertySources.addAll(builder.changedPropertySources);
+        if(builder.version!=null){
+            this.version = builder.version;
+        }
+        if(builder.timestamp!=null){
+            this.timestamp = builder.timestamp;
+        }
+        this.configurationContext = builder.configurationContext;
+    }
+
+    @Override
+    public Class<ConfigurationContext> getResourceType() {
+        return ConfigurationContext.class;
+    }
+
+    @Override
+    public ConfigurationContext getResource() {
+        return configurationContext;
+    }
+
+    /**
+     * Get the base version, usable for optimistic locking.
+     * @return the base version.
+     */
+    @Override
+    public String getVersion(){
+        return version;
+    }
+
+    /**
+     * Get the timestamp in millis from the current epoch. it is expected that the timestamp and the version are unique to
+     * identify a changeset.
+     * @return the timestamp, when this changeset was created.
+     */
+    @Override
+    public long getTimestamp(){
+        return timestamp;
+    }
+
+    /**
+     * Get the changes recorded.
+     * @return the recorded changes, never null.
+     */
+    public Collection<PropertySourceChange> getPropertySourceChanges(){
+        return Collections.unmodifiableCollection(this.changedPropertySources);
+    }
+
+    /**
+     * Get the property source updates.
+     * @return the recorded changes, never null.
+     */
+    public Collection<PropertySourceChange> getPropertySourceUpdates(){
+        List<PropertySourceChange> result = new ArrayList<>();
+        for (PropertySourceChange pc : this.changedPropertySources) {
+            if (pc.getChangeType() == ChangeType.UPDATED) {
+                result.add(pc);
+            }
+        }
+        return result;
+//        return Collections.unmodifiableCollection(this.changedPropertySources).stream()
+//                .filter(pc -> pc.getChangeType()==ChangeType.UPDATED).collect(Collectors.toList());
+    }
+
+    /**
+     * Get the property sources to be removed.
+     * @return the recorded changes, never null.
+     */
+    public Collection<PropertySource> getRemovedPropertySources(){
+        List<PropertySource> result = new ArrayList<>();
+        for (PropertySourceChange pc : this.changedPropertySources) {
+            if (pc.getChangeType() == ChangeType.DELETED) {
+                result.add(pc.getResource());
+            }
+        }
+        return result;
+//        return getPropertySourceChanges().stream().filter(pc -> pc.getChangeType()==ChangeType.DELETED).
+//                map(ps -> ps.getPropertySource()).collect(Collectors.toList());
+    }
+
+    /**
+     * Get the property sources to be added.
+     * @return the recorded changes, never null.
+     */
+    public Collection<PropertySource> getAddedPropertySources(){
+        List<PropertySource> result = new ArrayList<>();
+        for (PropertySourceChange pc : this.changedPropertySources) {
+            if (pc.getChangeType() == ChangeType.NEW) {
+                result.add(pc.getResource());
+            }
+        }
+        return result;
+//        return getPropertySourceChanges().stream().filter(pc -> pc.getChangeType()==ChangeType.NEW).
+//                map(ps -> ps.getPropertySource()).collect(Collectors.toList());
+    }
+
+    /**
+     * Get the property sources to be updated.
+     * @return the recorded changes, never null.
+     */
+    public Collection<PropertySource> getUpdatedPropertySources(){
+        List<PropertySource> result = new ArrayList<>();
+        for (PropertySourceChange pc : this.changedPropertySources) {
+            if (pc.getChangeType() == ChangeType.UPDATED) {
+                result.add(pc.getResource());
+            }
+        }
+        return result;
+//        return getPropertySourceChanges().stream().filter(pc -> pc.getChangeType()==ChangeType.UPDATED).
+//                map(ps -> ps.getPropertySource()).collect(Collectors.toList());
+    }
+
+    /**
+     * Checks if the given propertySource is affected (added, changed or removed).
+     * @param propertySource the propertySource, not null.
+     * @return true, if the given propertySource ia affected.
+     */
+    public boolean isAffected(PropertySource propertySource) {
+        for (PropertySourceChange ps : this.changedPropertySources) {
+            if (ps.getResource() == propertySource ||
+                    ps.getResource().getName().equals(propertySource.getName())) {
+                return true;
+            }
+        }
+        return false;
+//        return this.changedPropertySources.stream().filter(ps ->  ps.getPropertySource()==propertySource ||
+//                ps.getPropertySource().getName().equals(propertySource.getName())).findAny().isPresent();
+    }
+
+    /**
+     * CHecks if the current change set does not contain any changes.
+     * @return tru, if the change set is empty.
+     */
+    public boolean isEmpty(){
+        return this.changedPropertySources.isEmpty();
+    }
+
+
+    @Override
+    public String toString() {
+        return "ConfigurationContextChange{" +
+                "changedPropertySources=" + changedPropertySources +
+                ", version='" + version + '\'' +
+                ", timestamp=" + timestamp +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/ConfigurationContextChangeBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/ConfigurationContextChangeBuilder.java b/src/main/java/org/apache/tamaya/events/ConfigurationContextChangeBuilder.java
new file mode 100644
index 0000000..2341f92
--- /dev/null
+++ b/src/main/java/org/apache/tamaya/events/ConfigurationContextChangeBuilder.java
@@ -0,0 +1,173 @@
+/*
+ * 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.events;
+
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.PropertySource;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Models a set current changes applied to a {@link org.apache.tamaya.spi.PropertySource}. Consumers of these events
+ * can observing changes to property sources and
+ * <ol>
+ *     <li>Check if their current configuration instance ({@link org.apache.tamaya.spi.ConfigurationContext}
+ *     contains the changed {@link org.apache.tamaya.spi.PropertySource} (Note: the reference tova property source is never affected by a
+ *     change, its only the data of the property source).</li>
+ *     <li>If so corresponding action may be taken, such as reevaluating the configuration values (depending on
+ *     the update policy) or reevaluating the complete {@link org.apache.tamaya.Configuration} to create a change
+ *     event on configuration level.
+ * </ol>
+ */
+public final class ConfigurationContextChangeBuilder {
+    /**
+     * The recorded changes.
+     */
+    final List<PropertySourceChange> changedPropertySources = new ArrayList<>();
+    /**
+     * The version configured, or null, for generating a default.
+     */
+    String version;
+    /**
+     * The optional timestamp in millis of this epoch.
+     */
+    Long timestamp;
+
+    ConfigurationContext configurationContext;
+
+    /**
+     * Constructor.
+     */
+    private ConfigurationContextChangeBuilder(ConfigurationContext configurationContext) {
+        this.configurationContext = Objects.requireNonNull(configurationContext);
+    }
+
+    /**
+     * Just creates a new ConfigurationContextBuilder using the current COnfigurationContext has root resource.
+     * @return a new ConfigurationContextBuilder, never null.
+     */
+    public static ConfigurationContextChangeBuilder of() {
+        return of(ConfigurationProvider.getConfigurationContext());
+    }
+
+    /**
+     * Creates a new instance current this builder.
+     *
+     * @return the builder for chaining.
+     */
+    public static ConfigurationContextChangeBuilder of(ConfigurationContext context) {
+        return new ConfigurationContextChangeBuilder(context);
+    }
+
+    /*
+     * Apply a version/UUID to the set being built.
+     * @param version the version to apply, or null, to let the system generate a version for you.
+     * @return the builder for chaining.
+     */
+    public ConfigurationContextChangeBuilder setVersion(String version) {
+        this.version = version;
+        return this;
+    }
+
+    /*
+     * Apply given timestamp to the set being built.
+     * @param version the version to apply, or null, to let the system generate a version for you.
+     * @return the builder for chaining.
+     */
+    public ConfigurationContextChangeBuilder setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+        return this;
+    }
+
+    /**
+     * This method records all changes to be applied to the base property provider/configuration to
+     * achieve the given target state.
+     *
+     * @param propertySource the new target state, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigurationContextChangeBuilder newPropertySource(PropertySource propertySource) {
+        this.changedPropertySources.add(PropertySourceChange.ofAdded(propertySource));
+        return this;
+    }
+
+    /**
+     * This method records all changes to be applied to the base property provider/configuration to
+     * achieve the given target state.
+     *
+     * @param propertySource the new target state, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigurationContextChangeBuilder removedPropertySource(PropertySource propertySource) {
+        this.changedPropertySources.add(PropertySourceChange.ofDeleted(propertySource));
+        return this;
+    }
+
+    /**
+     * This method records all changes to be applied to the base property provider/configuration to
+     * achieve the given target state.
+     *
+     * @param propertySourceChange the change state, not null.
+     * @return the builder for chaining.
+     */
+    public ConfigurationContextChangeBuilder changedPropertySource(PropertySourceChange propertySourceChange) {
+        this.changedPropertySources.add(Objects.requireNonNull(propertySourceChange));
+        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.changedPropertySources.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.changedPropertySources.clear();
+    }
+
+    /**
+     * Builds the corresponding change set.
+     *
+     * @return the new change set, never null.
+     */
+    public ConfigurationContextChange build() {
+        return new ConfigurationContextChange(this);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "ConfigurationContextChangeBuilder [propertySources=" + changedPropertySources + "]";
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/ConfigurationObserver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/ConfigurationObserver.java b/src/main/java/org/apache/tamaya/events/ConfigurationObserver.java
deleted file mode 100644
index 1eafc0c..0000000
--- a/src/main/java/org/apache/tamaya/events/ConfigurationObserver.java
+++ /dev/null
@@ -1,107 +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.events;
-
-import org.apache.tamaya.ConfigException;
-import org.apache.tamaya.events.spi.ConfigObserverSpi;
-import org.apache.tamaya.spi.ServiceContextManager;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Set;
-
-/**
- * Singleton accessor for managing {@link ConfigListener} instances and mappings.
- */
-public class ConfigurationObserver {
-
-    /**
-     * Private singleton constructor.
-     */
-    private ConfigurationObserver() {
-    }
-
-    /**
-     * The backing SPI.
-     */
-    private static final ConfigObserverSpi SPI = ServiceContextManager.getServiceContext()
-            .getService(ConfigObserverSpi.class);
-
-
-    /**
-     * Add key expressions for generating ConfigurationChange events.
-     *
-     * @param keys             the keys to be observed for changes.
-     */
-    public static <T> void addObservedKeys(Collection<String> keys) {
-        if (SPI == null) {
-            throw new ConfigException("No SPI registered for " +
-                    ConfigurationObserver.class.getName());
-        }
-        SPI.addObservedKeys(keys);
-    }
-
-    /**
-     * Add key expressions for generating ConfigurationChange events.
-     *
-     * @param keys             the keys to be observed for changes.
-     */
-    public static <T> void addObservedKeys(String... keys) {
-        if (SPI == null) {
-            throw new ConfigException("No SPI registered for " +
-                    ConfigurationObserver.class.getName());
-        }
-        SPI.addObservedKeys(Arrays.asList(keys));
-    }
-
-    /**
-     * Removes key expressions for generating ConfigurationChange events.
-     *
-     * @param keys the keys to be observed for changes.
-     */
-    public static <T> void removeObservedKeys(Collection<String> keys) {
-        if (SPI == null) {
-            throw new ConfigException("No SPI registered for " +
-                    ConfigurationObserver.class.getName());
-        }
-        SPI.removeObservedKeys(keys);
-    }
-
-    /**
-     * Removes key expressions for generating ConfigurationChange events.
-     *
-     * @param keys the keys to be observed for changes.
-     */
-    public static <T> void removeObservedKeys(String... keys) {
-        if (SPI == null) {
-            throw new ConfigException("No SPI registered for " +
-                    ConfigurationObserver.class.getName());
-        }
-        SPI.removeObservedKeys(Arrays.asList(keys));
-    }
-
-    /**
-     * Get all registered key expressions for generating ConfigurationChange events.
-     *
-     * @return  set with the keys found, never null.
-     */
-    public static Set<String> getObservedKeys() {
-        return SPI.getObservedKeys();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/PropertySourceChange.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/PropertySourceChange.java b/src/main/java/org/apache/tamaya/events/PropertySourceChange.java
new file mode 100644
index 0000000..a34e949
--- /dev/null
+++ b/src/main/java/org/apache/tamaya/events/PropertySourceChange.java
@@ -0,0 +1,242 @@
+/*
+ * 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.events;
+
+import org.apache.tamaya.spi.PropertySource;
+
+import java.beans.PropertyChangeEvent;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * 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 PropertySourceChangeBuilder}.
+ *
+ * Created by Anatole on 22.10.2014.
+ */
+public final class PropertySourceChange implements ConfigEvent<PropertySource>, Serializable{
+
+    private static final long serialVersionUID = 1L;
+    /** The base property provider/configuration. */
+    private FrozenPropertySource propertySource;
+    /** The base version, usable for optimistic locking. */
+    private String version = UUID.randomUUID().toString();
+    /** The timestamp of the change set in millis from the epoch. */
+    private long timestamp = System.currentTimeMillis();
+    /** The recorded changes. */
+    private Map<String,PropertyChangeEvent> changes = new HashMap<>();
+    /** The overall type of change. */
+    private ChangeType changeType;
+
+    /**
+     * Constructor used by {@link PropertySourceChangeBuilder}.
+     * @param builder The builder used, not null.
+     */
+    PropertySourceChange(PropertySourceChangeBuilder builder) {
+        this.propertySource = FrozenPropertySource.of(builder.source);
+        for (PropertyChangeEvent c : builder.delta.values()) {
+            this.changes.put(c.getPropertyName(), c);
+        }
+        if(builder.version!=null){
+            this.version = builder.version;
+        }
+        if(builder.timestamp!=null){
+            this.timestamp = builder.timestamp;
+        }
+        this.changeType = builder.changeType;
+    }
+
+    /**
+     * Gets the type of change for this PropertySource.
+     * @return the type of change for this PropertySource, never null.
+     */
+    public ChangeType getChangeType(){
+        return this.changeType;
+    }
+
+    @Override
+    public Class<PropertySource> getResourceType() {
+        return PropertySource.class;
+    }
+
+    /**
+     * Get the underlying property provider/configuration.
+     * @return the underlying property provider/configuration, or null, if the change instance was deserialized.
+     */
+    @Override
+    public PropertySource getResource(){
+        return this.propertySource;
+    }
+
+    /**
+     * Get the base version, usable for optimistic locking.
+     * @return the base version.
+     */
+    @Override
+    public String getVersion(){
+        return version;
+    }
+
+    /**
+     * Get the timestamp in millis from the current epoch. it is expected that the timestamp and the version are unique to
+     * identify a changeset.
+     * @return the timestamp, when this changeset was created.
+     */
+    @Override
+    public long getTimestamp(){
+        return timestamp;
+    }
+
+    /**
+     * Get the changes recorded.
+     * @return the recorded changes, never null.
+     */
+    public Collection<PropertyChangeEvent> getChanges(){
+        return Collections.unmodifiableCollection(this.changes.values());
+    }
+
+    /**
+     * Access the number current removed entries.
+     * @return the number current removed entries.
+     */
+    public int getRemovedSize() {
+        int removedCount = 0;
+        for (PropertyChangeEvent ev : this.changes.values()) {
+            if (ev.getNewValue() == null) {
+                removedCount++;
+            }
+        }
+        return removedCount;
+//        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() {
+        int addedCount = 0;
+        for (PropertyChangeEvent ev : this.changes.values()) {
+            if (ev.getOldValue() == null &&
+                    ev.getNewValue() != null) {
+                addedCount++;
+            }
+        }
+        return addedCount;
+//        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() {
+        int updatedCount = 0;
+        for (PropertyChangeEvent ev : this.changes.values()) {
+            if (ev.getOldValue() != null && ev.getNewValue() != null) {
+                updatedCount++;
+            }
+        }
+        return updatedCount;
+//        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 isKeyAffected(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();
+    }
+
+
+    /**
+     * Create a change event for a new PropertySource that was added.
+     * @param propertySource the new property source, not null.
+     * @return a new PropertySourceChange, representing a PropertySource that was added.
+     */
+    public static PropertySourceChange ofAdded(PropertySource propertySource) {
+        return PropertySourceChangeBuilder.of(propertySource, ChangeType.NEW).build();
+    }
+
+    /**
+     * Create a change event for a deleted PropertySource.
+     * @param propertySource the deleted property source, not null.
+     * @return a new PropertySourceChange, representing a PropertySource that was deleted.
+     */
+    public static PropertySourceChange ofDeleted(PropertySource propertySource) {
+        return PropertySourceChangeBuilder.of(propertySource, ChangeType.DELETED).build();
+    }
+
+    @Override
+    public String toString() {
+        return "PropertySourceChange{" +
+                "changeType=" + changeType +
+                ", propertySource=" + propertySource +
+                ", version='" + version + '\'' +
+                ", timestamp=" + timestamp +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/PropertySourceChangeBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/PropertySourceChangeBuilder.java b/src/main/java/org/apache/tamaya/events/PropertySourceChangeBuilder.java
new file mode 100644
index 0000000..25f3620
--- /dev/null
+++ b/src/main/java/org/apache/tamaya/events/PropertySourceChangeBuilder.java
@@ -0,0 +1,258 @@
+/*
+ * 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.events;
+
+import org.apache.tamaya.spi.PropertySource;
+
+import java.beans.PropertyChangeEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * Models a set current changes applied to a {@link org.apache.tamaya.spi.PropertySource}. Consumers of these events
+ * can observing changes to property sources and
+ * <ol>
+ *     <li>Check if their current configuration instance ({@link org.apache.tamaya.spi.ConfigurationContext}
+ *     contains the changed {@link org.apache.tamaya.spi.PropertySource} (Note: the reference tova property source is never affected by a
+ *     change, its only the data of the property source).</li>
+ *     <li>If so corresponding action may be taken, such as reevaluating the configuration values (depending on
+ *     the update policy) or reevaluating the complete {@link org.apache.tamaya.Configuration} to create a change
+ *     event on configuration level.
+ * </ol>
+ */
+public final class PropertySourceChangeBuilder {
+    /**
+     * The recorded changes.
+     */
+    final SortedMap<String, PropertyChangeEvent> delta = new TreeMap<>();
+    /**
+     * The underlying configuration/provider.
+     */
+    PropertySource source;
+    /**
+     * The version configured, or null, for generating a default.
+     */
+    String version;
+    /**
+     * The optional timestamp in millis of this epoch.
+     */
+    Long timestamp;
+
+    /** The type of change. */
+    ChangeType changeType;
+
+    /**
+     * Constructor.
+     *
+     * @param source the underlying configuration/provider, not null.
+     */
+    private PropertySourceChangeBuilder(PropertySource source, ChangeType changeType) {
+        this.source = Objects.requireNonNull(source);
+        this.changeType = Objects.requireNonNull(changeType);
+    }
+
+    /**
+     * Creates a new instance current this builder.
+     *
+     * @param source the underlying property provider/configuration, not null.
+     * @return the builder for chaining.
+     */
+    public static PropertySourceChangeBuilder of(PropertySource source, ChangeType changeType) {
+        return new PropertySourceChangeBuilder(source, changeType);
+    }
+
+    /**
+     * 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()) {
+            String val = map2.get(en.getKey());
+            if (val == null) {
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), null, en.getValue()));
+            } else if (!val.equals(en.getValue())) {
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), val, en.getValue()));
+            }
+        }
+        for (Map.Entry<String, String> en : map2.getProperties().entrySet()) {
+            String val = map1.get(en.getKey());
+            if (val == null) {
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), en.getValue(), null));
+            } else if (!val.equals(en.getValue())) {
+                changes.add(new PropertyChangeEvent(map1, en.getKey(), en.getValue(), val));
+            }
+        }
+        return changes;
+    }
+
+    /*
+     * Apply a version/UUID to the set being built.
+     * @param version the version to apply, or null, to let the system generate a version for you.
+     * @return the builder for chaining.
+     */
+    public PropertySourceChangeBuilder setVersion(String version) {
+        this.version = version;
+        return this;
+    }
+
+    /*
+     * Apply given timestamp to the set being built.
+     * @param version the version to apply, or null, to let the system generate a version for you.
+     * @return the builder for chaining.
+     */
+    public PropertySourceChangeBuilder setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+        return this;
+    }
+
+    /**
+     * 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 PropertySourceChangeBuilder addChanges(PropertySource newState) {
+        Collection<PropertyChangeEvent> events = PropertySourceChangeBuilder.compare(newState, this.source);
+        for (PropertyChangeEvent c : events) {
+            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 PropertySourceChangeBuilder remove(String key, String... otherKeys) {
+        String oldValue = this.source.get(key);
+        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);
+            if (oldValue == null) {
+                this.delta.remove(addKey);
+            }
+            this.delta.put(addKey, new PropertyChangeEvent(this.source, addKey, oldValue, null));
+        }
+        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 PropertySourceChangeBuilder 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 PropertySourceChangeBuilder deleteAll() {
+        this.delta.clear();
+        for (Map.Entry<String, String> en : this.source.getProperties().entrySet()) {
+            this.delta.put(en.getKey(), new PropertyChangeEvent(this.source, en.getKey(), en.getValue(), 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();
+    }
+
+    public PropertySourceChangeBuilder setChangeType(ChangeType changeType) {
+        this.changeType = changeType;
+        return this;
+    }
+
+    /**
+     * Builds the corresponding change set.
+     *
+     * @return the new change set, never null.
+     */
+    public PropertySourceChange build() {
+        return new PropertySourceChange(this);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "PropertiesChangeBuilder [source=" + source + ", " +
+                ", delta=" + delta + "]";
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/delta/ChangeType.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/delta/ChangeType.java b/src/main/java/org/apache/tamaya/events/delta/ChangeType.java
deleted file mode 100644
index ecc0a2d..0000000
--- a/src/main/java/org/apache/tamaya/events/delta/ChangeType.java
+++ /dev/null
@@ -1,28 +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.events.delta;
-
-/**
- * Created by Anatole on 20.02.2015.
- */
-public enum ChangeType {
-    NEW,
-    DELETED,
-    UPDATED,
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/384b09eb/src/main/java/org/apache/tamaya/events/delta/ConfigurationChange.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/tamaya/events/delta/ConfigurationChange.java b/src/main/java/org/apache/tamaya/events/delta/ConfigurationChange.java
deleted file mode 100644
index 41c6ba1..0000000
--- a/src/main/java/org/apache/tamaya/events/delta/ConfigurationChange.java
+++ /dev/null
@@ -1,216 +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.events.delta;
-
-import org.apache.tamaya.Configuration;
-import org.apache.tamaya.events.ChangeNotification;
-import org.apache.tamaya.events.FrozenConfiguration;
-
-import java.beans.PropertyChangeEvent;
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-
-/**
- * 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 PropertySourceChangeBuilder}.
- *
- * Created by Anatole on 22.10.2014.
- */
-public final class ConfigurationChange implements ChangeNotification<Configuration>, Serializable{
-
-    private static final long serialVersionUID = 1L;
-    /** The base property provider/configuration. */
-    private FrozenConfiguration configuration;
-    /** The base version, usable for optimistic locking. */
-    private String version = UUID.randomUUID().toString();
-    /** The timestamp of the change set in millis from the epoch. */
-    private long timestamp = System.currentTimeMillis();
-    /** The recorded changes. */
-    private Map<String,PropertyChangeEvent> changes = new HashMap<>();
-
-    /**
-     * Get an empty change set for the given provider.
-     * @param configuration The configuration changed, not null.
-     * @return an empty ConfigurationChangeSet instance.
-     */
-    public static ConfigurationChange emptyChangeSet(Configuration configuration){
-        return ConfigurationChangeBuilder.of(configuration).build();
-    }
-
-    /**
-     * Constructor used by {@link PropertySourceChangeBuilder}.
-     * @param builder The builder used, not null.
-     */
-    ConfigurationChange(ConfigurationChangeBuilder builder) {
-        this.configuration = FrozenConfiguration.of(builder.source);
-        for(PropertyChangeEvent ev:builder.delta.values()){
-            this.changes.put(ev.getPropertyName(), ev);
-        }
-        if(builder.version!=null){
-            this.version = builder.version;
-        }
-        if(builder.timestamp!=null){
-            this.timestamp = builder.timestamp;
-        }
-    }
-
-    /**
-     * Get the underlying property provider/configuration.
-     * @return the underlying property provider/configuration, never null.
-     */
-    public Configuration getResource(){
-        return this.configuration;
-    }
-
-    /**
-     * Get the base version, usable for optimistic locking.
-     * @return the base version.
-     */
-    public String getVersion(){
-        return version;
-    }
-
-    /**
-     * Get the timestamp in millis from the current epoch. it is expected that the timestamp and the version are unique to
-     * identify a changeset.
-     * @return the timestamp, when this changeset was created.
-     */
-    public long getTimestamp(){
-        return timestamp;
-    }
-
-    /**
-     * Get the changes recorded.
-     * @return the recorded changes, never null.
-     */
-    public Collection<PropertyChangeEvent> getChanges(){
-        return Collections.unmodifiableCollection(this.changes.values());
-    }
-
-    /**
-     * Access the number current removed entries.
-     * @return the number current removed entries.
-     */
-    public int getRemovedSize() {
-        int removedCount = 0;
-        for(PropertyChangeEvent ev:this.changes.values()){
-            if(ev.getNewValue() == null){
-                removedCount++;
-            }
-        }
-        return removedCount;
-//        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() {
-        int addedCount = 0;
-        for(PropertyChangeEvent ev:this.changes.values()){
-            if(ev.getOldValue() == null &&
-                    ev.getNewValue() != null){
-                addedCount++;
-            }
-        }
-        return addedCount;
-//        return (int) this.changes.values().stream().filter((e) -> e.getOldValue() == null &&
-//                e.getNewValue() != null).count();
-    }
-
-    /**
-     * Access the number current updated entries.
-     * @return the number current updated entries.
-     */
-    public int getUpdatedSize() {
-        int updatedCount = 0;
-        for(PropertyChangeEvent ev:this.changes.values()){
-            if( ev.getOldValue()!=null && ev.getNewValue()!=null){
-                updatedCount++;
-            }
-        }
-        return updatedCount;
-//        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 isKeyAffected(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 "ConfigurationChange{" +
-                "configuration=" + configuration +
-                ", version='" + version + '\'' +
-                ", timestamp=" + timestamp +
-                '}';
-    }
-}


Mime
View raw message