tamaya-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ple...@apache.org
Subject [32/50] [abbrv] incubator-tamaya-extensions git commit: TAMAYA-175 Moved the events module to the directory events after extracting it for the Tamaya main repository.
Date Sun, 23 Oct 2016 20:36:44 GMT
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/delta/package-info.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/delta/package-info.java b/events/src/main/java/org/apache/tamaya/events/delta/package-info.java
new file mode 100644
index 0000000..2006717
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/delta/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/**
+ * This package contains artifacts to describe the changes (delta) of a
+ * Configuration or a PropertySource.
+ */
+package org.apache.tamaya.events.delta;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/folderobserver/FileChangeListener.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/folderobserver/FileChangeListener.java b/events/src/main/java/org/apache/tamaya/events/folderobserver/FileChangeListener.java
new file mode 100644
index 0000000..283719e
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/folderobserver/FileChangeListener.java
@@ -0,0 +1,144 @@
+/*
+ * 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.folderobserver;
+
+import org.apache.tamaya.ConfigException;
+
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+/**
+ * Class that has the responsibility to watch the folder and then publish the changes to a
+ * {@link org.apache.tamaya.events.PropertySourceChange}.
+ * @see ObservingPropertySourceProvider
+ * This listener will wait to events and wait to one second to watch again.
+ * <p>If new file was created or modified will commit from this file.</p>
+ * <p>If a file was removed then the listener will load using all files left.</p>
+ * @author otaviojava
+ */
+class FileChangeListener implements Runnable {
+
+    private static final Logger LOGGER = Logger.getLogger(FileChangeListener.class.getName());
+
+    private final WatchService watchService;
+
+    private final FileChangeObserver observer;
+
+    private final Path directory;
+
+    private volatile boolean running = true;
+
+    public FileChangeListener(Path directory, FileChangeObserver observer) {
+        this.observer = observer;
+        this.directory = directory;
+        this.watchService = getWatchService();
+
+        if (watchService!=null && directory!=null) {
+            try {
+                directory.register(watchService,
+                        StandardWatchEventKinds.ENTRY_DELETE,
+                        StandardWatchEventKinds.ENTRY_MODIFY,
+                        StandardWatchEventKinds.ENTRY_CREATE);
+            } catch (IOException e) {
+                throw new FileChangeListenerException("An error happened when does try to registry to watch the folder", e);
+            }
+        }
+    }
+
+    /**
+     * Stops the listener service from observing the target directory.
+     */
+    public void stopListener(){
+        running = false;
+    }
+
+    @Override
+    public void run() {
+        if (watchService!=null || directory!=null) {
+            return;
+        }
+        while (running) {
+            watchFolder();
+        }
+    }
+
+    /**
+     * Start watching the current folder.
+     */
+    private void watchFolder() {
+        try {
+            WatchKey watckKey = watchService.take();
+            for (WatchEvent<?> event : watckKey.pollEvents()) {
+                Path filePath = (Path) watckKey.watchable();
+                if(event.kind().equals(StandardWatchEventKinds.ENTRY_CREATE)||
+                        event.kind().equals(StandardWatchEventKinds.ENTRY_MODIFY) ||
+                        event.kind().equals(StandardWatchEventKinds.ENTRY_DELETE)){
+                    LOGGER.info("File change detected in: " + filePath.getFileName());
+                    observer.directoryChanged(filePath);
+                }
+            }
+            watckKey.reset();
+            Thread.sleep(1_000L);
+        } catch (Exception e) {
+            throw new FileChangeListenerException("An error happened when does try to watch the folder", e);
+        }
+    }
+
+    /**
+     * Get the watch service.
+     * @return the watch service, or null, if the watch service is not supported.
+     */
+    private WatchService getWatchService() {
+        try {
+            FileSystem fileSystem = Paths.get(".").getFileSystem();
+            return fileSystem.newWatchService();
+        } catch (IOException e) {
+            LOGGER.log(Level.WARNING, "The file System does not supports WatchService", e);
+            return null;
+        }
+
+    }
+
+    /**
+     * Exception if file listening fails.
+     */
+    static class FileChangeListenerException extends ConfigException {
+        /** Serialversion UID. */
+        private static final long serialVersionUID = -8965486770881001513L;
+
+        /**
+         * Constructor.
+         * @param message a message
+         * @param cause an (optional) root cause.
+         */
+        public FileChangeListenerException(String message, Throwable cause) {
+            super(message, cause);
+        }
+
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/folderobserver/FileChangeObserver.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/folderobserver/FileChangeObserver.java b/events/src/main/java/org/apache/tamaya/events/folderobserver/FileChangeObserver.java
new file mode 100644
index 0000000..63d25cd
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/folderobserver/FileChangeObserver.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.events.folderobserver;
+
+import java.nio.file.Path;
+
+/**
+ * Observer to be used in {@link FileChangeListener} to commit all configurations and provider.
+ */
+interface FileChangeObserver {
+    /**
+     * Called when a file has been modified.
+     * @param path the file path, not null.
+     */
+    void directoryChanged(Path path);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/folderobserver/ObservingPropertySourceProvider.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/folderobserver/ObservingPropertySourceProvider.java b/events/src/main/java/org/apache/tamaya/events/folderobserver/ObservingPropertySourceProvider.java
new file mode 100644
index 0000000..feddd70
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/folderobserver/ObservingPropertySourceProvider.java
@@ -0,0 +1,209 @@
+/*
+ * 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.folderobserver;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.events.ConfigEventManager;
+import org.apache.tamaya.events.ConfigurationContextChange;
+import org.apache.tamaya.events.ConfigurationContextChangeBuilder;
+import org.apache.tamaya.spi.PropertySource;
+import org.apache.tamaya.spi.PropertySourceProvider;
+import org.apache.tamaya.spisupport.BasePropertySource;
+
+/**
+ * This implementation runs in a folder taking up all files compatible with the given
+ * ConfigurationFormats. When a file is added, deleted or modified the PropertySourceProvider
+ * will adapt the changes automatically and trigger according
+ * {@link org.apache.tamaya.events.PropertySourceChange} events.
+ * The default folder is META-INF/config, but you can change it via an absolute path in the
+ * "-Dtamaya.configdir" parameter.
+ */
+public class ObservingPropertySourceProvider implements PropertySourceProvider, FileChangeObserver {
+    /**
+     * The logger.
+     */
+    private static final Logger LOG = Logger.getLogger(ObservingPropertySourceProvider.class.getName());
+    /**
+     * The current active property sources of this provider.
+     */
+    private final List<PropertySource> propertySources = Collections.synchronizedList(new LinkedList<PropertySource>());
+    /**
+     * The thread pool used.
+     */
+    private final ExecutorService executor = Executors.newSingleThreadExecutor();
+
+    /**
+     * Constructorm using an explicit directory, ignoring all kind of configuration, if set.
+     *
+     * @param directory the target directory. If null, the default configuration and system property are used.
+     */
+    public ObservingPropertySourceProvider(Path directory) {
+        if (directory == null) {
+            directory = getDirectory();
+        }
+        if (directory!=null){
+            synchronized (this.propertySources) {
+                this.propertySources.addAll(readConfiguration(directory));
+            }
+            final Runnable runnable = new FileChangeListener(directory, this);
+            executor.execute(runnable);
+        } else {
+            executor.shutdown();
+        }
+    }
+
+    /**
+     * Read the initial configuration.
+     *
+     * @param directory the target directory, not null.
+     */
+    private List<PropertySource> readConfiguration(Path directory) {
+        final List<PropertySource> result = new ArrayList<>();
+        try {
+            synchronized (propertySources) {
+                for (final Path path : Files.newDirectoryStream(directory, "*")) {
+                    result.addAll(getPropertySources(path));
+                }
+                return result;
+            }
+        } catch (final IOException e) {
+            LOG.log(Level.WARNING, "Failed to read configuration from dir: " + directory, e);
+        }
+        return result;
+    }
+
+    /**
+     * Read property sources from the given file.
+     * 
+     * @param file source of the property sources.
+     * @return property sources from the given file.
+     */
+    protected Collection<PropertySource> getPropertySources(final Path file) {
+        return Arrays.asList(new PropertySource[]{new BasePropertySource() {
+            private final Map<String,String> props = readProperties(file);
+
+            @Override
+            public Map<String, String> getProperties() {
+                return props;
+            }
+        }});
+    }
+
+    /**
+     * Load a single file.
+     *
+     * @param file the file, not null.
+     * @return properties as read from the given file.
+     */
+    protected static Map<String,String> readProperties(Path file) {
+        try (InputStream is = file.toUri().toURL().openStream()){
+            final Properties props = new Properties();
+                props.load(is);
+            final Map<String,String> result = new HashMap<>();
+            for(final Map.Entry<Object,Object> en:props.entrySet()){
+                result.put(String.valueOf(en.getKey()), String.valueOf(en.getValue()));
+            }
+            return result;
+        } catch (final Exception e) {
+            LOG.log(Level.INFO, "Error reading file: " + file.toString() +
+                    ", using format: properties", e);
+        }
+        return Collections.emptyMap();
+    }
+
+
+    /**
+     * Evaluates the target directory from system property (tamaya.configdir) or classpath.
+     *
+     * @return the directory to be read, or null.
+     */
+    private Path getDirectory() {
+        final String absolutePath = System.getProperty("tamaya.configdir");
+        if (null!=absolutePath) {
+            final Path path = Paths.get(absolutePath);
+            if (Files.isDirectory(path)) {
+                return path;
+            }
+        }
+        final URL resource = ObservingPropertySourceProvider.class.getResource("/META-INF/config/");
+        if (null!=resource) {
+            try {
+                return Paths.get(resource.toURI());
+            } catch (final URISyntaxException e) {
+                throw new ConfigException("An error to find the directory to watch", e);
+            }
+        }
+        return null;
+    }
+
+
+    @Override
+    public void directoryChanged(Path directory) {
+        synchronized (this.propertySources) {
+            final List<PropertySource> existingPropertySources = new ArrayList<>(propertySources);
+            propertySources.clear();
+            final Collection<PropertySource> sourcesRead = readConfiguration(directory);
+            this.propertySources.addAll(sourcesRead);
+            triggerConfigChange(existingPropertySources, propertySources);
+        }
+    }
+
+
+    private void triggerConfigChange(List<PropertySource> originalPropertySources,
+                                     List<PropertySource> newPropertySources) {
+        final ConfigurationContextChangeBuilder b = ConfigurationContextChangeBuilder.of();
+        for (final PropertySource ps : originalPropertySources) {
+            b.removedPropertySource(ps);
+        }
+        for (final PropertySource ps : newPropertySources) {
+            b.newPropertySource(ps);
+        }
+        final ConfigurationContextChange changeEvent = b.build();
+        LOG.fine("Trigger Config Context Change: " + changeEvent);
+        ConfigEventManager.fireEvent(changeEvent);
+    }
+
+    @Override
+    public Collection<PropertySource> getPropertySources() {
+        synchronized (propertySources) {
+            return new ArrayList<>(this.propertySources);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/folderobserver/package-info.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/folderobserver/package-info.java b/events/src/main/java/org/apache/tamaya/events/folderobserver/package-info.java
new file mode 100644
index 0000000..347f2d8
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/folderobserver/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+/**
+ * This package contains code to observe a folder for file changes and to trigger
+ * corresponding events, that are handled by an according {@link org.apache.tamaya.events.folderobserver.ObservingPropertySourceProvider}
+ * instance.
+ */
+package org.apache.tamaya.events.folderobserver;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigChangeObserver.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigChangeObserver.java b/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigChangeObserver.java
new file mode 100644
index 0000000..f4457b2
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigChangeObserver.java
@@ -0,0 +1,111 @@
+/*
+ * 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.internal;
+
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.events.ConfigEventManager;
+import org.apache.tamaya.events.ConfigurationChange;
+import org.apache.tamaya.events.ConfigurationChangeBuilder;
+import org.apache.tamaya.events.FrozenConfiguration;
+
+import java.util.*;
+import java.util.logging.Logger;
+
+/**
+ * Timer task that regularly checks the configuration for changes.
+ */
+public class DefaultConfigChangeObserver {
+
+    private static final long START_DELAY = 5000L;
+
+    private static final Logger LOG = Logger.getLogger(DefaultConfigChangeObserver.class.getName());
+
+    private Timer timer = new Timer("DefaultConfigChangeObserver", true);
+
+    private long checkPeriod = 2000L;
+
+    private volatile FrozenConfiguration lastConfig;
+
+    private volatile boolean running;
+
+    /**
+     * Constructor. Also loads all registered listeners.
+     */
+    public DefaultConfigChangeObserver() {
+        LOG.info("Registering config change observer, rechecking config changes every " + checkPeriod + " ms.");
+        timer.scheduleAtFixedRate(new TimerTask() {
+            @Override
+            public void run() {
+            if(running) {
+                checkConfigurationUpdate();
+            }
+            }
+        }, START_DELAY, checkPeriod);
+    }
+
+
+    public void checkConfigurationUpdate() {
+        LOG.finest("Checking configuration for changes...");
+        FrozenConfiguration newConfig = FrozenConfiguration.of(ConfigurationProvider.getConfiguration());
+        ConfigurationChange changes;
+        if(lastConfig==null){
+            changes = ConfigurationChangeBuilder.of(newConfig).putAll(newConfig.getProperties())
+                    .build();
+        }else{
+            changes = ConfigurationChangeBuilder.of(lastConfig).addChanges(newConfig)
+                    .build();
+        }
+        if(!changes.isEmpty()) {
+            LOG.info("Identified configuration changes, publishing change event...");
+            ConfigEventManager.fireEvent(changes);
+        }
+    }
+
+    public long getCheckPeriod() {
+        return checkPeriod;
+    }
+
+    public boolean isMonitoring(){
+        return running;
+    }
+
+    public void enableMonitoring(boolean enable){
+        this.running = true;
+    }
+
+    /**
+     * Sets the new check period, cancels the currently running timer and schedules a new task with the new checkperiod
+     * and a startup delay of 500ms.
+     * @param checkPeriod the period in ms, for checking on changes.
+     */
+    public void setCheckPeriod(long checkPeriod) {
+        LOG.finest("Resetting check period to " + checkPeriod + " ms, reregistering timer.");
+        this.checkPeriod = checkPeriod;
+        timer.cancel();
+        timer = new Timer("DefaultConfigChangeObserver", true);
+        timer.scheduleAtFixedRate(new TimerTask() {
+            @Override
+            public void run() {
+                if(running) {
+                    checkConfigurationUpdate();
+                }
+            }
+        }, 500L, checkPeriod);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigEventManagerSpi.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigEventManagerSpi.java b/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigEventManagerSpi.java
new file mode 100644
index 0000000..586df5c
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigEventManagerSpi.java
@@ -0,0 +1,202 @@
+/*
+ * 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.internal;
+
+import org.apache.tamaya.events.ConfigEvent;
+import org.apache.tamaya.events.ConfigEventListener;
+import org.apache.tamaya.events.spi.ConfigEventManagerSpi;
+import org.apache.tamaya.spi.ServiceContextManager;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Default implementation of {@link DefaultConfigEventManagerSpi} just forwarding all
+ * events synchronously to the listeners.
+ */
+public class DefaultConfigEventManagerSpi implements ConfigEventManagerSpi {
+
+    private static final Logger LOG = Logger.getLogger(DefaultConfigEventManagerSpi.class.getName());
+
+    private final Map<Class,List<ConfigEventListener>> listeners = new ConcurrentHashMap<>();
+
+    private final ExecutorService publisher = Executors.newCachedThreadPool();
+
+    private final DefaultConfigChangeObserver changeObserver = new DefaultConfigChangeObserver();
+
+    /**
+     * Constructor. Also loads all registered listeners.
+     */
+    public DefaultConfigEventManagerSpi() {
+        try {
+            for (ConfigEventListener l : ServiceContextManager.getServiceContext().getServices(ConfigEventListener.class)) {
+                try {
+                    addListener(l);
+                } catch (Exception e) {
+                    LOG.log(Level.WARNING, "Failed to load configured listener: " + l.getClass().getName(), e);
+                }
+            }
+        } catch (Exception e) {
+            LOG.log(Level.WARNING, "Failed to load configured listeners.", e);
+        }
+    }
+
+    @Override
+    public void addListener(ConfigEventListener l){
+        addListener(l, ConfigEvent.class);
+    }
+
+    @Override
+    public <T extends ConfigEvent> void addListener(ConfigEventListener l, Class<T> eventType){
+        List<ConfigEventListener> ls = listeners.get(eventType);
+        if(ls==null){
+            ls = Collections.synchronizedList(new ArrayList<ConfigEventListener>());
+            listeners.put(eventType, ls);
+        }
+        synchronized (ls){
+            if(!ls.contains(l)){
+                ls.add(l);
+            }
+        }
+    }
+
+    @Override
+    public void removeListener(ConfigEventListener l){
+        removeListener(l, ConfigEvent.class);
+    }
+
+    @Override
+    public <T extends ConfigEvent> void removeListener(ConfigEventListener l, Class<T> eventType) {
+        List<ConfigEventListener> targets = this.listeners.get(eventType);
+        if(targets!=null) {
+            // forward to explicit listeners
+            synchronized (targets) {
+                targets.remove(l);
+            }
+        }
+    }
+
+    @Override
+    public Collection<? extends ConfigEventListener> getListeners(Class<? extends ConfigEvent> eventType) {
+        List<ConfigEventListener> targets = this.listeners.get(eventType);
+        if(targets!=null){
+            synchronized(targets){
+                return new ArrayList<>(targets);
+            }
+        }
+        return Collections.emptyList();
+    }
+
+    @Override
+    public Collection<? extends ConfigEventListener> getListeners() {
+        Set<ConfigEventListener> targets = new HashSet<>();
+        for(List<ConfigEventListener> l:this.listeners.values()){
+            targets.addAll(l);
+        }
+        return targets;
+    }
+
+    @Override
+    public void fireEvent(ConfigEvent<?> event) {
+        List<ConfigEventListener> targets = this.listeners.get(event.getClass());
+        if(targets!=null) {
+            // forward to explicit listeners
+            synchronized (targets) {
+                for (ConfigEventListener l : targets) {
+                    l.onConfigEvent(event);
+                }
+            }
+        }
+        // forward to global listeners
+        targets = this.listeners.get(ConfigEvent.class);
+        if(targets!=null) {
+            synchronized (targets) {
+                for (ConfigEventListener l : targets) {
+                    l.onConfigEvent(event);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void fireEventAsynch(ConfigEvent<?> event) {
+        List<ConfigEventListener> targets = this.listeners.get(event.getClass());
+        if(targets!=null) {
+            // forward to explicit listeners
+            synchronized (targets) {
+                for (ConfigEventListener l : targets) {
+                    publisher.execute(new PublishConfigChangeTask(l, event));
+                }
+            }
+        }
+        // forward to global listeners
+        targets = this.listeners.get(ConfigEvent.class);
+        if(targets!=null) {
+            synchronized (targets) {
+                for (ConfigEventListener l : targets) {
+                    publisher.execute(new PublishConfigChangeTask(l, event));
+                }
+            }
+        }
+    }
+
+    @Override
+    public long getChangeMonitoringPeriod() {
+        return changeObserver.getCheckPeriod();
+    }
+
+    @Override
+    public void setChangeMonitoringPeriod(long millis){
+        changeObserver.setCheckPeriod(millis);
+    }
+
+    @Override
+    public boolean isChangeMonitorActive() {
+        return changeObserver.isMonitoring();
+    }
+
+    @Override
+    public void enableChangeMonitor(boolean enable) {
+        changeObserver.enableMonitoring(enable);
+    }
+
+
+    /**
+     * Tasks to inform observers on detected configuration changes.
+     */
+    private static final class PublishConfigChangeTask implements Runnable{
+
+        private final ConfigEventListener l;
+        private final ConfigEvent<?> changes;
+
+        public PublishConfigChangeTask(ConfigEventListener l, ConfigEvent<?> changes) {
+            this.l = Objects.requireNonNull(l);
+            this.changes = Objects.requireNonNull(changes);
+        }
+
+        @Override
+        public void run() {
+            l.onConfigEvent(changes);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java b/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java
new file mode 100644
index 0000000..e49856d
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java
@@ -0,0 +1,74 @@
+/*
+ * 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.internal;
+
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.events.ConfigEvent;
+import org.apache.tamaya.events.ConfigEventListener;
+import org.apache.tamaya.events.ConfigurationContextChange;
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.ConfigurationContextBuilder;
+import org.apache.tamaya.spi.PropertySource;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Default ConfigEventListener for ConfigurationContextChange events that updates the current context, if resources were
+ * affected.
+ */
+public class DefaultConfigurationContextChangeListener implements ConfigEventListener {
+
+    private static final Logger LOG = Logger.getLogger(DefaultConfigurationContextChangeListener.class.getName());
+
+    @Override
+    public void onConfigEvent(ConfigEvent<?> event) {
+        if(event.getClass() == ConfigurationContextChange.class) {
+            ConfigurationContextChange contextChange = (ConfigurationContextChange) event;
+            ConfigurationContext context = ConfigurationProvider.getConfigurationContext();
+            List<PropertySource> affectedPropertySources = new ArrayList<>();
+            for (PropertySource ps : context.getPropertySources()) {
+                if (contextChange.isAffected(ps)) {
+                    affectedPropertySources.add(ps);
+                }
+            }
+            ConfigurationContextBuilder newContextBuilder = ConfigurationProvider.getConfigurationContextBuilder()
+                    .setContext(context);
+            if (!affectedPropertySources.isEmpty()) {
+                Set<String> propertySourceNames = new HashSet<>();
+                for (PropertySource removed : contextChange.getRemovedPropertySources()) {
+                    propertySourceNames.add(removed.getName());
+                }
+                newContextBuilder.removePropertySources(propertySourceNames);
+            }
+            newContextBuilder.addPropertySources(contextChange.getAddedPropertySources());
+            newContextBuilder.addPropertySources(contextChange.getUpdatedPropertySources());
+            ConfigurationContext newContext = newContextBuilder.build();
+            try {
+                ConfigurationProvider.setConfigurationContext(newContext);
+            } catch (Exception e) {
+                LOG.log(Level.INFO, "Failed to update the current ConfigurationContext due to config model changes", e);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/internal/LoggingConfigListener.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/internal/LoggingConfigListener.java b/events/src/main/java/org/apache/tamaya/events/internal/LoggingConfigListener.java
new file mode 100644
index 0000000..be8c404
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/internal/LoggingConfigListener.java
@@ -0,0 +1,40 @@
+/*
+ * 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.internal;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.events.ConfigEvent;
+import org.apache.tamaya.events.ConfigEventListener;
+
+import java.util.logging.Logger;
+
+/**
+ * Simple ConfigListener that simply logs any detected config changes to INFO level.
+ */
+public class LoggingConfigListener implements ConfigEventListener {
+
+    private static final Logger LOG = Logger.getLogger(LoggingConfigListener.class.getName());
+
+    @Override
+    public void onConfigEvent(ConfigEvent<?> event) {
+        if(event.getResourceType()== Configuration.class) {
+            LOG.info("Configuration changed: " + event);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/internal/package-info.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/internal/package-info.java b/events/src/main/java/org/apache/tamaya/events/internal/package-info.java
new file mode 100644
index 0000000..9df5ac3
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/internal/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+/**
+ * This package contains internal default implementations for the config events module.
+ */
+package org.apache.tamaya.events.internal;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/package-info.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/package-info.java b/events/src/main/java/org/apache/tamaya/events/package-info.java
new file mode 100644
index 0000000..e175ceb
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+/**
+ * This package provides the main building blocks for handling configuration changes, such as
+ * {@link org.apache.tamaya.events.ConfigEventManager}, {@link org.apache.tamaya.events.ConfigEventListener} and
+ * artifacts to describe the changes (delta) of a Configuration or a PropertySource.
+ */
+package org.apache.tamaya.events;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/spi/BaseConfigEvent.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/spi/BaseConfigEvent.java b/events/src/main/java/org/apache/tamaya/events/spi/BaseConfigEvent.java
new file mode 100644
index 0000000..f6856d9
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/spi/BaseConfigEvent.java
@@ -0,0 +1,69 @@
+/*
+ * 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.spi;
+
+import org.apache.tamaya.events.ConfigEvent;
+
+import java.util.Objects;
+import java.util.UUID;
+
+/**
+ * Abstract base class for implementing your own configuration events.
+ * @param <T> the vent type
+ */
+public abstract class BaseConfigEvent<T> implements ConfigEvent<T> {
+        protected long timestamp = System.currentTimeMillis();
+        protected String version = UUID.randomUUID().toString();
+        protected final T paylod;
+        private final Class<T> type;
+
+        public BaseConfigEvent(T paylod, Class<T> type){
+            this.paylod = Objects.requireNonNull(paylod);
+            this.type = Objects.requireNonNull(type);
+        }
+
+        @Override
+        public Class<T> getResourceType() {
+            return type;
+        }
+
+        @Override
+        public T getResource() {
+            return paylod;
+        }
+
+        @Override
+        public String getVersion() {
+            return version;
+        }
+
+        @Override
+        public long getTimestamp() {
+            return timestamp;
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getSimpleName() + '{' +
+                    "timestamp=" + timestamp +
+                    ", version='" + version + '\'' +
+                    ", paylod='" + paylod + '\'' +
+                    '}';
+        }
+    }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/spi/ConfigEventManagerSpi.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/spi/ConfigEventManagerSpi.java b/events/src/main/java/org/apache/tamaya/events/spi/ConfigEventManagerSpi.java
new file mode 100644
index 0000000..66a8f73
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/spi/ConfigEventManagerSpi.java
@@ -0,0 +1,128 @@
+/*
+ * 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.spi;
+
+import org.apache.tamaya.events.ConfigEvent;
+import org.apache.tamaya.events.ConfigEventListener;
+
+import java.util.Collection;
+
+/**
+ * SPI interface to implement the {@link org.apache.tamaya.events.ConfigEventManager} singleton.
+ * Implementations of this interface must be registered with the current {@link org.apache.tamaya.spi.ServiceContext},
+ * by default this equals to registering it with {@link java.util.ServiceLoader}. Add {@link javax.annotation.Priority}
+ * annotations for overriding (higher values override lower values).
+ */
+public interface ConfigEventManagerSpi {
+    /**
+     * Adds a listener for observing events. References of this
+     * component to the listeners must be managed as weak references.
+     * 
+     * @param <T> the type of the events listened to.
+     * @param l the listener not null.
+     */
+    <T> void addListener(ConfigEventListener l);
+
+    /**
+     * Adds a listener for observing events of a given type.
+     *
+     * @param <T> the type of the events listened to.
+     * @param l the listener not null.
+     * @param eventType the type of concrete configuration event this listeners should be informed about. All other
+     *                  event types will never be delivered to this listener instance.
+     */
+    <T extends ConfigEvent> void addListener(ConfigEventListener l, Class<T> eventType);
+
+    /**
+     * Removes a listener for observing events.
+     *
+     * @param l the listener not null.
+     */
+    void removeListener(ConfigEventListener l);
+
+    /**
+     * Removes a listener for observing events of a certain type.
+     *
+     * @param <T> the type of the events listened to.
+     * @param l the listener not null.
+     * @param eventType the type of concrete configuration event this listeners should be informed about. All other
+     *                  event types will never be delivered toe this listener instance.
+     */
+    <T extends ConfigEvent> void removeListener(ConfigEventListener l, Class<T> eventType);
+
+    /**
+     * Access all globally registered listeners.
+     *
+     * @return the listeners found, never null.
+     */
+    Collection<? extends ConfigEventListener> getListeners();
+
+    /**
+     * Access all listeners listening for a certain event type, including any global listeners.
+     * @param eventType the type of concrete configuration event this listeners should be informed about. All other
+     *                  event types will never be delivered toe this listener instance.
+     * @return the listeners found, never null.
+     */
+    Collection<? extends ConfigEventListener> getListeners(Class<? extends ConfigEvent> eventType);
+
+    /**
+     * Publishes an event to all interested listeners, hereby executing all registered listeners sequentually and
+     * synchronously.,
+     *
+     * @param event the event, not null.
+     */
+    void fireEvent(ConfigEvent<?> event);
+
+    /**
+     * Publishes an event to all interested listeners, hereby publishing the change events asynchrously and in
+     * parallel (multithreaded).
+     *
+     * @param event the event, not null.
+     */
+    void fireEventAsynch(ConfigEvent<?> event);
+
+    /**
+     * Get the current check period to check for configuration changes.
+     *
+     * @return the check period in ms.
+     */
+    long getChangeMonitoringPeriod();
+
+    void setChangeMonitoringPeriod(long millis);
+
+    /**
+     * Check if the observer is running currently.
+     *
+     * @return true, if the change monitoring service is currently running.
+     */
+    boolean isChangeMonitorActive();
+
+    /**
+     * Start/stop the change monitoring service, which will observe/reevaluate the current configuration regularly
+     * and trigger ConfigurationChange events if something is 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.
+     * 
+     * @param enable whether to enable or disable the change monitoring.
+     */
+    void enableChangeMonitor(boolean enable);
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/java/org/apache/tamaya/events/spi/package-info.java
----------------------------------------------------------------------
diff --git a/events/src/main/java/org/apache/tamaya/events/spi/package-info.java b/events/src/main/java/org/apache/tamaya/events/spi/package-info.java
new file mode 100644
index 0000000..63d2b3b
--- /dev/null
+++ b/events/src/main/java/org/apache/tamaya/events/spi/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/**
+ * This package contains the SPI to implement the
+ * {@link org.apache.tamaya.events.ConfigEventManager} singleton.
+ */
+package org.apache.tamaya.events.spi;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/resources/META-INF/services/org.apache.tamaya.events.ConfigEventListener
----------------------------------------------------------------------
diff --git a/events/src/main/resources/META-INF/services/org.apache.tamaya.events.ConfigEventListener b/events/src/main/resources/META-INF/services/org.apache.tamaya.events.ConfigEventListener
new file mode 100644
index 0000000..f9942c1
--- /dev/null
+++ b/events/src/main/resources/META-INF/services/org.apache.tamaya.events.ConfigEventListener
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy current the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+org.apache.tamaya.events.internal.DefaultConfigurationContextChangeListener

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/main/resources/META-INF/services/org.apache.tamaya.events.spi.ConfigEventManagerSpi
----------------------------------------------------------------------
diff --git a/events/src/main/resources/META-INF/services/org.apache.tamaya.events.spi.ConfigEventManagerSpi b/events/src/main/resources/META-INF/services/org.apache.tamaya.events.spi.ConfigEventManagerSpi
new file mode 100644
index 0000000..d45dc43
--- /dev/null
+++ b/events/src/main/resources/META-INF/services/org.apache.tamaya.events.spi.ConfigEventManagerSpi
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy current the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+org.apache.tamaya.events.internal.DefaultConfigEventManagerSpi
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/test/java/org/apache/tamaya/events/ChangeableGlobalPropertySource.java
----------------------------------------------------------------------
diff --git a/events/src/test/java/org/apache/tamaya/events/ChangeableGlobalPropertySource.java b/events/src/test/java/org/apache/tamaya/events/ChangeableGlobalPropertySource.java
new file mode 100644
index 0000000..0384064
--- /dev/null
+++ b/events/src/test/java/org/apache/tamaya/events/ChangeableGlobalPropertySource.java
@@ -0,0 +1,62 @@
+/*
+ * 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.core.propertysource.BasePropertySource;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * PropertySource implementation that accesses properties that are statically stored.
+ */
+public class ChangeableGlobalPropertySource extends BasePropertySource{
+
+    private static final Map<String,String> STORED_ENTRIES = new ConcurrentHashMap<>();
+
+    @Override
+    public String getName() {
+        return getClass().getSimpleName();
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        return null;
+    }
+
+    /**
+     * Put a value (globally) into this property source.
+     * @param key the key, not null
+     * @param value the value, not null
+     * @return the entry replaced, or null.
+     */
+    public static String put(String key, String value){
+        return STORED_ENTRIES.put(key,value);
+    }
+
+    /**
+     * Put all the properties, overriding any existing ones with the same key.
+     * @param properties the properties, not null.
+     */
+    public static void putAll(Map<String,String> properties){
+        STORED_ENTRIES.putAll(properties);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/test/java/org/apache/tamaya/events/ChangeableThreadLocalPropertySource.java
----------------------------------------------------------------------
diff --git a/events/src/test/java/org/apache/tamaya/events/ChangeableThreadLocalPropertySource.java b/events/src/test/java/org/apache/tamaya/events/ChangeableThreadLocalPropertySource.java
new file mode 100644
index 0000000..cc6c812
--- /dev/null
+++ b/events/src/test/java/org/apache/tamaya/events/ChangeableThreadLocalPropertySource.java
@@ -0,0 +1,57 @@
+/*
+ * 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.core.propertysource.BasePropertySource;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * PropertySource implementation that accesses properties that are stored on ThreadLocal level, e.g. good to use for
+ * testing..
+ */
+public class ChangeableThreadLocalPropertySource extends BasePropertySource{
+
+    private static final ThreadLocal<Map<String,String>> STORED_ENTRIES = new ThreadLocal<Map<String,String>>(){
+        protected Map<String,String> initialValue(){
+            return new HashMap<>();
+        }
+    };
+
+    @Override
+    public String getName() {
+        return getClass().getSimpleName();
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        return null;
+    }
+
+    public static String put(String key, String value){
+        return STORED_ENTRIES.get().put(key,value);
+    }
+
+    public static void putAll(Map<String,String> properties){
+        STORED_ENTRIES.get().putAll(properties);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/test/java/org/apache/tamaya/events/ConfigEventManagerTest.java
----------------------------------------------------------------------
diff --git a/events/src/test/java/org/apache/tamaya/events/ConfigEventManagerTest.java b/events/src/test/java/org/apache/tamaya/events/ConfigEventManagerTest.java
new file mode 100644
index 0000000..b56407c
--- /dev/null
+++ b/events/src/test/java/org/apache/tamaya/events/ConfigEventManagerTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.junit.Test;
+
+import java.util.UUID;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for {@link ConfigEventManager}.
+ */
+public class ConfigEventManagerTest {
+
+    private Object testAddListenerValue;
+
+    @Test
+    public void testAddRemoveListener() throws Exception {
+        ConfigEventListener testListener = new ConfigEventListener() {
+            @Override
+            public void onConfigEvent(ConfigEvent<?> event) {
+                testAddListenerValue = event.getResource();
+            }
+        };
+        ConfigEventManager.addListener(testListener);
+        ConfigEventManager.fireEvent(new SimpleEvent("Event1"));
+        assertEquals(testAddListenerValue, "Event1");
+        ConfigEventManager.removeListener(testListener);
+        ConfigEventManager.fireEvent(new SimpleEvent("Event2"));
+        assertEquals(testAddListenerValue, "Event1");
+    }
+
+    @Test
+    public void testFireEvent() throws Exception {
+        ConfigEventListener testListener = new ConfigEventListener() {
+            @Override
+            public void onConfigEvent(ConfigEvent<?> event) {
+                testAddListenerValue = event.getResource();
+            }
+        };
+        ConfigEventManager.addListener(testListener);
+        ConfigEventManager.fireEvent(new SimpleEvent("Event1"));
+        assertEquals(testAddListenerValue, "Event1");
+        ConfigEventManager.removeListener(testListener);
+        ConfigEventManager.fireEvent(new SimpleEvent("Event2"));
+        assertEquals(testAddListenerValue, "Event1");
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/test/java/org/apache/tamaya/events/FrozenPropertySourceTest.java
----------------------------------------------------------------------
diff --git a/events/src/test/java/org/apache/tamaya/events/FrozenPropertySourceTest.java b/events/src/test/java/org/apache/tamaya/events/FrozenPropertySourceTest.java
new file mode 100644
index 0000000..1431228
--- /dev/null
+++ b/events/src/test/java/org/apache/tamaya/events/FrozenPropertySourceTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.core.propertysource.SystemPropertySource;
+import org.apache.tamaya.spi.PropertySource;
+import org.junit.Test;
+
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for {@link org.apache.tamaya.events.FrozenPropertySource}.
+ */
+public class FrozenPropertySourceTest {
+
+    private static final PropertySource myPS = new SystemPropertySource();
+
+    @Test
+    public void testOf() throws Exception {
+        PropertySource ps = FrozenPropertySource.of(myPS);
+        assertNotNull(ps);
+    }
+
+    @Test
+    public void testGetName() throws Exception {
+        PropertySource ps = FrozenPropertySource.of(myPS);
+        String name = ps.getName();
+        assertNotNull(name);
+        assertEquals(name, ps.getName());
+    }
+
+    @Test
+    public void testGetOrdinal() throws Exception {
+        PropertySource ps = FrozenPropertySource.of(myPS);
+        assertEquals(myPS.getOrdinal(), ps.getOrdinal());
+    }
+
+    @Test
+    public void testGet() throws Exception {
+        PropertySource ps = FrozenPropertySource.of(myPS);
+        assertNotNull(ps);
+        for (Map.Entry<String, String> e : myPS.getProperties().entrySet()) {
+            assertEquals(ps.get(e.getKey()).getValue(), e.getValue());
+        }
+    }
+
+    @Test
+    public void testGetProperties() throws Exception {
+        PropertySource ps = FrozenPropertySource.of(myPS);
+        assertNotNull(ps);
+        assertNotNull(ps.getProperties());
+        assertFalse(ps.getProperties().isEmpty());
+    }
+
+    @Test
+    public void testEquals() throws Exception {
+        PropertySource ps1 = FrozenPropertySource.of(myPS);
+        PropertySource ps2 = FrozenPropertySource.of(myPS);
+        assertEquals(ps1.getName(), ps2.getName());
+        assertEquals(ps1.getProperties().size(), ps2.getProperties().size());
+    }
+
+    @Test
+    public void testHashCode() throws Exception {
+        boolean alwaysDifferent = true;
+        for(int i=0;i<10;i++){
+            PropertySource ps1 = FrozenPropertySource.of(myPS);
+            PropertySource ps2 = FrozenPropertySource.of(myPS);
+            // sometimes not same, because frozenAt in ms maybe different
+            if(ps1.hashCode()==ps2.hashCode()){
+                alwaysDifferent=false;
+                break;
+            }
+        }
+        if(alwaysDifferent){
+            fail("HashCode should be same if frozenAt is in the same ms...");
+        }
+    }
+
+    @Test
+    public void testToString() throws Exception {
+        PropertySource ps = FrozenPropertySource.of(myPS);
+        String toString = ps.toString();
+        assertNotNull(toString);
+        assertTrue(toString.contains("FrozenPropertySource"));
+        assertTrue(toString.contains(myPS.getName()));
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/test/java/org/apache/tamaya/events/ObservedConfigTest.java
----------------------------------------------------------------------
diff --git a/events/src/test/java/org/apache/tamaya/events/ObservedConfigTest.java b/events/src/test/java/org/apache/tamaya/events/ObservedConfigTest.java
new file mode 100644
index 0000000..0cd9e2b
--- /dev/null
+++ b/events/src/test/java/org/apache/tamaya/events/ObservedConfigTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.commons.io.FileUtils;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test (currently manual) to test configuration changes.
+ */
+public class ObservedConfigTest {
+
+    @Test
+    @Ignore // reactivate later...
+    public void testChangingConfig() throws IOException {
+        Configuration config = ConfigurationProvider.getConfiguration().with(TestConfigView.of());
+
+        Map<String, String> props = config.getProperties();
+        assertEquals(props.get("test"), "test2");
+        assertEquals(props.get("testValue1"), "value");
+        assertNull(props.get("testValue2"));
+
+        //insert a new properties file into the tempdirectory
+        FileUtils.writeStringToFile(
+                new File(TestObservingProvider.propertyLocation.toFile(), "test2.properties"),
+                "testValue2=anotherValue");
+
+        try {
+            Thread.sleep(10000);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
+        config = ConfigurationProvider.getConfiguration().with(TestConfigView.of());
+
+        props = config.getProperties();
+
+        assertEquals(props.get("test"), "test2");
+        assertEquals(props.get("testValue1"), "value");
+        assertEquals(props.get("testValue2"), "anotherValue");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/test/java/org/apache/tamaya/events/RandomPropertySource.java
----------------------------------------------------------------------
diff --git a/events/src/test/java/org/apache/tamaya/events/RandomPropertySource.java b/events/src/test/java/org/apache/tamaya/events/RandomPropertySource.java
new file mode 100644
index 0000000..dead0d9
--- /dev/null
+++ b/events/src/test/java/org/apache/tamaya/events/RandomPropertySource.java
@@ -0,0 +1,66 @@
+/*
+ * 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 org.apache.tamaya.spi.PropertyValue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * PropertySource that provides a randome entry, different on each access!
+ */
+public class RandomPropertySource implements PropertySource{
+
+    private Map<String, String> data = new HashMap<>();
+
+    @Override
+    public int getOrdinal() {
+        return 0;
+    }
+
+    @Override
+    public String getName() {
+        return "random";
+    }
+
+    @Override
+    public PropertyValue get(String key) {
+        if(key.equals("random.new")){
+            return PropertyValue.of(key, String.valueOf(Math.random()),getName());
+        }
+        return null;
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        synchronized(data) {
+            data.put("random.new", String.valueOf(Math.random()));
+            data.put("_random.new.source", getName());
+            data.put("_random.new.timestamp", String.valueOf(System.currentTimeMillis()));
+            return new HashMap<>(data);
+        }
+    }
+
+    @Override
+    public boolean isScannable() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/test/java/org/apache/tamaya/events/SimpleEvent.java
----------------------------------------------------------------------
diff --git a/events/src/test/java/org/apache/tamaya/events/SimpleEvent.java b/events/src/test/java/org/apache/tamaya/events/SimpleEvent.java
new file mode 100644
index 0000000..5017aa1
--- /dev/null
+++ b/events/src/test/java/org/apache/tamaya/events/SimpleEvent.java
@@ -0,0 +1,32 @@
+/*
+ * 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.spi.BaseConfigEvent;
+
+/**
+ * Simple test event for testing only.
+ */
+public class SimpleEvent extends BaseConfigEvent<String> {
+
+    public SimpleEvent(String paylod) {
+        super(paylod, String.class);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/test/java/org/apache/tamaya/events/TestConfigView.java
----------------------------------------------------------------------
diff --git a/events/src/test/java/org/apache/tamaya/events/TestConfigView.java b/events/src/test/java/org/apache/tamaya/events/TestConfigView.java
new file mode 100644
index 0000000..8e5b397
--- /dev/null
+++ b/events/src/test/java/org/apache/tamaya/events/TestConfigView.java
@@ -0,0 +1,156 @@
+/*
+ * 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.ConfigOperator;
+import org.apache.tamaya.ConfigQuery;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.spi.ConfigurationContext;
+import org.apache.tamaya.spi.ConversionContext;
+import org.apache.tamaya.spi.PropertyConverter;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Created by Anatole on 24.03.2015.
+ */
+public class TestConfigView implements ConfigOperator{
+
+    private static final TestConfigView INSTANCE = new TestConfigView();
+
+    private TestConfigView(){}
+
+    public static ConfigOperator of(){
+        return INSTANCE;
+    }
+
+    @Override
+    public Configuration operate(final Configuration config) {
+        return new Configuration() {
+            @Override
+            public Map<String, String> getProperties() {
+                Map<String, String> result = new HashMap<>();
+                for (Map.Entry<String, String> en : config.getProperties().entrySet()) {
+                    if (en.getKey().startsWith("test")) {
+                        result.put(en.getKey(), en.getValue());
+                    }
+                }
+                return result;
+//                return config.getProperties().entrySet().stream().filter(e -> e.getKey().startsWith("test")).collect(
+//                        Collectors.toMap(en -> en.getKey(), en -> en.getValue()));
+            }
+
+            @Override
+            public Configuration with(ConfigOperator operator) {
+                return null;
+            }
+
+            @Override
+            public <T> T query(ConfigQuery<T> query) {
+                return null;
+            }
+
+            @Override
+            public ConfigurationContext getContext() {
+                return config.getContext();
+            }
+
+            @Override
+            public String get(String key) {
+                return getProperties().get(key);
+            }
+
+            @Override
+            public String getOrDefault(String key, String defaultValue) {
+                String val = get(key);
+                if(val==null){
+                    return defaultValue;
+                }
+                return val;
+            }
+
+            @Override
+            public <T> T getOrDefault(String key, Class<T> type, T defaultValue) {
+                T val = get(key, type);
+                if(val==null){
+                    return defaultValue;
+                }
+                return val;
+            }
+
+            @Override
+            public <T> T get(String key, Class<T> type) {
+                return (T) get(key, TypeLiteral.of(type));
+            }
+
+            /**
+             * Accesses the current String value for the given key and tries to convert it
+             * using the {@link org.apache.tamaya.spi.PropertyConverter} instances provided by the current
+             * {@link org.apache.tamaya.spi.ConfigurationContext}.
+             *
+             * @param key  the property's absolute, or relative path, e.g. @code
+             *             a/b/c/d.myProperty}.
+             * @param type The target type required, not null.
+             * @param <T>  the value type
+             * @return the converted value, never null.
+             */
+            @Override
+            public <T> T get(String key, TypeLiteral<T> type) {
+                String value = get(key);
+                if (value != null) {
+                    List<PropertyConverter<T>> converters = ConfigurationProvider.getConfigurationContext()
+                            .getPropertyConverters(type);
+                    ConversionContext context = new ConversionContext.Builder(
+                            key,type).build();
+                    for (PropertyConverter<T> converter : converters) {
+                        try {
+                            T t = converter.convert(value, context);
+                            if (t != null) {
+                                return t;
+                            }
+                        } catch (Exception e) {
+                            Logger.getLogger(getClass().getName())
+                                    .log(Level.FINEST, "PropertyConverter: " + converter + " failed to convert value: "
+                                            + value, e);
+                        }
+                    }
+                    throw new ConfigException("Unparseable config value for type: " + type.getRawType().getName() + ": "
+                            + key + ", supportedFormats: " + context.getSupportedFormats());
+                }
+                return null;
+            }
+
+            @Override
+            public <T> T getOrDefault(String key, TypeLiteral<T> type, T defaultValue) {
+                T val = get(key, type);
+                if(val==null){
+                    return defaultValue;
+                }
+                return val;
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/89223dcd/events/src/test/java/org/apache/tamaya/events/TestObservingProvider.java
----------------------------------------------------------------------
diff --git a/events/src/test/java/org/apache/tamaya/events/TestObservingProvider.java b/events/src/test/java/org/apache/tamaya/events/TestObservingProvider.java
new file mode 100644
index 0000000..2685d3e
--- /dev/null
+++ b/events/src/test/java/org/apache/tamaya/events/TestObservingProvider.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.events;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.tamaya.events.folderobserver.ObservingPropertySourceProvider;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Test configuration property source provider that observes a directory and updated the config if necessary.
+ */
+public class TestObservingProvider extends ObservingPropertySourceProvider{
+
+    public static Path propertyLocation;
+
+    static{
+        try {
+            // create some temporary config
+            Path tempDir = Files.createTempDirectory("observedFolder");
+
+            TestObservingProvider.propertyLocation = tempDir;
+
+            FileUtils.copyInputStreamToFile(
+                    TestObservingProvider.class.getResourceAsStream("/test.properties"),
+                    new File(tempDir.toFile(), "test.properties"));
+
+            Runtime.getRuntime().addShutdownHook(new Thread(){
+                @Override
+                public void run(){
+                    try{
+                        // cleanup directory
+                        Files.deleteIfExists(getTargetFile("test1.properties"));
+                        Files.deleteIfExists(getTargetFile("test2.properties"));
+                        Files.deleteIfExists(getTargetFile("test3.properties"));
+                    }
+                    catch(Exception e){
+                        Logger.getLogger("TestObservingProvider").log(Level.WARNING,
+                                "Failed to cleanup config test dir", e);
+                    }
+                }
+            });
+        }
+        catch(Exception e){
+            Logger.getLogger("TestObservingProvider").log(Level.WARNING, "Failed to init config test dir", e);
+        }
+    }
+
+    private static Path getTargetFile(String name) {
+        File testFile = new File(TestObservingProvider.getTestDirectory(), name);
+        return Paths.get(testFile.toURI());
+    }
+
+    public TestObservingProvider(){
+        super(propertyLocation);
+        Logger.getLogger(getClass().getName()).info("Using test directory: " + getTestPath());
+    }
+
+    public static File getTestDirectory(){
+        String tempDir = System.getProperty("java.io.tmpdir");
+        File dir = new File(tempDir, "tamaya-events-testdir");
+        if(!dir.exists()){
+            dir.mkdirs();
+        }
+        return dir;
+    }
+
+    private static String getTestPath(){
+        return getTestDirectory().getAbsolutePath();
+    }
+}


Mime
View raw message