You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by st...@apache.org on 2018/04/05 12:16:05 UTC
[2/5] deltaspike git commit: DELTASPIKE-1335 atomic access to
configured values
DELTASPIKE-1335 atomic access to configured values
Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/a101bab9
Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/a101bab9
Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/a101bab9
Branch: refs/heads/master
Commit: a101bab996d6cfad8369dc96626bb7d016318351
Parents: fdd1e3d
Author: Mark Struberg <st...@apache.org>
Authored: Wed Apr 4 17:09:52 2018 +0200
Committer: Mark Struberg <st...@apache.org>
Committed: Wed Apr 4 17:31:39 2018 +0200
----------------------------------------------------------------------
.../deltaspike/core/api/config/Config.java | 4 +-
.../deltaspike/core/impl/config/ConfigImpl.java | 28 ++++++
.../core/impl/config/ConfigTransactionImpl.java | 51 +++++++++++
.../core/api/config/ConfigTransactionTest.java | 88 +++++++++++++++++++
.../config/ConfigurableTestConfigSource.java | 91 ++++++++++++++++++++
...ache.deltaspike.core.spi.config.ConfigSource | 1 +
6 files changed, 261 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/a101bab9/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/Config.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/Config.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/Config.java
index f1fc368..6a1bf54 100644
--- a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/Config.java
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/Config.java
@@ -66,7 +66,7 @@ public interface Config
* To consistently access n different config values we can start a {@link ConfigTransaction} for those values.
*
* <pre>
- * ConfigTransaction cfgTx = config.startTx(hostCfg, portCfg);
+ * ConfigTransaction cfgTx = config.startTransaction(hostCfg, portCfg);
*
* String host = cfgTx.getValue(hostCfg);
* Integer port = cfgTx.getValue(portCfg);
@@ -80,7 +80,7 @@ public interface Config
*
* @return a new {@link ConfigTransaction} which holds the resolved values of all the {@param typedResolvers}.
*/
- ConfigTransaction startTx(ConfigResolver.TypedResolver<?>... typedResolvers);
+ ConfigTransaction startTransaction(ConfigResolver.TypedResolver<?>... typedResolvers);
/**
* @return all the current ConfigSources for this Config
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/a101bab9/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigImpl.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigImpl.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigImpl.java
index eefc612..b6502bf 100644
--- a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigImpl.java
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigImpl.java
@@ -20,6 +20,7 @@ package org.apache.deltaspike.core.impl.config;
import org.apache.deltaspike.core.api.config.Config;
import org.apache.deltaspike.core.api.config.ConfigResolver;
+import org.apache.deltaspike.core.api.config.ConfigTransaction;
import org.apache.deltaspike.core.spi.config.ConfigFilter;
import org.apache.deltaspike.core.spi.config.ConfigSource;
import org.apache.deltaspike.core.spi.config.ConfigSourceProvider;
@@ -28,7 +29,9 @@ import org.apache.deltaspike.core.util.ServiceUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
@@ -127,6 +130,31 @@ public class ConfigImpl implements Config
}
@Override
+ public ConfigTransaction startTransaction(ConfigResolver.TypedResolver<?>[] typedResolvers)
+ {
+ // we implement kind of optimistic Locking
+ // Means we try multiple time to resolve all the given values
+ // until the config didn't change inbetween.
+ for (int tries = 1; tries < 5; tries++)
+ {
+ Map<ConfigResolver.TypedResolver<?>, Object> configValues = new HashMap<>();
+ long startReadCfgTst = lastChanged;
+ for (ConfigResolver.TypedResolver<?> typedResolver : typedResolvers)
+ {
+ configValues.put(typedResolver, typedResolver.getValue());
+ }
+
+ if (startReadCfgTst == lastChanged)
+ {
+ return new ConfigTransactionImpl(this, configValues);
+ }
+ }
+
+ throw new IllegalStateException(
+ "Could not resolve ConfigTransaction as underlying values are permanently changing!");
+ }
+
+ @Override
public void addConfigSources(List<ConfigSource> configSourcesToAdd)
{
List<ConfigSource> allConfigSources = new ArrayList<>();
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/a101bab9/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigTransactionImpl.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigTransactionImpl.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigTransactionImpl.java
new file mode 100644
index 0000000..4a5108a
--- /dev/null
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigTransactionImpl.java
@@ -0,0 +1,51 @@
+/*
+ * 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.deltaspike.core.impl.config;
+
+import org.apache.deltaspike.core.api.config.ConfigResolver;
+import org.apache.deltaspike.core.api.config.ConfigTransaction;
+
+import java.util.Map;
+
+/**
+ * @author Mark Struberg
+ */
+public class ConfigTransactionImpl implements ConfigTransaction
+{
+ private final ConfigImpl config;
+ private final Map<ConfigResolver.TypedResolver<?>, Object> configValues;
+
+ public ConfigTransactionImpl(ConfigImpl config, Map<ConfigResolver.TypedResolver<?>, Object> configValues)
+ {
+ this.config = config;
+ this.configValues = configValues;
+ }
+
+ @Override
+ public <T> T getValue(ConfigResolver.TypedResolver<T> typedResolver)
+ {
+ if (!configValues.containsKey(typedResolver))
+ {
+ throw new IllegalArgumentException("The TypedResolver for key " + typedResolver.getKey() +
+ " does not belong to this ConfigTransaction!");
+ }
+
+ return (T) configValues.get(typedResolver);
+ }
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/a101bab9/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/ConfigTransactionTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/ConfigTransactionTest.java b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/ConfigTransactionTest.java
new file mode 100644
index 0000000..e448ca6
--- /dev/null
+++ b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/ConfigTransactionTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.deltaspike.test.core.api.config;
+
+import org.apache.deltaspike.core.api.config.Config;
+import org.apache.deltaspike.core.api.config.ConfigResolver;
+import org.apache.deltaspike.core.api.config.ConfigTransaction;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+
+public class ConfigTransactionTest
+{
+ private static final String HOST_KEY = "ds.test.myapp.host";
+ private static final String PORT1_KEY = "ds.test.myapp.port1";
+ private static final String PORT2_KEY = "ds.test.myapp.port2";
+
+ private ConfigResolver.TypedResolver<String> hostCfg;
+ private ConfigResolver.TypedResolver<Integer> port1Cfg;
+ private ConfigResolver.TypedResolver<Integer> port2Cfg;
+
+
+ @Test
+ public void testConfigTx()
+ {
+ ConfigurableTestConfigSource configSource = ConfigurableTestConfigSource.instance();
+ try
+ {
+ configSource.set(HOST_KEY, "host1");
+ configSource.set(PORT1_KEY, "1");
+ configSource.set(PORT2_KEY, "1");
+
+ Config cfg = ConfigResolver.getConfig();
+ hostCfg = cfg.resolve(HOST_KEY);
+ port1Cfg = cfg.resolve(PORT1_KEY).as(Integer.class);
+ port2Cfg = cfg.resolve(PORT2_KEY).as(Integer.class);
+
+ assertEquals("host1", hostCfg.getValue());
+ assertEquals(Integer.valueOf(1), port1Cfg.getValue());
+ assertEquals(Integer.valueOf(1), port2Cfg.getValue());
+
+ ConfigTransaction configTransaction = cfg.startTransaction(hostCfg, port1Cfg, port2Cfg);
+ assertNotNull(configTransaction);
+
+ assertEquals("host1", configTransaction.getValue(hostCfg));
+ assertEquals(Integer.valueOf(1), configTransaction.getValue(port1Cfg));
+ assertEquals(Integer.valueOf(1), configTransaction.getValue(port2Cfg));
+
+ // and those values don't change, even if we modify the underlying ConfigSource!
+ configSource.set(HOST_KEY, "host2");
+ configSource.set(PORT1_KEY, "2");
+ configSource.set(PORT2_KEY, "2");
+
+ assertEquals("host1", configTransaction.getValue(hostCfg));
+ assertEquals(Integer.valueOf(1), configTransaction.getValue(port1Cfg));
+ assertEquals(Integer.valueOf(1), configTransaction.getValue(port2Cfg));
+
+ // but the actual config did really change!
+ assertEquals("host2", hostCfg.getValue());
+ assertEquals(Integer.valueOf(2), port1Cfg.getValue());
+ assertEquals(Integer.valueOf(2), port2Cfg.getValue());
+ }
+ finally
+ {
+ configSource.clear();
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/a101bab9/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/ConfigurableTestConfigSource.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/ConfigurableTestConfigSource.java b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/ConfigurableTestConfigSource.java
new file mode 100644
index 0000000..2c3a9db
--- /dev/null
+++ b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/ConfigurableTestConfigSource.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.deltaspike.test.core.api.config;
+
+import org.apache.deltaspike.core.api.config.ConfigResolver;
+import org.apache.deltaspike.core.spi.config.ConfigSource;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A ConfigSource which is backed by a ThreadLocal.
+ * So it can be dynamically configured even for parallel tests.
+ *
+ * Note that you MUST call the {@link #clear()} method at the end of a method which uses this ConfigSource.
+ */
+public class ConfigurableTestConfigSource implements ConfigSource
+{
+ private static ThreadLocal<Map<String, String>> props = new ThreadLocal<>();
+
+ @Override
+ public int getOrdinal()
+ {
+ return 500;
+ }
+
+ public static ConfigurableTestConfigSource instance() {
+ return (ConfigurableTestConfigSource) Arrays.stream(ConfigResolver.getConfig().getConfigSources())
+ .filter(cs -> cs instanceof ConfigurableTestConfigSource)
+ .findFirst()
+ .get();
+ }
+
+ @Override
+ public Map<String, String> getProperties()
+ {
+ Map<String, String> propMap = props.get();
+ if (propMap == null)
+ {
+ propMap = new ConcurrentHashMap<>();
+ props.set(propMap);
+ }
+ return propMap;
+ }
+
+ @Override
+ public String getPropertyValue(String key)
+ {
+ return getProperties().get(key);
+ }
+
+ @Override
+ public String getConfigName()
+ {
+ return this.getClass().getSimpleName();
+ }
+
+ @Override
+ public boolean isScannable()
+ {
+ return true;
+ }
+
+ public void clear()
+ {
+ props.set(null);
+ props.remove();
+ }
+
+ public void set(String key, String value)
+ {
+ getProperties().put(key, value);
+ }
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/a101bab9/deltaspike/core/impl/src/test/resources/META-INF/services/org.apache.deltaspike.core.spi.config.ConfigSource
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/test/resources/META-INF/services/org.apache.deltaspike.core.spi.config.ConfigSource b/deltaspike/core/impl/src/test/resources/META-INF/services/org.apache.deltaspike.core.spi.config.ConfigSource
index 833d367..956fb04 100644
--- a/deltaspike/core/impl/src/test/resources/META-INF/services/org.apache.deltaspike.core.spi.config.ConfigSource
+++ b/deltaspike/core/impl/src/test/resources/META-INF/services/org.apache.deltaspike.core.spi.config.ConfigSource
@@ -18,3 +18,4 @@
#####################################################################################
org.apache.deltaspike.test.core.api.config.TestConfigSource
+org.apache.deltaspike.test.core.api.config.ConfigurableTestConfigSource
\ No newline at end of file