ensure system properties set during extension startup lifecycle are usable at runtime, even with our copy strategy
diff --git a/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigBean.java b/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigBean.java
deleted file mode 100644
index 0549a88..0000000
--- a/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigBean.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.geronimo.config.cdi;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.singleton;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.context.spi.CreationalContext;
-import javax.enterprise.inject.spi.Bean;
-import javax.enterprise.inject.spi.InjectionPoint;
-import javax.enterprise.inject.spi.PassivationCapable;
-
-import org.eclipse.microprofile.config.Config;
-import org.eclipse.microprofile.config.ConfigProvider;
-
-public class ConfigBean<T> implements Bean<T>, PassivationCapable {
-
-    private final String id = ConfigBean.class.getName();
-
-    private final Set<Annotation> qualifiers = singleton(new DefaultLiteral());
-
-    private final Set<Type> types = new HashSet<>(asList(Config.class, Object.class));
-
-    @Override
-    public Set<InjectionPoint> getInjectionPoints() {
-        return Collections.emptySet();
-    }
-
-    @Override
-    public Class<?> getBeanClass() {
-        return Config.class;
-    }
-
-    @Override
-    public boolean isNullable() {
-        return false;
-    }
-
-    @Override
-    public T create(final CreationalContext<T> context) {
-        return (T) ConfigProvider.getConfig();
-    }
-
-    @Override
-    public void destroy(final T instance, final CreationalContext<T> context) {
-        // no-op
-    }
-
-    @Override
-    public Set<Type> getTypes() {
-        return types;
-    }
-
-    @Override
-    public Set<Annotation> getQualifiers() {
-        return qualifiers;
-    }
-
-    @Override
-    public Class<? extends Annotation> getScope() {
-        return ApplicationScoped.class;
-    }
-
-    @Override
-    public String getName() {
-        return null;
-    }
-
-    @Override
-    public Set<Class<? extends Annotation>> getStereotypes() {
-        return Collections.emptySet();
-    }
-
-    @Override
-    public boolean isAlternative() {
-        return false;
-    }
-
-    @Override
-    public String getId() {
-        return id;
-    }
-}
diff --git a/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigExtension.java b/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigExtension.java
index dd6c114..8870ff0 100644
--- a/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigExtension.java
+++ b/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigExtension.java
@@ -18,10 +18,11 @@
 
 import static java.util.stream.Collectors.toList;
 
-import org.apache.geronimo.config.DefaultConfigProvider;
+import org.apache.geronimo.config.cdi.configsource.Reloadable;
 import org.eclipse.microprofile.config.Config;
 import org.eclipse.microprofile.config.ConfigProvider;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
 
 import javax.enterprise.event.Observes;
 import javax.enterprise.inject.spi.AfterBeanDiscovery;
@@ -32,15 +33,12 @@
 import javax.enterprise.inject.spi.Extension;
 import javax.enterprise.inject.spi.InjectionPoint;
 import javax.enterprise.inject.spi.ProcessAnnotatedType;
-import javax.enterprise.inject.spi.ProcessBean;
 import javax.enterprise.inject.spi.ProcessInjectionPoint;
 import javax.inject.Provider;
 
