You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tamaya.apache.org by pl...@apache.org on 2016/09/26 22:19:03 UTC

[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.

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 <an...@apache.org>
Authored: Wed Dec 16 08:37:17 2015 +0100
Committer: Oliver B. Fischer <pl...@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 +
-                '}';
-    }
-}