TAMAYA-182: Streamlined/unified builder API and fixed some bugs popping up during testing.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/commit/3aca9112 Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/tree/3aca9112 Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/diff/3aca9112 Branch: refs/heads/master Commit: 3aca9112035e8b1ed70ecd739b03de15c32a3617 Parents: fe7cd8f Author: anatole <[email protected]> Authored: Sun Oct 30 22:59:21 2016 +0100 Committer: anatole <[email protected]> Committed: Sun Oct 30 22:59:21 2016 +0100 ---------------------------------------------------------------------- ...faultConfigurationContextChangeListener.java | 5 +- .../functions/ConfigurationFunctions.java | 5 + .../tamaya/functions/SimplePropertySource.java | 89 ++++ modules/mutable-config/pom.xml | 82 ++++ .../mutableconfig/ChangePropagationPolicy.java | 53 +++ .../mutableconfig/MutableConfiguration.java | 126 ++++++ .../MutableConfigurationProvider.java | 239 +++++++++++ .../internal/DefaultMutableConfiguration.java | 170 ++++++++ .../DefaultMutableConfigurationSpi.java | 38 ++ .../MutablePropertiesPropertySource.java | 196 +++++++++ .../MutableXmlPropertiesPropertySource.java | 198 +++++++++ .../mutableconfig/spi/ConfigChangeRequest.java | 176 ++++++++ .../spi/MutableConfigurationProviderSpi.java | 42 ++ .../spi/MutablePropertySource.java | 47 +++ ...leconfig.spi.MutableConfigurationProviderSpi | 19 + .../MutableConfigurationProviderTest.java | 84 ++++ .../mutableconfig/MutableConfigurationTest.java | 187 +++++++++ .../PropertiesFileConfigBackendTest.java | 29 ++ .../internal/WritablePropertiesSource.java | 49 +++ .../internal/WritableXmlPropertiesSource.java | 49 +++ .../org.apache.tamaya.spi.PropertySource | 20 + modules/spi-support/pom.xml | 6 +- .../tamaya/spisupport/CLIPropertySource.java | 101 +++++ .../tamaya/spisupport/DefaultConfiguration.java | 4 +- .../spisupport/DefaultConfigurationContext.java | 253 ++++++------ .../DefaultConfigurationContextBuilder.java | 410 +++++++++++++++++++ .../spisupport/EnvironmentPropertySource.java | 102 +++++ .../spisupport/PropertyConverterManager.java | 248 ++++++----- .../spisupport/PropertyFilterComparator.java | 60 +++ .../spisupport/PropertyFilterManager.java | 131 ++++++ .../tamaya/spisupport/SimplePropertySource.java | 151 +++++++ .../tamaya/spisupport/SystemPropertySource.java | 125 ++++++ .../java/org/apache/tamaya/spisupport/A.java | 29 ++ .../java/org/apache/tamaya/spisupport/B.java | 29 ++ .../spisupport/BasePropertySourceTest.java | 106 +++++ .../java/org/apache/tamaya/spisupport/C.java | 56 +++ .../spisupport/CLIPropertySourceTest.java | 59 +++ .../tamaya/spisupport/CTestConverter.java | 32 ++ .../DefaultConfigurationContextTest.java | 183 +++++++++ .../tamaya/spisupport/EnumConverterTest.java | 60 +++ .../EnvironmentPropertySourceTest.java | 67 +++ .../PriorityServiceComparatorTest.java | 45 ++ .../PropertiesFilePropertySourceTest.java | 60 +++ .../PropertyConverterManagerTest.java | 180 ++++++++ .../spisupport/SimplePropertySourceTest.java | 85 ++++ .../spisupport/SystemPropertySourceTest.java | 102 +++++ .../spisupport/TestPropertyDefaultSource.java | 56 +++ .../org.apache.tamaya.spi.PropertyConverter | 38 ++ .../src/test/resources/invalid-properties.xml | 25 ++ .../src/test/resources/non-xml-properties.xml | 18 + .../test/resources/overrideOrdinal.properties | 25 ++ .../src/test/resources/testfile.properties | 22 + .../src/test/resources/valid-properties.xml | 25 ++ 53 files changed, 4565 insertions(+), 231 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java ---------------------------------------------------------------------- diff --git a/modules/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java b/modules/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java index e49856d..8a9ff64 100644 --- a/modules/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java +++ b/modules/events/src/main/java/org/apache/tamaya/events/internal/DefaultConfigurationContextChangeListener.java @@ -56,10 +56,7 @@ public class DefaultConfigurationContextChangeListener implements ConfigEventLis .setContext(context); if (!affectedPropertySources.isEmpty()) { Set<String> propertySourceNames = new HashSet<>(); - for (PropertySource removed : contextChange.getRemovedPropertySources()) { - propertySourceNames.add(removed.getName()); - } - newContextBuilder.removePropertySources(propertySourceNames); + newContextBuilder.removePropertySources(contextChange.getRemovedPropertySources()); } newContextBuilder.addPropertySources(contextChange.getAddedPropertySources()); newContextBuilder.addPropertySources(contextChange.getUpdatedPropertySources()); http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java index 6dd0427..97934f6 100644 --- a/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java +++ b/modules/functions/src/main/java/org/apache/tamaya/functions/ConfigurationFunctions.java @@ -124,6 +124,11 @@ public final class ConfigurationFunctions { } @Override + public PropertySource getPropertySource(String name) { + return null; + } + + @Override public <T> void addPropertyConverter(TypeLiteral<T> typeToConvert, PropertyConverter<T> propertyConverter) { // ignore } http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/functions/src/main/java/org/apache/tamaya/functions/SimplePropertySource.java ---------------------------------------------------------------------- diff --git a/modules/functions/src/main/java/org/apache/tamaya/functions/SimplePropertySource.java b/modules/functions/src/main/java/org/apache/tamaya/functions/SimplePropertySource.java new file mode 100644 index 0000000..5dad7bb --- /dev/null +++ b/modules/functions/src/main/java/org/apache/tamaya/functions/SimplePropertySource.java @@ -0,0 +1,89 @@ +/* + * 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.functions; + +import org.apache.tamaya.spi.PropertySource; +import org.apache.tamaya.spi.PropertyValue; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** +* Simple property source implementation using a map. +*/ +public class SimplePropertySource implements PropertySource { + /** The properties. */ + private final Map<String, String> properties; + /** The source's name. */ + private final String name; + /** The default ordinal. */ + private int defaultOrdinal; + + public SimplePropertySource(String name, Map<String, String> properties){ + this.properties = new HashMap<>(properties); + this.name = Objects.requireNonNull(name); + } + + @Override + public int getOrdinal(){ + PropertyValue configuredOrdinal = get(TAMAYA_ORDINAL); + if(configuredOrdinal!=null){ + try{ + return Integer.parseInt(configuredOrdinal.getValue()); + } catch(Exception e){ + Logger.getLogger(getClass().getName()).log(Level.WARNING, + "Configured Ordinal is not an int number: " + configuredOrdinal, e); + } + } + return getDefaultOrdinal(); + } + + public int getDefaultOrdinal(){ + return defaultOrdinal; + } + + @Override + public String getName() { + return name; + } + + @Override + public PropertyValue get(String key) { + return PropertyValue.of(key, this.properties.get(key), + getName()); + } + + @Override + public Map<String, String> getProperties() { + return this.properties; + } + + @Override + public boolean isScannable() { + return false; + } + + @Override + public String toString(){ + return "SimplePropertySource(name="+name+", numProps="+properties.size()+")"; + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/pom.xml ---------------------------------------------------------------------- diff --git a/modules/mutable-config/pom.xml b/modules/mutable-config/pom.xml new file mode 100644 index 0000000..e9be993 --- /dev/null +++ b/modules/mutable-config/pom.xml @@ -0,0 +1,82 @@ +<!-- +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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-extensions</artifactId> + <version>0.3-incubating-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + <artifactId>tamaya-mutable-config</artifactId> + <name>Apache Tamaya Modules - Mutable Configuration</name> + <description>This module provides abstraction, if your scenario needs to actively change configuration entries + and write changes back to some property sources, files etc.</description> + <packaging>bundle</packaging> + + <properties> + <jdkVersion>1.7</jdkVersion> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.tamaya</groupId> + <artifactId>tamaya-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.tamaya.ext</groupId> + <artifactId>tamaya-spisupport</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.tamaya</groupId> + <artifactId>tamaya-core</artifactId> + <version>${project.version}</version> + <scope>runtime</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>java-hamcrest</artifactId> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Export-Package> + org.apache.tamaya.mutableconfig + </Export-Package> + </instructions> + </configuration> + </plugin> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ChangePropagationPolicy.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ChangePropagationPolicy.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ChangePropagationPolicy.java new file mode 100644 index 0000000..5378166 --- /dev/null +++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/ChangePropagationPolicy.java @@ -0,0 +1,53 @@ +/* + * 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.mutableconfig; + +import org.apache.tamaya.mutableconfig.spi.ConfigChangeRequest; +import org.apache.tamaya.spi.PropertySource; + +import java.util.Collection; + +/** + * Policy that defines how changes are applied to the available + * {@link org.apache.tamaya.mutableconfig.spi.MutablePropertySource} instances, e.g. + * <ul> + * <li><b>ALL: </b>Changes are propagated to all {@link org.apache.tamaya.mutableconfig.spi.MutablePropertySource} + * instances in order of significance. This means that a key added, updated or removed in each instance, if the key + * is writable/removable.</li> + * <li><b>SIGNIFICANT_ONLY: </b>A change (creation, update) is only applied, if + * <ol> + * <li>the value is not provided by a more significant read-only property source.</li> + * <li>there is no more significant writable property source, which supports writing a g iven key.</li> + * </ol> + * In other words a added or updated value is written exactly once to the most significant + * writable property source, which accepts a given key. Otherwise the change is discarded.</li> + * <li><b>NONE: </b>Do not apply any changes.</li> + * </ul> + */ +public interface ChangePropagationPolicy { + + /** + * Method being called when a multiple key/value pairs are added or updated. + * @param propertySources the property sources, including readable property sources of the current configuration, + * never null. + * @param configChange the configuration change, not null. + */ + void applyChange(ConfigChangeRequest configChange, Collection<PropertySource> propertySources); + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfiguration.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfiguration.java new file mode 100644 index 0000000..451769e --- /dev/null +++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfiguration.java @@ -0,0 +1,126 @@ +/* + * 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.mutableconfig; + +import org.apache.tamaya.Configuration; +import org.apache.tamaya.mutableconfig.spi.ConfigChangeRequest; + +import java.util.Collection; +import java.util.Map; + + +/** + * This interface extends the Configuration interface hereby adding methods to change configuration entries. + * Hereby not all configuration entries are necessarily mutable, since some entries may be read from non + * mutable areas of configuration. Of course, it is always possible to add a mutable shadow layer on top of all + * property sources to persist/control any changes applied. The exact management and storage persistence algorithm + * should be transparent. + * + * As a consequence clients should first check, using the corresponding methods, if entries can be added/updated or + * removed. + * + * This class should only used in a single threaded context, though all methods inherited from {@link Configuration} + * must be thread-safe. Methods handling configuration changes are expected to be used in a single threaded environment + * only. For multi-threaded us create a new instance of {@link MutableConfiguration} for each thread. + */ +public interface MutableConfiguration extends Configuration { + + /** + * Storesd the changes. After a commit the change is not editable anymore. All changes applied will be written to + * the corresponding configuration backend. + * + * NOTE that changes applied must not necessarily be visible in the current {@link Configuration} instance, + * since visibility of changes also depends on the ordinals set on the {@link org.apache.tamaya.spi.PropertySource}s + * configured. + * @throws org.apache.tamaya.ConfigException if the request already has been committed or cancelled, or the commit fails. + */ + void store(); + + /** + * Access the current configuration change context, built up on all the change context of the participating + * {@link org.apache.tamaya.mutableconfig.spi.MutablePropertySource} instances. + * @return the colleted changes as one single config change for the current transaction, or null, if no transaction + * is active. + */ + ConfigChangeRequest getConfigChangeRequest(); + + /** + * Access the active {@link ChangePropagationPolicy}.This policy controls how configuration changes are written/published + * to the known {@link org.apache.tamaya.mutableconfig.spi.MutablePropertySource} instances of a {@link Configuration}. + * @return he active {@link ChangePropagationPolicy}, never null. + */ + ChangePropagationPolicy getChangePropagationPolicy(); + + /** + * Sets a property. + * + * @param key the property's key, not null. + * @param value the property's value, not null. + * @return the former property value, or null. + * @throws org.apache.tamaya.ConfigException if the key/value cannot be added, or the request is read-only. + */ + MutableConfiguration put(String key, String value); + + /** + * Puts all given configuration entries. This method should check that all given properties are + * basically removable, as defined by #isWritable. If any of the passed keys is not writable during this initial + * check, the operation should not perform any configuration changes and throw a + * {@link org.apache.tamaya.ConfigException}. If errors occur afterwards, when the properties are effectively + * written back to the backends, the errors should be collected and returned as part of the ConfigException + * payload. Nevertheless the operation should in that case remove all entries as far as possible and abort the + * writing operation. + * + * @param properties the properties tobe written, not null. + * @return the config change request + * @throws org.apache.tamaya.ConfigException if any of the given properties could not be written, or the request + * is read-only. + */ + MutableConfiguration putAll(Map<String, String> properties); + + /** + * Removes all given configuration entries. This method should check that all given properties are + * basically removable, as defined by #isRemovable. If any of the passed keys is not removable during this initial + * check, the operation should not perform any configuration changes and throw a + * {@link org.apache.tamaya.ConfigException}. If errors + * occur afterwards, when the properties are effectively written back to the backends, the errors should be + * collected and returned as part of the ConfigException payload. Nevertheless the operation should in that case + * remove all entries as far as possible and abort the writing operation. + * + * @param keys the property's keys to be removedProperties, not null. + * @return the config change request + * @throws org.apache.tamaya.ConfigException if any of the given keys could not be removedProperties, or the + * request is read-only. + */ + MutableConfiguration remove(Collection<String> keys); + + /** + * Removes all given configuration entries. This method should check that all given properties are + * basically removable, as defined by #isRemovable. If any of the passed keys is not removable during this initial + * check, the operation should not perform any configuration changes and throw a {@link org.apache.tamaya.ConfigException}. If errors + * occur afterwards, when the properties are effectively written back to the backends, the errors should be + * collected and returned as part of the ConfigException payload. Nevertheless the operation should in that case + * remove all entries as far as possible and abort the writing operation. + * + * @param keys the property's keys to be removedProperties, not null. + * @return the config change request + * @throws org.apache.tamaya.ConfigException if any of the given keys could not be removedProperties, or the request is read-only. + */ + MutableConfiguration remove(String... keys); + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfigurationProvider.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfigurationProvider.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfigurationProvider.java new file mode 100644 index 0000000..c2cd20e --- /dev/null +++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/MutableConfigurationProvider.java @@ -0,0 +1,239 @@ +/* + * 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.mutableconfig; + +import org.apache.tamaya.ConfigException; +import org.apache.tamaya.Configuration; +import org.apache.tamaya.ConfigurationProvider; +import org.apache.tamaya.mutableconfig.spi.ConfigChangeRequest; +import org.apache.tamaya.mutableconfig.spi.MutableConfigurationProviderSpi; +import org.apache.tamaya.mutableconfig.spi.MutablePropertySource; +import org.apache.tamaya.spi.PropertySource; +import org.apache.tamaya.spi.ServiceContextManager; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Logger; + + +/** + * Accessor for creating {@link MutableConfiguration} instances to change configuration and commit changes. + */ +public final class MutableConfigurationProvider { + + private static final Logger LOG = Logger.getLogger(MutableConfigurationProvider.class.getName()); + /** + * URIs used by this query instance to identify the backends to use for write operations. + */ + private static MutableConfigurationProviderSpi mutableConfigurationProviderSpi = loadSpi(); + + /** + * SPI loader method. + * @throws ConfigException if loading fails. + * @return the SPI, never null. + */ + private static MutableConfigurationProviderSpi loadSpi() { + try{ + return ServiceContextManager.getServiceContext().getService( + MutableConfigurationProviderSpi.class) ; + } catch(Exception e){ + throw new ConfigException("Failed to initialize MutableConfigurationProviderSpi - " + + "mutable configuration support."); + } + } + + + /** Singleton constructor. */ + private MutableConfigurationProvider(){} + + /** + * Creates a new {@link MutableConfiguration} for the given default configuration, using all + * {@link MutablePropertySource} instances found in its context and {@code autoCommit = false}. + * + * @return a new MutableConfiguration instance + */ + public static MutableConfiguration createMutableConfiguration(){ + return mutableConfigurationProviderSpi.createMutableConfiguration( + ConfigurationProvider.getConfiguration(), getApplyMostSignificantOnlyChangePolicy()); + } + + /** + * Creates a new {@link MutableConfiguration} for the given default configuration, using all + * {@link MutablePropertySource} instances found in its context and {@code autoCommit = false}. + * @param changePropgationPolicy policy that defines how a change is written back and which property + * sources are finally eligible for a write operation. + * @return a new MutableConfiguration instance, with the given change policy active. + */ + public static MutableConfiguration createMutableConfiguration(ChangePropagationPolicy changePropgationPolicy){ + return mutableConfigurationProviderSpi.createMutableConfiguration( + ConfigurationProvider.getConfiguration(), changePropgationPolicy); + } + + + /** + * Creates a new {@link MutableConfiguration} for the given configuration, using all + * {@link MutablePropertySource} instances found in its context and {@code MOST_SIGNIFICANT_ONLY_POLICY} + * configuration writing policy. + * + * @param configuration the configuration to use to write the changes/config. + * @return a new MutableConfiguration instance + */ + public static MutableConfiguration createMutableConfiguration(Configuration configuration){ + return createMutableConfiguration(configuration, MOST_SIGNIFICANT_ONLY_POLICY); + } + + /** + * Creates a new {@link MutableConfiguration} for the given configuration, using all + * {@link MutablePropertySource} instances found in its context and {@code ALL_POLICY} + * configuration writing policy. + * + * @param configuration the configuration to use to write the changes/config. + * @param changePropagationPolicy the configuration writing policy. + * @return a new MutableConfiguration instance + */ + public static MutableConfiguration createMutableConfiguration(Configuration configuration, ChangePropagationPolicy changePropagationPolicy){ + return mutableConfigurationProviderSpi.createMutableConfiguration(configuration, changePropagationPolicy); + } + + /** + * This propagation policy writes through all changes to all mutable property sources, where applicable. + * This is also the default policy. + * @return default all policy. + */ + public static ChangePropagationPolicy getApplyAllChangePolicy(){ + return ALL_POLICY; + } + + /** + * This propagation policy writes changes only once to the most significant property source, where a change is + * applicable. + * @return a corresponding {@link ChangePropagationPolicy} implementation, never null. + */ + public static ChangePropagationPolicy getApplyMostSignificantOnlyChangePolicy(){ + return MOST_SIGNIFICANT_ONLY_POLICY; + } + + /** + * This propagation policy writes changes only once to the most significant property source, where a change is + * applicable. + * @param propertySourceNames the names of the mutable property sources to be considered for writing any changes to. + * @return a corresponding {@link ChangePropagationPolicy} implementation, never null. + */ + public static ChangePropagationPolicy getApplySelectiveChangePolicy(String... propertySourceNames){ + return new SelectiveChangeApplyPolicy(propertySourceNames); + } + + /** + * This propagation policy writes changes only once to the most significant property source, where a change is + * applicable. + * @return a corresponding {@link ChangePropagationPolicy} implementation, never null. + */ + public static ChangePropagationPolicy getApplyNonePolicy(){ + return NONE_POLICY; + } + + /** + * This propagation policy writes through all changes to all mutable property sources, where applicable. + */ + private static final ChangePropagationPolicy ALL_POLICY = new ChangePropagationPolicy() { + @Override + public void applyChange(ConfigChangeRequest change, Collection<PropertySource> propertySources) { + for(PropertySource propertySource: propertySources){ + if(propertySource instanceof MutablePropertySource){ + MutablePropertySource target = (MutablePropertySource)propertySource; + try{ + target.applyChange(change); + }catch(ConfigException e){ + LOG.warning("Failed to store changes '"+change+"' not applicable to "+target.getName() + +"("+target.getClass().getName()+")."); + } + } + } + } + + }; + + /** + * This propagation policy writes changes only once to the most significant property source, where a change is + * applicable. + */ + private static final ChangePropagationPolicy MOST_SIGNIFICANT_ONLY_POLICY = new ChangePropagationPolicy() { + @Override + public void applyChange(ConfigChangeRequest change, Collection<PropertySource> propertySources) { + for(PropertySource propertySource: propertySources){ + if(propertySource instanceof MutablePropertySource){ + MutablePropertySource target = (MutablePropertySource)propertySource; + try{ + target.applyChange(change); + }catch(ConfigException e){ + LOG.warning("Failed to store changes '"+change+"' not applicable to "+target.getName() + +"("+target.getClass().getName()+")."); + } + break; + } + } + } + + }; + + /** + * This propagation policy writes changes only once to the most significant property source, where a change is + * applicable. + */ + private static final ChangePropagationPolicy NONE_POLICY = new ChangePropagationPolicy() { + @Override + public void applyChange(ConfigChangeRequest change, Collection<PropertySource> propertySources) { + LOG.warning("Cannot store changes '"+change+"': prohibited by change policy (read-only)."); + } + }; + + /** + * This propagation policy writes through all changes to all mutable property sources, where applicable. + */ + private static final class SelectiveChangeApplyPolicy implements ChangePropagationPolicy { + + private Set<String> propertySourceNames = new HashSet<>(); + + SelectiveChangeApplyPolicy(String... propertySourceNames){ + this.propertySourceNames.addAll(Arrays.asList(propertySourceNames)); + } + + @Override + public void applyChange(ConfigChangeRequest change, Collection<PropertySource> propertySources) { + for(PropertySource propertySource: propertySources){ + if(propertySource instanceof MutablePropertySource){ + if(this.propertySourceNames.contains(propertySource.getName())) { + MutablePropertySource target = (MutablePropertySource) propertySource; + try{ + target.applyChange(change); + }catch(ConfigException e){ + LOG.warning("Failed to store changes '"+change+"' not applicable to "+target.getName() + +"("+target.getClass().getName()+")."); + } + break; + } + } + } + } + }; + + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfiguration.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfiguration.java new file mode 100644 index 0000000..ad272ef --- /dev/null +++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfiguration.java @@ -0,0 +1,170 @@ +/* + * 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.mutableconfig.internal; + +import org.apache.tamaya.ConfigOperator; +import org.apache.tamaya.ConfigQuery; +import org.apache.tamaya.Configuration; +import org.apache.tamaya.TypeLiteral; +import org.apache.tamaya.mutableconfig.ChangePropagationPolicy; +import org.apache.tamaya.mutableconfig.MutableConfiguration; +import org.apache.tamaya.mutableconfig.spi.ConfigChangeRequest; +import org.apache.tamaya.mutableconfig.spi.MutablePropertySource; +import org.apache.tamaya.spi.ConfigurationContext; +import org.apache.tamaya.spi.PropertySource; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.logging.Logger; + + +/** + * Default implementation of a {@link MutableConfiguration}. + */ +public class DefaultMutableConfiguration implements MutableConfiguration { + private static final Logger LOG = Logger.getLogger(DefaultMutableConfiguration.class.getName()); + private ConfigChangeRequest changeRequest = new ConfigChangeRequest(UUID.randomUUID().toString()); + private final Configuration config; + private ChangePropagationPolicy changePropagationPolicy; + + public DefaultMutableConfiguration(Configuration config, ChangePropagationPolicy changePropagationPolicy){ + this.config = Objects.requireNonNull(config); + this.changePropagationPolicy = Objects.requireNonNull(changePropagationPolicy); + } + + @Override + public ChangePropagationPolicy getChangePropagationPolicy(){ + return changePropagationPolicy; + } + + @Override + public ConfigChangeRequest getConfigChangeRequest(){ + return changeRequest; + } + + protected List<MutablePropertySource> getMutablePropertySources() { + List<MutablePropertySource> result = new ArrayList<>(); + for(PropertySource propertySource:this.config.getContext().getPropertySources()) { + if(propertySource instanceof MutablePropertySource){ + result.add((MutablePropertySource)propertySource); + } + } + return result; + } + + + @Override + public MutableConfiguration put(String key, String value) { + changeRequest.put(key, value); + return this; + } + + @Override + public MutableConfiguration putAll(Map<String, String> properties) { + changeRequest.putAll(properties); + return this; + } + + @Override + public MutableConfiguration remove(String... keys) { + changeRequest.removeAll(Arrays.asList(keys)); + return this; + } + + + @Override + public void store() { + this.changePropagationPolicy.applyChange(changeRequest, config.getContext().getPropertySources()); + } + + @Override + public MutableConfiguration remove(Collection<String> keys) { + for(MutablePropertySource target:getMutablePropertySources()) { + changeRequest.removeAll(keys); + } + return this; + } + + @Override + public String get(String key) { + return this.config.get(key); + } + + @Override + public String getOrDefault(String key, String defaultValue) { + return this.config.getOrDefault(key, defaultValue); + } + + @Override + public <T> T getOrDefault(String key, Class<T> type, T defaultValue) { + return this.config.getOrDefault(key, type, defaultValue); + } + + @Override + public <T> T get(String key, Class<T> type) { + return this.config.get(key, type); + } + + @Override + public <T> T get(String key, TypeLiteral<T> type) { + return this.config.get(key, type); + } + + @Override + public <T> T getOrDefault(String key, TypeLiteral<T> type, T defaultValue) { + return this.config.getOrDefault(key, type, defaultValue); + } + + @Override + public Map<String, String> getProperties() { + return this.config.getProperties(); + } + + @Override + public Configuration with(ConfigOperator operator) { + return operator.operate(this); + } + + @Override + public <T> T query(ConfigQuery<T> query) { + return query.query(this); + } + + @Override + public ConfigurationContext getContext() { + return config.getContext(); + } + + private Collection<PropertySource> getPropertySources() { + return this.config.getContext().getPropertySources(); + } + + @Override + public String toString() { + return "DefaultMutableConfiguration{" + + "config=" + config + + '}'; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfigurationSpi.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfigurationSpi.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfigurationSpi.java new file mode 100644 index 0000000..a47cd0e --- /dev/null +++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/internal/DefaultMutableConfigurationSpi.java @@ -0,0 +1,38 @@ +/* + * 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.mutableconfig.internal; + +import org.apache.tamaya.Configuration; +import org.apache.tamaya.mutableconfig.ChangePropagationPolicy; +import org.apache.tamaya.mutableconfig.MutableConfiguration; +import org.apache.tamaya.mutableconfig.spi.MutableConfigurationProviderSpi; + + +/** + * SPI implementation that creates instances of {@link DefaultMutableConfiguration}, hereby for + * each instance of {@link Configuration} a new instance has to be returned. + */ +public class DefaultMutableConfigurationSpi implements MutableConfigurationProviderSpi { + + @Override + public MutableConfiguration createMutableConfiguration(Configuration configuration, + ChangePropagationPolicy propagationPolicy){ + return new DefaultMutableConfiguration(configuration, propagationPolicy); + } +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutablePropertiesPropertySource.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutablePropertiesPropertySource.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutablePropertiesPropertySource.java new file mode 100644 index 0000000..af9bed4 --- /dev/null +++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutablePropertiesPropertySource.java @@ -0,0 +1,196 @@ +/* + * 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.mutableconfig.propertysources; + +import org.apache.tamaya.ConfigException; +import org.apache.tamaya.mutableconfig.spi.ConfigChangeRequest; +import org.apache.tamaya.mutableconfig.spi.MutablePropertySource; +import org.apache.tamaya.spi.PropertyValue; +import org.apache.tamaya.spi.PropertyValueBuilder; +import org.apache.tamaya.spisupport.BasePropertySource; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Simple implementation of a mutable {@link org.apache.tamaya.spi.PropertySource} for .properties files. + */ +public class MutablePropertiesPropertySource extends BasePropertySource +implements MutablePropertySource{ + + /** + * The logger. + */ + private static final Logger LOG = Logger.getLogger(MutablePropertiesPropertySource.class.getName()); + + /** + * Default update interval is 1 minute. + */ + private static final long DEFAULT_UPDATE_INTERVAL = 60000L; + + /** + * The property source name. + */ + private String name; + + /** + * The configuration resource's URL. + */ + private File file; + + /** + * Timestamp of last read. + */ + private long lastRead; + + /** + * Interval, when the resource should try to update its contents. + */ + private long updateInterval = DEFAULT_UPDATE_INTERVAL; + /** + * The current properties. + */ + private Map<String, String> properties = new HashMap<>(); + + /** + * Creates a new Properties based PropertySource based on the given URL. + * + * @param propertiesLocation the URL encoded location, not null. + * @param defaultOrdinal the default ordinal to be used, when no ordinal is provided with the property + * source's properties. + */ + public MutablePropertiesPropertySource(File propertiesLocation, int defaultOrdinal) { + super(defaultOrdinal); + this.name = propertiesLocation.toString(); + try { + this.file = propertiesLocation; + load(); + } catch (Exception e) { + LOG.log(Level.SEVERE, "Cannot convert file to URL: " + propertiesLocation, e); + } + } + + @Override + public PropertyValue get(String key) { + Map<String,String> properties = getProperties(); + String val = properties.get(key); + if(val==null){ + return null; + } + PropertyValueBuilder b = new PropertyValueBuilder(key, val, getName()); + String metaKeyStart = "_" + key + "."; + for(Map.Entry<String,String> en:properties.entrySet()) { + if(en.getKey().startsWith(metaKeyStart)){ + b.addContextData(en.getKey().substring(metaKeyStart.length()), en.getValue()); + } + } + return b.build(); + } + + @Override + public String getName() { + return name; + } + + @Override + public Map<String, String> getProperties() { + checkLoad(); + return Collections.unmodifiableMap(this.properties); + } + + + private void checkLoad() { + if(file!=null && (lastRead+updateInterval)<System.currentTimeMillis()){ + load(); + } + } + + /** + * loads the Properties from the given URL + * + * @throws IllegalStateException in case of an error while reading properties-file + */ + private void load() { + try (InputStream stream = new FileInputStream(file)) { + Map<String, String> properties = new HashMap<>(); + Properties props = new Properties(); + props.load(stream); + for (String key : props.stringPropertyNames()) { + properties.put(key, props.getProperty(key)); + } + this.lastRead = System.currentTimeMillis(); + LOG.log(Level.FINEST, "Loaded properties from " + file); + this.properties = properties; + } catch (IOException e) { + LOG.log(Level.FINEST, "Cannot load properties from " + file, e); + } + } + + @Override + public void applyChange(ConfigChangeRequest change) { + if(change.isEmpty()){ + LOG.info("Nothing to commit for transaction: " + change.getTransactionID()); + return; + } + if(!file.exists()){ + try { + if(!file.createNewFile()){ + throw new ConfigException("Failed to create config file " + file); + } + } catch (IOException e) { + throw new ConfigException("Failed to create config file " + file, e); + } + } + for(Map.Entry<String,String> en:change.getAddedProperties().entrySet()){ + int index = en.getKey().indexOf('?'); + if(index>0){ + this.properties.put(en.getKey().substring(0, index), en.getValue()); + }else{ + this.properties.put(en.getKey(), en.getValue()); + } + } + for(String rmKey:change.getRemovedProperties()){ + this.properties.remove(rmKey); + } + try(BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))){ + Properties props = new Properties(); + for (Map.Entry<String,String> en : this.properties.entrySet()) { + props.setProperty(en.getKey(), en.getValue()); + } + props.store(bos, "Properties written from Tamaya on " + new Date()); + bos.flush(); + } + catch(Exception e){ + throw new ConfigException("Failed to write config to " + file, e); + } + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutableXmlPropertiesPropertySource.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutableXmlPropertiesPropertySource.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutableXmlPropertiesPropertySource.java new file mode 100644 index 0000000..514ed1d --- /dev/null +++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/propertysources/MutableXmlPropertiesPropertySource.java @@ -0,0 +1,198 @@ +/* + * 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.mutableconfig.propertysources; + +import org.apache.tamaya.ConfigException; +import org.apache.tamaya.mutableconfig.spi.ConfigChangeRequest; +import org.apache.tamaya.mutableconfig.spi.MutablePropertySource; +import org.apache.tamaya.spi.PropertyValue; +import org.apache.tamaya.spi.PropertyValueBuilder; +import org.apache.tamaya.spisupport.BasePropertySource; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Simple implementation of a mutable {@link org.apache.tamaya.spi.PropertySource} for .xml properties files. + */ +public class MutableXmlPropertiesPropertySource extends BasePropertySource +implements MutablePropertySource{ + + /** + * The logger. + */ + private static final Logger LOG = Logger.getLogger(MutableXmlPropertiesPropertySource.class.getName()); + /** + * Default update interval is 1 minute. + */ + private static final long DEFAULT_UPDATE_INTERVAL = 60000L; + + /** + * The property source name. + */ + private String name; + + /** + * The configuration resource's URL. + */ + private File file; + + /** + * Timestamp of last read. + */ + private long lastRead; + + /** + * Interval, when the resource should try to update its contents. + */ + private long updateInterval = DEFAULT_UPDATE_INTERVAL; + /** + * The current properties. + */ + private Map<String, String> properties = new HashMap<>(); + + /** + * Creates a new Properties based PropertySource based on the given URL. + * + * @param propertiesLocation the URL encoded location, not null. + * @param defaultOrdinal the default ordinal to be used, when no ordinal is provided with the property + * source's properties. + */ + public MutableXmlPropertiesPropertySource(File propertiesLocation, int defaultOrdinal) { + super(defaultOrdinal); + this.name = propertiesLocation.toString(); + try { + this.file = propertiesLocation; + load(); + } catch (Exception e) { + LOG.log(Level.SEVERE, "Cannot convert file to URL: " + propertiesLocation, e); + } + } + + + + @Override + public PropertyValue get(String key) { + Map<String,String> properties = getProperties(); + String val = properties.get(key); + if(val==null){ + return null; + } + PropertyValueBuilder b = new PropertyValueBuilder(key, val, getName()); + String metaKeyStart = "_" + key + "."; + for(Map.Entry<String,String> en:properties.entrySet()) { + if(en.getKey().startsWith(metaKeyStart)){ + b.addContextData(en.getKey().substring(metaKeyStart.length()), en.getValue()); + } + } + return b.build(); + } + + @Override + public String getName() { + return name; + } + + @Override + public Map<String, String> getProperties() { + checkLoad(); + return Collections.unmodifiableMap(this.properties); + } + + + private void checkLoad() { + if(file!=null && (lastRead+updateInterval)<System.currentTimeMillis()){ + load(); + } + } + + /** + * loads the Properties from the given URL + * + * @throws IllegalStateException in case of an error while reading properties-file + */ + private void load() { + try (InputStream stream = new FileInputStream(file)) { + Map<String, String> properties = new HashMap<>(); + Properties props = new Properties(); + props.loadFromXML(stream); + for (String key : props.stringPropertyNames()) { + properties.put(key, props.getProperty(key)); + } + this.lastRead = System.currentTimeMillis(); + this.properties = properties; + LOG.log(Level.FINEST, "Loaded properties from " + file); + this.properties = properties; + } catch (IOException e) { + LOG.log(Level.FINEST, "Cannot load properties from " + file, e); + } + } + + @Override + public void applyChange(ConfigChangeRequest configChange) { + if(configChange.isEmpty()){ + LOG.info("Nothing to commit for transaction: " + configChange.getTransactionID()); + return; + } + if(!file.exists()){ + try { + if(!file.createNewFile()){ + throw new ConfigException("Failed to create config file " + file); + } + } catch (IOException e) { + throw new ConfigException("Failed to create config file " + file, e); + } + } + for(Map.Entry<String,String> en:configChange.getAddedProperties().entrySet()){ + int index = en.getKey().indexOf('?'); + if(index>0){ + this.properties.put(en.getKey().substring(0, index), en.getValue()); + }else{ + this.properties.put(en.getKey(), en.getValue()); + } + } + for(String rmKey:configChange.getRemovedProperties()){ + this.properties.remove(rmKey); + } + try(BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))){ + Properties props = new Properties(); + for (Map.Entry<String,String> en : this.properties.entrySet()) { + props.setProperty(en.getKey(), en.getValue()); + } + props.storeToXML(bos, "Properties written from Tamaya on " + new Date()); + bos.flush(); + } + catch(Exception e){ + throw new ConfigException("Failed to write config to " + file, e); + } + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/ConfigChangeRequest.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/ConfigChangeRequest.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/ConfigChangeRequest.java new file mode 100644 index 0000000..2349ad1 --- /dev/null +++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/ConfigChangeRequest.java @@ -0,0 +1,176 @@ +/* + * 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.mutableconfig.spi; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * Change context used for managing configuration changes within an + * {@link org.apache.tamaya.mutableconfig.spi.MutablePropertySource}. + */ +public final class ConfigChangeRequest { + /** + * The transaction id. + */ + private String transactionId; + /** + * The starting point. + */ + private long startedAt = System.currentTimeMillis(); + /** + * The Properties. + */ + private final Map<String,String> addedProperties = new HashMap<>(); + /** + * The Removed. + */ + private final Set<String> removedProperties = new HashSet<>(); + + /** + * Creates a new instance bound to the given transaction. + * @param transactionID the transaction ID, not null. + */ + public ConfigChangeRequest(String transactionID){ + this.transactionId = Objects.requireNonNull(transactionID); + } + + /** + * Sets the started at value. By default {@link #startedAt} is already set on instance creation to + * {@code System.currentTimeMillis()}. + * @param startedAt the new UTC POSIX timestamp in millis. + */ + public void setStartedAt(long startedAt) { + this.startedAt = startedAt; + } + + /** + * Get the corresppnding transaction ID of this instance. + * @return the transaction ID, never null. + */ + public String getTransactionID(){ + return transactionId; + } + + /** + * Timestamp in UTC millis, when this transaction (context) was created. + * @return the timestamp in millis. + */ + public long getStartedAt(){ + return startedAt; + } + + /** + * Get an unmodifiable key/value map of properties added or updated. + * @return an unmodifiable key/value map of properties added or updated, never null. + */ + public Map<String,String> getAddedProperties(){ + return Collections.unmodifiableMap(addedProperties); + } + + /** + * Get an unmodifiable key set of properties removed. + * @return an unmodifiable key set of properties removed, never null. + */ + public Set<String> getRemovedProperties(){ + return Collections.unmodifiableSet(removedProperties); + } + + /** + * Adds/updates a new key/value pair. + * @param key the key, not null. + * @param value the value, not null. + */ + public void put(String key, String value) { + this.addedProperties.put(key, value); + this.removedProperties.remove(key); + } + + /** + * Add/updated multiple key/values. + * @param properties the keys and values to be added/updated, not null. + */ + public void putAll(Map<String, String> properties) { + this.addedProperties.putAll(properties); + this.removedProperties.removeAll(properties.keySet()); + } + + /** + * Remove all the given keys, ir present. + * @param key the key to be removed, not null. + */ + public void remove(String key) { + this.removedProperties.add(key); + this.addedProperties.remove(key); + } + + /** + * Remove all the given keys, ir present. + * @param keys the keys to be removed, not null. + */ + public void removeAll(Collection<String> keys) { + this.removedProperties.addAll(keys); + for(String k:keys) { + this.addedProperties.remove(k); + } + } + + /** + * Allows easily to check if no additions/changes an no removals are present in the current transaction. + * @return true, if not actions have to be committed. + */ + public boolean isEmpty() { + return this.addedProperties.isEmpty() && this.removedProperties.isEmpty(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ConfigChangeRequest)) { + return false; + } + ConfigChangeRequest that = (ConfigChangeRequest) o; + return transactionId.equals(that.transactionId); + + } + + @Override + public int hashCode() { + return transactionId.hashCode(); + } + + @Override + public String toString() { + return "ConfigChangeRequest{" + + "transactionId=" + transactionId + + ", startedAt=" + startedAt + + ", addedProperties=" + addedProperties + + ", removedProperties=" + removedProperties + + '}'; + } + + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutableConfigurationProviderSpi.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutableConfigurationProviderSpi.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutableConfigurationProviderSpi.java new file mode 100644 index 0000000..4412085 --- /dev/null +++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutableConfigurationProviderSpi.java @@ -0,0 +1,42 @@ +/* + * 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.mutableconfig.spi; + +import org.apache.tamaya.Configuration; +import org.apache.tamaya.mutableconfig.ChangePropagationPolicy; +import org.apache.tamaya.mutableconfig.MutableConfiguration; + + +/** + * Provider SPI used by {@link org.apache.tamaya.mutableconfig.MutableConfigurationProvider}. Providers may override + * other providers registering with a higher {@link javax.annotation.Priority} value annotated. + */ +public interface MutableConfigurationProviderSpi { + + /** + * Creates a new {@link MutableConfiguration} with {@code autoCommit = false} as default. + * + * @param configuration the configuration, not null. + * @param propagationPolicy policy that defines how changes are published to the property + * sources. + * @return a new mutable configuration instance. + */ + MutableConfiguration createMutableConfiguration(Configuration configuration, + ChangePropagationPolicy propagationPolicy); +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutablePropertySource.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutablePropertySource.java b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutablePropertySource.java new file mode 100644 index 0000000..b648341 --- /dev/null +++ b/modules/mutable-config/src/main/java/org/apache/tamaya/mutableconfig/spi/MutablePropertySource.java @@ -0,0 +1,47 @@ +/* + * 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.mutableconfig.spi; + +import org.apache.tamaya.spi.PropertySource; + + +/** + * This interface models a writable backend for configuration data. + * + * As a consequence clients should first check, using the corresponding methods, if entries are to edited or removedProperties + * actually are eligible for change/creation or removal. + */ +public interface MutablePropertySource extends PropertySource { + + /** + * Puts all given configuration entries. This method should check that all given properties are + * basically removable, as defined by #isWritable. If any of the passed keys is not writable during this initial + * check, the operation should not perform any configuration changes and throw a {@link org.apache.tamaya.ConfigException}. If errors + * occur afterwards, when the properties are effectively written back to the backends, the errors should be + * collected and returned as part of the ConfigException payload. Nevertheless the operation should in that case + * remove all entries as far as possible and abort the writing operation. + * + * @param configChange the {@link ConfigChangeRequest}, containing the transactionId used to isolate + * the change, the properties to be added/overridden and the property keys + * being removed. + * @throws org.apache.tamaya.ConfigException if any of the given properties could not be written, or the request is read-only. + */ + void applyChange(ConfigChangeRequest configChange); + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/main/resources/META-INF/services/org.apache.tamaya.mutableconfig.spi.MutableConfigurationProviderSpi ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/main/resources/META-INF/services/org.apache.tamaya.mutableconfig.spi.MutableConfigurationProviderSpi b/modules/mutable-config/src/main/resources/META-INF/services/org.apache.tamaya.mutableconfig.spi.MutableConfigurationProviderSpi new file mode 100644 index 0000000..eb366fc --- /dev/null +++ b/modules/mutable-config/src/main/resources/META-INF/services/org.apache.tamaya.mutableconfig.spi.MutableConfigurationProviderSpi @@ -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.mutableconfig.internal.DefaultMutableConfigurationSpi \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationProviderTest.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationProviderTest.java b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationProviderTest.java new file mode 100644 index 0000000..b316b7d --- /dev/null +++ b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationProviderTest.java @@ -0,0 +1,84 @@ +/* + * 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.mutableconfig; + +import org.apache.tamaya.ConfigurationProvider; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by atsticks on 26.08.16. + */ +public class MutableConfigurationProviderTest { + @Test + public void createMutableConfiguration() throws Exception { + assertNotNull(MutableConfigurationProvider.createMutableConfiguration()); + } + + @Test + public void createMutableConfiguration1() throws Exception { + MutableConfiguration cfg = MutableConfigurationProvider + .createMutableConfiguration(ConfigurationProvider.getConfiguration()); + assertNotNull(cfg); + assertEquals(cfg.getChangePropagationPolicy(), + MutableConfigurationProvider.getApplyMostSignificantOnlyChangePolicy()); + } + + @Test + public void createMutableConfiguration2() throws Exception { + ChangePropagationPolicy policy = MutableConfigurationProvider.getApplySelectiveChangePolicy("blabla"); + MutableConfiguration cfg = MutableConfigurationProvider + .createMutableConfiguration(ConfigurationProvider.getConfiguration(), + policy); + assertNotNull(cfg); + assertEquals(cfg.getChangePropagationPolicy(), policy); + } + + @Test + public void createMutableConfiguration3() throws Exception { + ChangePropagationPolicy policy = MutableConfigurationProvider.getApplySelectiveChangePolicy("gugus"); + MutableConfiguration cfg = MutableConfigurationProvider + .createMutableConfiguration(policy); + assertNotNull(cfg); + assertEquals(cfg.getChangePropagationPolicy(), policy); + } + + @Test + public void getApplyAllChangePolicy() throws Exception { + assertNotNull(MutableConfigurationProvider.getApplyAllChangePolicy()); + } + + @Test + public void getApplyMostSignificantOnlyChangePolicy() throws Exception { + assertNotNull(MutableConfigurationProvider.getApplyMostSignificantOnlyChangePolicy()); + } + + @Test + public void getApplySelectiveChangePolicy() throws Exception { + assertNotNull(MutableConfigurationProvider.getApplySelectiveChangePolicy()); + } + + @Test + public void getApplyNonePolicy() throws Exception { + assertNotNull(MutableConfigurationProvider.getApplyNonePolicy()); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationTest.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationTest.java b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationTest.java new file mode 100644 index 0000000..814f3ce --- /dev/null +++ b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/MutableConfigurationTest.java @@ -0,0 +1,187 @@ +/* + * 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.mutableconfig; + +import org.apache.tamaya.Configuration; +import org.apache.tamaya.ConfigurationProvider; +import org.apache.tamaya.mutableconfig.internal.WritablePropertiesSource; +import org.apache.tamaya.mutableconfig.internal.WritableXmlPropertiesSource; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import static org.junit.Assert.*; + +/** + * Tests for {@link MutableConfiguration}. + */ +public class MutableConfigurationTest { + + /** + * Test create change request. + * + * @throws Exception the exception + */ + @Test + public void testCreateMutableConfiguration() throws Exception { + File f = File.createTempFile("ConfigChangeRequest",".properties"); + MutableConfiguration cfg1 = MutableConfigurationProvider.createMutableConfiguration( + ConfigurationProvider.getConfiguration(), + MutableConfigurationProvider.getApplyAllChangePolicy()); + assertNotNull(cfg1); + assertNotNull(cfg1.getConfigChangeRequest()); + MutableConfiguration cfg2 = MutableConfigurationProvider.createMutableConfiguration( + ConfigurationProvider.getConfiguration()); + assertNotNull(cfg2); + assertNotNull(cfg2.getConfigChangeRequest()); + assertTrue(cfg1!=cfg2); + assertTrue(cfg1.getConfigChangeRequest()!=cfg2.getConfigChangeRequest()); + } + + /** + * Test null create change request. + * + * @throws Exception the exception + */ + @Test(expected=NullPointerException.class) + public void testNullCreateMutableConfiguration1() throws Exception { + MutableConfigurationProvider.createMutableConfiguration( + (Configuration) null); + } + + /** + * Test null create change request. + * + * @throws Exception the exception + */ + @Test(expected=NullPointerException.class) + public void testNullCreateMutableConfiguration2() throws Exception { + MutableConfigurationProvider.createMutableConfiguration( + (ChangePropagationPolicy) null); + } + + /** + * Test read write properties with rollback. + * + * @throws IOException the io exception + */ + @Test + public void testReadWriteProperties_WithCancel() throws IOException { + WritablePropertiesSource.target.delete(); + MutableConfiguration mutConfig = MutableConfigurationProvider.createMutableConfiguration( + ConfigurationProvider.getConfiguration() + ); + mutConfig.put("key1", "value1"); + Map<String,String> cm = new HashMap<>(); + cm.put("key2", "value2"); + cm.put("key3", "value3"); + } + + /** + * Test read write properties with commit. + * + * @throws IOException the io exception + */ + @Test + public void testReadWriteProperties_WithCommit() throws IOException { + WritablePropertiesSource.target.delete(); + MutableConfiguration mutConfig = MutableConfigurationProvider.createMutableConfiguration( + ConfigurationProvider.getConfiguration() + ); + mutConfig.put("key1", "value1"); + Map<String,String> cm = new HashMap<>(); + cm.put("key2", "value2"); + cm.put("key3", "value3"); + mutConfig.putAll(cm); + mutConfig.store(); + assertTrue(WritablePropertiesSource.target.exists()); + MutableConfiguration mmutConfig2 = MutableConfigurationProvider.createMutableConfiguration( + ConfigurationProvider.getConfiguration() + ); + mmutConfig2.remove("foo"); + mmutConfig2.remove("key3"); + mmutConfig2.put("key1", "value1.2"); + mmutConfig2.put("key4", "value4"); + mmutConfig2.store(); + Properties props = new Properties(); + props.load(WritablePropertiesSource.target.toURL().openStream()); + assertEquals(3, props.size()); + assertEquals("value1.2", props.getProperty("key1")); + assertEquals("value2", props.getProperty("key2")); + assertEquals("value4", props.getProperty("key4")); + } + + /** + * Test read write xml properties with commit. + * + * @throws IOException the io exception + */ + @Test + public void testReadWriteXmlProperties_WithCommit() throws IOException { + WritableXmlPropertiesSource.target.delete(); + MutableConfiguration cfg = MutableConfigurationProvider.createMutableConfiguration( + ConfigurationProvider.getConfiguration(), MutableConfigurationProvider.getApplyAllChangePolicy()); + cfg.put("key1", "value1"); + Map<String,String> cm = new HashMap<>(); + cm.put("key2", "value2"); + cm.put("key3", "value3"); + cfg.putAll(cm); + cfg.store(); + assertTrue(WritableXmlPropertiesSource.target.exists()); + MutableConfiguration cfg2 = MutableConfigurationProvider.createMutableConfiguration( + ConfigurationProvider.getConfiguration()); + assertTrue(cfg != cfg2); + cfg2.remove("foo"); + cfg2.remove("key3"); + cfg2.put("key1", "value1.2"); + cfg2.put("key4", "value4"); + cfg2.store(); + Properties props = new Properties(); + props.loadFromXML( WritableXmlPropertiesSource.target.toURL().openStream()); + assertEquals(3, props.size()); + assertEquals("value1", props.getProperty("key1")); + assertEquals("value2", props.getProperty("key2")); + } + + /** + * Test read write xml properties with commit. + * + * @throws IOException the io exception + */ + @Test + public void testWriteWithNoChangePolicy() throws IOException { + WritableXmlPropertiesSource.target.delete(); + MutableConfiguration cfg = MutableConfigurationProvider.createMutableConfiguration( + ConfigurationProvider.getConfiguration(), + MutableConfigurationProvider.getApplyNonePolicy()); + cfg.put("key1", "value1"); + Map<String,String> cm = new HashMap<>(); + cm.put("key2", "value2"); + cm.put("key3", "value3"); + cfg.putAll(cm); + cfg.store(); + assertFalse(WritableXmlPropertiesSource.target.exists()); + } + + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigBackendTest.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigBackendTest.java b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigBackendTest.java new file mode 100644 index 0000000..e6c79f5 --- /dev/null +++ b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/PropertiesFileConfigBackendTest.java @@ -0,0 +1,29 @@ +/* + * 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.mutableconfig.internal; + +import org.apache.tamaya.mutableconfig.propertysources.MutablePropertiesPropertySource; + + +/** + * Tests for {@link MutablePropertiesPropertySource}. + */ +public class PropertiesFileConfigBackendTest { + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/3aca9112/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/WritablePropertiesSource.java ---------------------------------------------------------------------- diff --git a/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/WritablePropertiesSource.java b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/WritablePropertiesSource.java new file mode 100644 index 0000000..5257c8b --- /dev/null +++ b/modules/mutable-config/src/test/java/org/apache/tamaya/mutableconfig/internal/WritablePropertiesSource.java @@ -0,0 +1,49 @@ +/* + * 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.mutableconfig.internal; + +import org.apache.tamaya.mutableconfig.propertysources.MutablePropertiesPropertySource; + +import java.io.File; +import java.io.IOException; + +/** + * Writable test property source based on the {@link MutablePropertiesPropertySource}. + */ +public class WritablePropertiesSource extends MutablePropertiesPropertySource { + + public static File target = createFile(); + + private static File createFile() { + try { + return File.createTempFile("writableProps",".properties"); + } catch (IOException e) { + e.printStackTrace(); + throw new IllegalStateException("Cannot init test.", e); + } + } + + /** + * Creates a new Properties based PropertySource based on the given URL. + */ + public WritablePropertiesSource() throws IOException { + super(target, 100); + } + +}