-import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -50,6 +48,7 @@
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 /**
  * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
@@ -72,7 +71,6 @@
     private Set<Class<?>> proxies = new HashSet<>();
     private List<Class<?>> validProxies;
     private List<ProxyBean<?>> proxyBeans;
-    private boolean foundConfig;
 
 
     public void findProxies(@Observes ProcessAnnotatedType<?> pat) {
@@ -91,10 +89,6 @@
         }
     }
 
-    void onConfig(@Observes final ProcessAnnotatedType<Config> configProcessBean) {
-        foundConfig = true;
-    }
-
     public void registerConfigProducer(@Observes AfterBeanDiscovery abd, BeanManager bm) {
         Set<Type> types = injectionPoints.stream()
                 .filter(NOT_PROVIDERS)
@@ -121,16 +115,18 @@
                                      .collect(toList());
             proxyBeans.forEach(abd::addBean);
         } // else there are errors
-
-        if (!foundConfig) {
-            abd.addBean(new ConfigInjectionBean<>(bm, Config.class));
-        }
     }
 
     public void validate(@Observes AfterDeploymentValidation add) {
         List<String> deploymentProblems = new ArrayList<>();
 
         config = ConfigProvider.getConfig();
+
+        StreamSupport.stream(config.getConfigSources().spliterator(), false)
+                     .filter(Reloadable.class::isInstance)
+                     .map(Reloadable.class::cast)
+                     .forEach(Reloadable::reload);
+
         proxyBeans.forEach(b -> b.init(config));
         proxyBeans.clear();
 
@@ -167,7 +163,7 @@
     }
 
     public void shutdown(@Observes BeforeShutdown bsd) {
-        DefaultConfigProvider.instance().releaseConfig(config);
+        ConfigProviderResolver.instance().releaseConfig(config);
     }
 
     private boolean isValidProxy(final Class<?> api) {
diff --git a/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigurationHandler.java b/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigurationHandler.java
index 838d452..7880771 100644
--- a/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigurationHandler.java
+++ b/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigurationHandler.java
@@ -127,6 +127,8 @@
                 final String finalDefaultValue = defaultValue;
                 if (lookupType == long.class || lookupType == Long.class) {
                     this.defaultValue = Long.parseLong(finalDefaultValue);
+                } else if (lookupType == boolean.class || lookupType == Boolean.class) {
+                    this.defaultValue = Boolean.parseBoolean(finalDefaultValue);
                 } else if (lookupType == int.class || lookupType == Integer.class) {
                     this.defaultValue = Integer.parseInt(finalDefaultValue);
                 } else if (lookupType == double.class || lookupType == Double.class) {
diff --git a/impl/src/main/java/org/apache/geronimo/config/cdi/configsource/Reloadable.java b/impl/src/main/java/org/apache/geronimo/config/cdi/configsource/Reloadable.java
new file mode 100644
index 0000000..62e916d
--- /dev/null
+++ b/impl/src/main/java/org/apache/geronimo/config/cdi/configsource/Reloadable.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.geronimo.config.cdi.configsource;
+
+/**
+ * Enable config source to be reloaded in AfterDeploymentValidation
+ * phase. Particularly useful for sources relying on a state which can
+ * be mutated in previous phases like system properties but which
+ * desire to stay immutable at runtime for perf/lock reasons.
+ */
+public interface Reloadable {
+    void reload();
+}
diff --git a/impl/src/main/java/org/apache/geronimo/config/configsource/SystemPropertyConfigSource.java b/impl/src/main/java/org/apache/geronimo/config/configsource/SystemPropertyConfigSource.java
index 553c197..066bc0d 100644
--- a/impl/src/main/java/org/apache/geronimo/config/configsource/SystemPropertyConfigSource.java
+++ b/impl/src/main/java/org/apache/geronimo/config/configsource/SystemPropertyConfigSource.java
@@ -18,6 +18,7 @@
  */
 package org.apache.geronimo.config.configsource;
 
+import org.apache.geronimo.config.cdi.configsource.Reloadable;
 import org.eclipse.microprofile.config.spi.ConfigSource;
 
 import javax.enterprise.inject.Typed;
@@ -35,18 +36,18 @@
  */
 @Typed
 @Vetoed
