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