Repository: incubator-tamaya-extensions Updated Branches: refs/heads/master 9d346676a -> 7505b0078
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/7505b007/modules/events/src/test/java/org/apache/tamaya/events/delta/ConfigurationContextChangeTest.java ---------------------------------------------------------------------- diff --git a/modules/events/src/test/java/org/apache/tamaya/events/delta/ConfigurationContextChangeTest.java b/modules/events/src/test/java/org/apache/tamaya/events/delta/ConfigurationContextChangeTest.java deleted file mode 100644 index ee631ce..0000000 --- a/modules/events/src/test/java/org/apache/tamaya/events/delta/ConfigurationContextChangeTest.java +++ /dev/null @@ -1,138 +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.ConfigurationProvider; -import org.apache.tamaya.core.propertysource.SystemPropertySource; -import org.apache.tamaya.events.ChangeType; -import org.apache.tamaya.events.ConfigurationContextChange; -import org.apache.tamaya.events.ConfigurationContextChangeBuilder; -import org.apache.tamaya.events.PropertySourceChangeBuilder; -import org.apache.tamaya.spi.PropertySource; -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Test class for {@link ConfigurationContextChange}. - */ -public class ConfigurationContextChangeTest { - - @Test - public void testEmptyChangeSet() throws Exception { - ConfigurationContextChange change = ConfigurationContextChange.emptyChangeSet( - ConfigurationProvider.getConfigurationContext()); - assertNotNull(change); - assertTrue(change.isEmpty()); - } - - @Test - public void testGetVersion() throws Exception { - Configuration config = ConfigurationProvider.getConfiguration(); - ConfigurationContextChange change = ConfigurationContextChangeBuilder.of().build(); - assertNotNull(change.getVersion()); - change = ConfigurationContextChangeBuilder.of().setVersion("version2").build(); - assertNotNull(change.getVersion()); - assertEquals("version2", change.getVersion()); - } - - @Test - public void testGetTimestamp() throws Exception { - Configuration config = ConfigurationProvider.getConfiguration(); - ConfigurationContextChange change = ConfigurationContextChangeBuilder.of().build(); - assertTrue((System.currentTimeMillis() - change.getTimestamp()) <= 10L); - change = ConfigurationContextChangeBuilder.of().setTimestamp(10L).build(); - assertEquals(10L, change.getTimestamp()); - } - - @Test - public void testGetPropertySourceChanges() throws Exception { - Configuration config = ConfigurationProvider.getConfiguration(); - ConfigurationContextChange change = ConfigurationContextChangeBuilder.of().build(); - assertTrue(change.getPropertySourceChanges(). isEmpty()); - change = ConfigurationContextChangeBuilder.of().build(); - assertTrue(change.getPropertySourceChanges(). isEmpty()); - } - - @Test - public void testGetPropertySourceUpdates() throws Exception { - Configuration config = ConfigurationProvider.getConfiguration(); - ConfigurationContextChange change = ConfigurationContextChangeBuilder.of().build(); - assertTrue(change.getPropertySourceChanges(). isEmpty()); - change = ConfigurationContextChangeBuilder.of().build(); - assertTrue(change.getPropertySourceUpdates(). isEmpty()); - } - - @Test - public void testGetRemovedPropertySources() throws Exception { - Configuration config = ConfigurationProvider.getConfiguration(); - ConfigurationContextChange change = ConfigurationContextChangeBuilder.of().build(); - assertTrue(change.getPropertySourceChanges(). isEmpty()); - change = ConfigurationContextChangeBuilder.of().build(); - assertTrue(change.getRemovedPropertySources(). isEmpty()); - } - - @Test - public void testGetAddedPropertySources() throws Exception { - Configuration config = ConfigurationProvider.getConfiguration(); - ConfigurationContextChange change = ConfigurationContextChangeBuilder.of().build(); - assertTrue(change.getPropertySourceChanges(). isEmpty()); - change = ConfigurationContextChangeBuilder.of().build(); - assertTrue(change.getAddedPropertySources().isEmpty()); - } - - @Test - public void testGetUpdatedPropertySources() throws Exception { - Configuration config = ConfigurationProvider.getConfiguration(); - ConfigurationContextChange change = ConfigurationContextChangeBuilder.of().build(); - assertTrue(change.getPropertySourceChanges(). isEmpty()); - change = ConfigurationContextChangeBuilder.of().build(); - assertTrue(change.getUpdatedPropertySources().isEmpty()); - } - - @Test - public void testIsAffected() throws Exception { - Configuration config = ConfigurationProvider.getConfiguration(); - PropertySource ps = new SystemPropertySource(); - ConfigurationContextChange change = ConfigurationContextChangeBuilder.of().changedPropertySource( - PropertySourceChangeBuilder.of(ps, ChangeType.UPDATED).build() - ).build(); - String toString = change.toString(); - assertTrue(change.isAffected(ps)); - } - - @Test - public void testIsEmpty() throws Exception { - Configuration config = ConfigurationProvider.getConfiguration(); - ConfigurationContextChange change = ConfigurationContextChangeBuilder.of().build(); - assertTrue(change.isEmpty()); - change = ConfigurationContextChangeBuilder.of().newPropertySource(new SystemPropertySource()).build(); - assertFalse(change.isEmpty()); - } - - @Test - public void testToString() throws Exception { - Configuration config = ConfigurationProvider.getConfiguration(); - ConfigurationContextChange change = ConfigurationContextChangeBuilder.of().newPropertySource(new SystemPropertySource()).build(); - String toString = change.toString(); - assertNotNull(toString); - assertTrue(toString.contains(new SystemPropertySource().getName())); - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/7505b007/modules/events/src/test/java/org/apache/tamaya/events/delta/PropertySourceChangeTest.java ---------------------------------------------------------------------- diff --git a/modules/events/src/test/java/org/apache/tamaya/events/delta/PropertySourceChangeTest.java b/modules/events/src/test/java/org/apache/tamaya/events/delta/PropertySourceChangeTest.java deleted file mode 100644 index 0dcdfba..0000000 --- a/modules/events/src/test/java/org/apache/tamaya/events/delta/PropertySourceChangeTest.java +++ /dev/null @@ -1,209 +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.core.propertysource.EnvironmentPropertySource; -import org.apache.tamaya.core.propertysource.SimplePropertySource; -import org.apache.tamaya.core.propertysource.SystemPropertySource; -import org.apache.tamaya.events.ChangeType; -import org.apache.tamaya.events.PropertySourceChange; -import org.apache.tamaya.events.PropertySourceChangeBuilder; -import org.apache.tamaya.spi.PropertySource; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; - -import static org.junit.Assert.*; - -/** - * Tests for {@link PropertySourceChange} and its builder. - */ -public class PropertySourceChangeTest { - - private static final PropertySource myPS = new SystemPropertySource(); - - @Test - public void testGetChangeType() throws Exception { - PropertySourceChange change = PropertySourceChangeBuilder.of(myPS, ChangeType.DELETED).build(); - assertEquals(change.getChangeType(), ChangeType.DELETED); - change = PropertySourceChangeBuilder.of(myPS, ChangeType.UPDATED).build(); - assertEquals(change.getChangeType(), ChangeType.UPDATED); - } - - @Test - public void testGetPropertySource() throws Exception { - PropertySourceChange change = PropertySourceChangeBuilder.of(myPS, ChangeType.DELETED).build(); - assertEquals(change.getResource().getName(), myPS.getName()); - } - - @Test - public void testGetVersion() throws Exception { - PropertySourceChange change = PropertySourceChangeBuilder.of(myPS, ChangeType.DELETED) - .setVersion("myVersion1").build(); - assertEquals(change.getVersion(), "myVersion1"); - } - - @Test - public void testGetTimestamp() throws Exception { - PropertySourceChange change = PropertySourceChangeBuilder.of(myPS, ChangeType.DELETED) - .setTimestamp(111L).build(); - assertEquals(change.getTimestamp(), 111L); - } - - @Test - public void testGetEvents() throws Exception { - PropertySourceChange change = PropertySourceChangeBuilder.of(myPS, ChangeType.DELETED) - .addChanges( - new EnvironmentPropertySource() - ).build(); - assertTrue(change.getChanges().size()>0); - } - - @Test - public void testGetRemovedSize() throws Exception { - PropertySourceChange change = PropertySourceChangeBuilder.of(myPS, ChangeType.UPDATED) - .addChanges( - new EnvironmentPropertySource() - ).build(); - assertTrue(change.getRemovedSize()>0); - } - - @Test - public void testGetAddedSize() throws Exception { - PropertySourceChange change = PropertySourceChangeBuilder.of(myPS, ChangeType.DELETED) - .addChanges( - new EnvironmentPropertySource() - ).build(); - assertTrue(change.getAddedSize()>0); - } - - @Test - public void testGetUpdatedSize() throws Exception { - PropertySourceChange change = PropertySourceChangeBuilder.of(myPS, ChangeType.DELETED) - .addChanges( - new EnvironmentPropertySource() - ).build(); - assertTrue(change.getUpdatedSize()==0); - } - - @Test - public void testIsRemoved() throws Exception { - Map<String, String> testData = new HashMap<>(); - testData.put("key1", "value1"); - testData.put("key2", "value2"); - PropertySource ps1 = new SimplePropertySource("test", testData); - testData = new HashMap<>(); - testData.put("key1", "value2"); - testData.put("key3", "value3"); - PropertySource ps2 = new SimplePropertySource("test", testData); - PropertySourceChange change = PropertySourceChangeBuilder.of(ps1, ChangeType.UPDATED) - .addChanges( - ps2 - ).build(); - assertFalse(change.isRemoved("key1")); - assertTrue(change.isRemoved("key2")); - assertFalse(change.isRemoved("key3")); - } - - @Test - public void testIsAdded() throws Exception { - Map<String, String> testData = new HashMap<>(); - testData.put("key1", "value1"); - testData.put("key2", "value2"); - PropertySource ps1 = new SimplePropertySource("test", testData); - testData = new HashMap<>(); - testData.put("key1", "value2"); - testData.put("key3", "value3"); - PropertySource ps2 = new SimplePropertySource("test", testData); - PropertySourceChange change = PropertySourceChangeBuilder.of(ps1, ChangeType.UPDATED) - .addChanges( - ps2 - ).build(); - assertTrue(change.isAdded("key3")); - assertFalse(change.isAdded("key2")); - assertFalse(change.isAdded("key1")); - } - - @Test - public void testIsUpdated() throws Exception { - Map<String, String> testData = new HashMap<>(); - testData.put("key1", "value1"); - testData.put("key2", "value2"); - PropertySource ps1 = new SimplePropertySource("test", testData); - testData = new HashMap<>(); - testData.put("key1", "value2"); - testData.put("key3", "value3"); - PropertySource ps2 = new SimplePropertySource("test", testData); - PropertySourceChange change = PropertySourceChangeBuilder.of(ps1, ChangeType.UPDATED) - .addChanges( - ps2 - ).build(); - assertTrue(change.isUpdated("key1")); - assertFalse(change.isUpdated("key2")); - assertFalse(change.isUpdated("key3")); - } - - @Test - public void testContainsKey() throws Exception { - PropertySourceChange change = PropertySourceChangeBuilder.of(new EnvironmentPropertySource(), ChangeType.DELETED) - .addChanges( - myPS - ).build(); - assertTrue(change.isKeyAffected("java.version")); - } - - @Test - public void testIsEmpty() throws Exception { - PropertySourceChange change = PropertySourceChangeBuilder.of(new EnvironmentPropertySource(), ChangeType.DELETED) - .build(); - assertTrue(change.isEmpty()); - change = PropertySourceChangeBuilder.of(new EnvironmentPropertySource(), ChangeType.DELETED) - .addChanges( - myPS - ).build(); - assertFalse(change.isEmpty()); - } - - @Test - public void testOfAdded() throws Exception { - PropertySourceChange change = PropertySourceChange.ofAdded(myPS); - assertNotNull(change); - assertEquals(change.getChangeType(), ChangeType.NEW); - } - - @Test - public void testOfDeleted() throws Exception { - PropertySourceChange change = PropertySourceChange.ofDeleted(myPS); - assertNotNull(change); - assertEquals(change.getChangeType(), ChangeType.DELETED); - } - - @Test - public void testToString() throws Exception { - PropertySourceChange change = PropertySourceChange.ofAdded(myPS); - String toString = change.toString(); - assertNotNull(toString); - assertTrue(toString.contains(myPS.getName())); - change = PropertySourceChange.ofDeleted(myPS); - toString = change.toString(); - assertNotNull(toString); - assertTrue(toString.contains(myPS.getName())); - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/7505b007/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/FileChangeListener.java ---------------------------------------------------------------------- diff --git a/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/FileChangeListener.java b/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/FileChangeListener.java new file mode 100644 index 0000000..283719e --- /dev/null +++ b/modules/events/src/test/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/7505b007/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/FileChangeObserver.java ---------------------------------------------------------------------- diff --git a/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/FileChangeObserver.java b/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/FileChangeObserver.java new file mode 100644 index 0000000..63d25cd --- /dev/null +++ b/modules/events/src/test/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/7505b007/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/ObservingPropertySourceProvider.java ---------------------------------------------------------------------- diff --git a/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/ObservingPropertySourceProvider.java b/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/ObservingPropertySourceProvider.java new file mode 100644 index 0000000..908c327 --- /dev/null +++ b/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/ObservingPropertySourceProvider.java @@ -0,0 +1,190 @@ +/* + * 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.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); + } + } + + @Override + public Collection<PropertySource> getPropertySources() { + synchronized (propertySources) { + return new ArrayList<>(this.propertySources); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/7505b007/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/TestObservingProvider.java ---------------------------------------------------------------------- diff --git a/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/TestObservingProvider.java b/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/TestObservingProvider.java new file mode 100644 index 0000000..b1e3962 --- /dev/null +++ b/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/TestObservingProvider.java @@ -0,0 +1,91 @@ +/* + * 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.commons.io.FileUtils; + +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(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/7505b007/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/package-info.java ---------------------------------------------------------------------- diff --git a/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/package-info.java b/modules/events/src/test/java/org/apache/tamaya/events/folderobserver/package-info.java new file mode 100644 index 0000000..347f2d8 --- /dev/null +++ b/modules/events/src/test/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/7505b007/modules/events/src/test/resources/META-INF/services/org.apache.tamaya.events.ConfigEventListener ---------------------------------------------------------------------- diff --git a/modules/events/src/test/resources/META-INF/services/org.apache.tamaya.events.ConfigEventListener b/modules/events/src/test/resources/META-INF/services/org.apache.tamaya.events.ConfigEventListener index f675fd6..d42210e 100644 --- a/modules/events/src/test/resources/META-INF/services/org.apache.tamaya.events.ConfigEventListener +++ b/modules/events/src/test/resources/META-INF/services/org.apache.tamaya.events.ConfigEventListener @@ -16,4 +16,4 @@ # specific language governing permissions and limitations # under the License. # -org.apache.tamaya.events.internal.DefaultConfigurationContextChangeListener \ No newline at end of file +org.apache.tamaya.events.ObservedConfigTest$MyConfigObserver \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/7505b007/modules/events/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySourceProvider ---------------------------------------------------------------------- diff --git a/modules/events/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySourceProvider b/modules/events/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySourceProvider index d34b4a2..6b3dc1d 100644 --- a/modules/events/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySourceProvider +++ b/modules/events/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertySourceProvider @@ -16,4 +16,4 @@ # specific language governing permissions and limitations # under the License. # -org.apache.tamaya.events.TestObservingProvider +org.apache.tamaya.events.folderobserver.TestObservingProvider