-public class SystemPropertyConfigSource extends BaseConfigSource {
+public class SystemPropertyConfigSource extends BaseConfigSource implements Reloadable {
     private static final String COPY_PROPERTY = "org.apache.geronimo.config.configsource.SystemPropertyConfigSource.copy";
     private final Map<String, String> instance;
+    private final boolean shouldReload;
 
     public SystemPropertyConfigSource() {
         this(valueOf(System.getProperty(COPY_PROPERTY, "true")));
     }
 
     public SystemPropertyConfigSource(boolean copy) {
-        instance = copy ?
-                System.getProperties().stringPropertyNames().stream().collect(toMap(identity(), System::getProperty)) :
-                Map.class.cast(System.getProperties());
+        instance = load(copy);
+        shouldReload = copy;
         initOrdinal(400);
     }
 
@@ -64,4 +65,19 @@
     public String getName() {
         return "system-properties";
     }
+
+    @Override
+    public void reload() {
+        if (!shouldReload) {
+            return;
+        }
+        instance.clear();
+        instance.putAll(load(true));
+    }
+
+    private Map<String, String> load(final boolean copy) {
+        return copy ?
+                System.getProperties().stringPropertyNames().stream().collect(toMap(identity(), System::getProperty)) :
+                Map.class.cast(System.getProperties());
+    }
 }
diff --git a/impl/src/test/java/org/apache/geronimo/config/test/internal/SystemPropertyConfigSourceTest.java b/impl/src/test/java/org/apache/geronimo/config/test/internal/SystemPropertyConfigSourceTest.java
new file mode 100644
index 0000000..a0addba
--- /dev/null
+++ b/impl/src/test/java/org/apache/geronimo/config/test/internal/SystemPropertyConfigSourceTest.java
@@ -0,0 +1,102 @@
+/*
+ *  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.geronimo.config.test.internal;
+
+import static org.testng.Assert.assertTrue;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.BeforeShutdown;
+import javax.enterprise.inject.spi.Extension;
+import javax.inject.Inject;
+
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.testng.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * It is important to ensure the config is reloaded before going live in case some
+ * system properties are set during the starting extension lifecycle.
+ */
+public class SystemPropertyConfigSourceTest extends Arquillian {
+    @Deployment
+    public static Archive<?> archive() {
+        return ShrinkWrap.create(WebArchive.class, SystemPropertyConfigSourceTest.class.getSimpleName() + ".war")
+                .addAsWebInfResource(EmptyAsset.INSTANCE, "classes/META-INF/beans.xml")
+                .addAsServiceProvider(Extension.class, InitInExtension.class)
+                .addClasses(SystemPropertyConfigSourceTest.class, Injected.class);
+    }
+
+    @Inject
+    private Injected injected;
+
+    @Test
+    public void testSystemPropsLoadedExtensionValue() {
+        assertTrue(injected.getSet());
+    }
+
+    @ApplicationScoped
+    public static class Injected {
+        @Inject
+        @ConfigProperty(name = "org.apache.geronimo.config.test.internal.SystemPropertyConfigSourceTest$InitInExtension")
+        private Boolean set;
+
+        public Boolean getSet() {
+            return set;
+        }
+    }
+
+    public static class InitInExtension implements Extension {
+        private String originalCopy;
+
+        void eagerInit(@Observes final BeforeBeanDiscovery beforeBeanDiscovery) {
+            originalCopy = System.getProperty("org.apache.geronimo.config.configsource.SystemPropertyConfigSource.copy");
+            // enfore the default, it is overriden for surefire
+            System.setProperty("org.apache.geronimo.config.configsource.SystemPropertyConfigSource.copy", "true");
+
+            // eager load -> loads system props and copy
+            ConfigProvider.getConfig();
+        }
+
+        // before validation to ensure config validation passes
+        void afterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery) {
+            // with copy this should get ignored but we will reload it before the validation
+            System.setProperty(InitInExtension.class.getName(), "true");
+        }
+
+        void beforeShutdown(@Observes final BeforeShutdown beforeShutdown) {
+            System.clearProperty(InitInExtension.class.getName());
+            if (originalCopy != null) {
+                System.setProperty("org.apache.geronimo.config.configsource.SystemPropertyConfigSource.copy", originalCopy);
+            } else {
+                System.clearProperty("org.apache.geronimo.config.configsource.SystemPropertyConfigSource.copy");
+            }
+        }
+    }
+}