SLING-9390 : Refactor implementation to have a single configuration object
diff --git a/src/main/java/org/apache/sling/feature/apiregions/impl/Activator.java b/src/main/java/org/apache/sling/feature/apiregions/impl/Activator.java
index 27189c3..9f78504 100644
--- a/src/main/java/org/apache/sling/feature/apiregions/impl/Activator.java
+++ b/src/main/java/org/apache/sling/feature/apiregions/impl/Activator.java
@@ -18,6 +18,17 @@
  */
 package org.apache.sling.feature.apiregions.impl;
 
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
@@ -31,21 +42,13 @@
 import org.osgi.resource.Requirement;
 import org.osgi.resource.Resource;
 
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.Map;
-import java.util.logging.Level;
-
 public class Activator implements BundleActivator, FrameworkListener {
     static final String MANAGED_SERVICE_PKG_NAME = "org.osgi.service.cm";
     static final String MANAGED_SERVICE_CLASS_NAME = MANAGED_SERVICE_PKG_NAME + ".ManagedService";
     static final String REGIONS_PROPERTY_NAME = "org.apache.sling.feature.apiregions.regions";
 
+    static final Logger LOG = Logger.getLogger(ResolverHookImpl.class.getName());
+
     BundleContext bundleContext;
     ServiceRegistration<ResolverHookFactory> hookRegistration;
 
@@ -68,16 +71,17 @@
             return; // There is already a hook, no need to re-register
 
         if (bundleContext.getProperty(REGIONS_PROPERTY_NAME) == null) {
-            RegionEnforcer.LOG.log(Level.WARNING, "API Regions not enabled. To enable set framework property: " + REGIONS_PROPERTY_NAME);
+            LOG.log(Level.WARNING, "API Regions not enabled. To enable set framework property: " + REGIONS_PROPERTY_NAME);
             return; // Component not enabled
         }
 
         Dictionary<String, Object> props = new Hashtable<>();
         try {
-            RegionEnforcer enforcer = new RegionEnforcer(bundleContext, props);
+            final RegionConfiguration cfg = new RegionConfiguration(bundleContext, props);
+            RegionEnforcer enforcer = new RegionEnforcer(cfg);
             hookRegistration = bundleContext.registerService(ResolverHookFactory.class, enforcer, props);
         } catch (Exception e) {
-            RegionEnforcer.LOG.log(Level.SEVERE, "Problem activating API Regions runtime enforcement component", e);
+            LOG.log(Level.SEVERE, "Problem activating API Regions runtime enforcement component", e);
         }
     }
 
@@ -95,7 +99,7 @@
 
             FrameworkWiring fw = bundleContext.getBundle().adapt(FrameworkWiring.class);
             if (fw == null) {
-                RegionEnforcer.LOG.log(Level.WARNING, "The API Regions runtime fragment is not attached to the system bundle.");
+                LOG.log(Level.WARNING, "The API Regions runtime fragment is not attached to the system bundle.");
                 return;
             }
 
@@ -150,10 +154,10 @@
 
                     return; // ManagedService registration successful. Exit method.
                 } catch (Exception e) {
-                    RegionEnforcer.LOG.log(Level.WARNING, "Problem attempting to register ManagedService from " + cap, e);
+                    LOG.log(Level.WARNING, "Problem attempting to register ManagedService from " + cap, e);
                 }
             }
-            RegionEnforcer.LOG.log(Level.INFO, "No Configuration Admin API available");
+            LOG.log(Level.INFO, "No Configuration Admin API available");
         }
     }
 
diff --git a/src/main/java/org/apache/sling/feature/apiregions/impl/RegionConfiguration.java b/src/main/java/org/apache/sling/feature/apiregions/impl/RegionConfiguration.java
new file mode 100644
index 0000000..3fb8809
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/apiregions/impl/RegionConfiguration.java
@@ -0,0 +1,267 @@
+/*
+ * 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.sling.feature.apiregions.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Version;
+
+class RegionConfiguration {
+    public static final String GLOBAL_REGION = "global";
+
+    static final String CLASSLOADER_PSEUDO_PROTOCOL = "classloader://";
+    static final String APIREGIONS_JOINGLOBAL = "sling.feature.apiregions.joinglobal";
+    static final String DEFAULT_REGIONS = "sling.feature.apiregions.default";
+    static final String PROPERTIES_RESOURCE_PREFIX = "sling.feature.apiregions.resource.";
+    static final String PROPERTIES_FILE_LOCATION = "sling.feature.apiregions.location";
+
+    static final String IDBSNVER_FILENAME = "idbsnver.properties";
+    static final String BUNDLE_FEATURE_FILENAME = "bundles.properties";
+    static final String FEATURE_REGION_FILENAME = "features.properties";
+    static final String REGION_PACKAGE_FILENAME = "regions.properties";
+
+    final Map<Map.Entry<String, Version>, List<String>> bsnVerMap;
+    final Map<String, Set<String>> bundleFeatureMap;
+    final Map<String, Set<String>> featureRegionMap;
+    final Map<String, Set<String>> regionPackageMap;
+    final Set<String> defaultRegions;
+
+    RegionConfiguration(Map<Entry<String, Version>, List<String>> bsnVerMap, Map<String, Set<String>> bundleFeatureMap,
+                        Map<String, Set<String>> featureRegionMap, Map<String, Set<String>> regionPackageMap, Set<String> defaultRegions) {
+        this.bsnVerMap = bsnVerMap;
+        this.bundleFeatureMap = bundleFeatureMap;
+        this.featureRegionMap = featureRegionMap;
+        this.regionPackageMap = regionPackageMap;
+        this.defaultRegions = defaultRegions;
+    }
+    RegionConfiguration(BundleContext context, Dictionary<String, Object> regProps)
+            throws IOException, URISyntaxException {
+        URI idbsnverFile = getDataFileURI(context, IDBSNVER_FILENAME);
+        // Register the location as a service property for diagnostic purposes
+        regProps.put(IDBSNVER_FILENAME, idbsnverFile.toString());
+        Map<Entry<String, Version>, List<String>> bvm = populateBSNVerMap(idbsnverFile);
+
+        URI bundlesFile = getDataFileURI(context, BUNDLE_FEATURE_FILENAME);
+        // Register the location as a service property for diagnostic purposes
+        regProps.put(BUNDLE_FEATURE_FILENAME, bundlesFile.toString());
+        Map<String, Set<String>> bfm = populateBundleFeatureMap(bundlesFile);
+
+        URI featuresFile = getDataFileURI(context, FEATURE_REGION_FILENAME);
+        // Register the location as a service property for diagnostic purposes
+        regProps.put(FEATURE_REGION_FILENAME, featuresFile.toString());
+        Map<String, Set<String>> frm = populateFeatureRegionMap(featuresFile);
+
+        URI regionsFile = getDataFileURI(context, REGION_PACKAGE_FILENAME);
+        // Register the location as a service property for diagnostic purposes
+        regProps.put(REGION_PACKAGE_FILENAME, regionsFile.toString());
+        Map<String, Set<String>> rpm = populateRegionPackageMap(regionsFile);
+
+        String toglobal = context.getProperty(APIREGIONS_JOINGLOBAL);
+        if (toglobal != null) {
+            joinRegionsWithGlobal(toglobal, rpm);
+            regProps.put(APIREGIONS_JOINGLOBAL, toglobal);
+        }
+
+        String defRegProp = context.getProperty(DEFAULT_REGIONS);
+        if (defRegProp != null) {
+            Set<String> defRegs = new HashSet<>();
+            for (String region : Arrays.asList(defRegProp.split(","))) {
+                if (region.length() > 0) {
+                    defRegs.add(region);
+                }
+            }
+            defaultRegions = Collections.unmodifiableSet(defRegs);
+            if (defaultRegions.size() > 0) {
+                regProps.put(DEFAULT_REGIONS, defaultRegions.toString());
+            }
+        } else {
+            defaultRegions = Collections.emptySet();
+        }
+
+        // Make all maps and their contents unmodifiable
+        bsnVerMap = unmodifiableMapToList(bvm);
+        bundleFeatureMap = unmodifiableMapToSet(bfm);
+        featureRegionMap = unmodifiableMapToSet(frm);
+        regionPackageMap = unmodifiableMapToSet(rpm);
+    }
+
+    private static <K,V> Map<K, List<V>> unmodifiableMapToList(Map<K, List<V>> m) {
+        for (Map.Entry<K, List<V>> entry : m.entrySet()) {
+            m.put(entry.getKey(), Collections.unmodifiableList(entry.getValue()));
+        }
+        return Collections.unmodifiableMap(m);
+    }
+
+    private static <K,V> Map<K, Set<V>> unmodifiableMapToSet(Map<K, Set<V>> m) {
+        for (Map.Entry<K, Set<V>> entry : m.entrySet()) {
+            m.put(entry.getKey(), Collections.unmodifiableSet(entry.getValue()));
+        }
+        return Collections.unmodifiableMap(m);
+    }
+
+    private void joinRegionsWithGlobal(String toglobal, Map<String, Set<String>> rpm) {
+        for (String region : toglobal.split(",")) {
+            Set<String> packages = rpm.get(region);
+            if (packages == null)
+                continue;
+
+            addValuesToMap(rpm, GLOBAL_REGION, packages);
+            rpm.remove(region);
+        }
+    }
+
+    private static Map<Map.Entry<String, Version>, List<String>> populateBSNVerMap(URI idbsnverFile) throws IOException {
+        Map<Map.Entry<String, Version>, List<String>> m = new HashMap<>();
+
+        Properties p = new Properties();
+        try (InputStream is = idbsnverFile.toURL().openStream()) {
+            p.load(is);
+        }
+
+        for (String n : p.stringPropertyNames()) {
+            String[] bsnver = p.getProperty(n).split("~");
+            addBsnVerArtifact(m, bsnver[0], bsnver[1], n);
+        }
+
+        return m;
+    }
+
+    private static void addBsnVerArtifact(
+            Map<Map.Entry<String, Version>, List<String>> bsnVerMap,
+            String bundleSymbolicName, String bundleVersion,
+            String artifactId) {
+        Version version = Version.valueOf(bundleVersion);
+        Map.Entry<String, Version> bsnVer = new AbstractMap.SimpleEntry<>(bundleSymbolicName, version);
+        List<String> l = bsnVerMap.get(bsnVer);
+        if (l == null) {
+            l = new ArrayList<>();
+            bsnVerMap.put(bsnVer, l);
+        }
+        l.add(artifactId);
+    }
+
+    private static Map<String, Set<String>> populateBundleFeatureMap(URI bundlesFile) throws IOException {
+        return loadMap(bundlesFile);
+    }
+
+    private static Map<String, Set<String>> populateFeatureRegionMap(URI featuresFile) throws IOException {
+        return loadMap(featuresFile);
+    }
+
+    private static Map<String, Set<String>> populateRegionPackageMap(URI regionsFile) throws IOException {
+        return loadMap(regionsFile);
+    }
+
+    private static Map<String, Set<String>> loadMap(URI propsFile) throws IOException {
+        Map<String, Set<String>> m = new HashMap<>();
+
+        Properties p = new Properties();
+        try (InputStream is = propsFile.toURL().openStream()) {
+            p.load(is);
+        }
+
+        for (String n : p.stringPropertyNames()) {
+            String[] features = p.getProperty(n).split(",");
+            addValuesToMap(m, n, features);
+        }
+
+        return m;
+    }
+
+    private static void addValuesToMap(Map<String, Set<String>> map, String key, String ... values) {
+        addValuesToMap(map, key, Arrays.asList(values));
+
+    }
+    private static void addValuesToMap(Map<String, Set<String>> map, String key, Collection<String> values) {
+        Set<String> bf = map.get(key);
+        if (bf == null) {
+            bf = new LinkedHashSet<>(); // It's important that the insertion order is maintained.
+            map.put(key, bf);
+        }
+        bf.addAll(values);
+    }
+
+    private URI getDataFileURI(BundleContext ctx, String name) throws IOException, URISyntaxException {
+        String fn = ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + name);
+        if (fn == null) {
+            String loc = ctx.getProperty(PROPERTIES_FILE_LOCATION);
+            if (loc != null) {
+                fn = loc + "/" + name;
+            }
+        }
+
+        if (fn == null)
+            throw new IOException("API Region Enforcement enabled, but no configuration found to find "
+                    + "region definition resource: " + name);
+
+        if (fn.contains(":")) {
+            if (fn.startsWith(CLASSLOADER_PSEUDO_PROTOCOL)) {
+                // It's using the 'classloader:' protocol looks up the location from the classloader
+                String loc = fn.substring(CLASSLOADER_PSEUDO_PROTOCOL.length());
+                if (!loc.startsWith("/"))
+                    loc = "/" + loc;
+                fn = getClass().getResource(loc).toString();
+            }
+            // It's already a URL
+            return new URI(fn);
+        } else {
+            // It's a file location
+            return new File(fn).toURI();
+        }
+    }
+
+    public Map<Map.Entry<String, Version>, List<String>> getBsnVerMap() {
+        return bsnVerMap;
+    }
+
+    public Map<String, Set<String>> getBundleFeatureMap() {
+        return bundleFeatureMap;
+    }
+
+    public Map<String, Set<String>> getFeatureRegionMap() {
+        return featureRegionMap;
+    }
+
+    public Map<String, Set<String>> getRegionPackageMap() {
+        return regionPackageMap;
+    }
+
+    public Set<String> getDefaultRegions() {
+        return defaultRegions;
+    }
+}
diff --git a/src/main/java/org/apache/sling/feature/apiregions/impl/RegionEnforcer.java b/src/main/java/org/apache/sling/feature/apiregions/impl/RegionEnforcer.java
index d1a1f40..74a5ae7 100644
--- a/src/main/java/org/apache/sling/feature/apiregions/impl/RegionEnforcer.java
+++ b/src/main/java/org/apache/sling/feature/apiregions/impl/RegionEnforcer.java
@@ -18,233 +18,25 @@
  */
 package org.apache.sling.feature.apiregions.impl;
 
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Version;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Collection;
+
 import org.osgi.framework.hooks.resolver.ResolverHook;
 import org.osgi.framework.hooks.resolver.ResolverHookFactory;
 import org.osgi.framework.wiring.BundleRevision;
 
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.AbstractMap;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
-import java.util.Set;
-import java.util.logging.Logger;
-
 class RegionEnforcer implements ResolverHookFactory {
-    public static final String GLOBAL_REGION = "global";
 
-    static final String CLASSLOADER_PSEUDO_PROTOCOL = "classloader://";
-    static final String APIREGIONS_JOINGLOBAL = "sling.feature.apiregions.joinglobal";
-    static final String DEFAULT_REGIONS = "sling.feature.apiregions.default";
-    static final String PROPERTIES_RESOURCE_PREFIX = "sling.feature.apiregions.resource.";
-    static final String PROPERTIES_FILE_LOCATION = "sling.feature.apiregions.location";
+    final RegionConfiguration configuration;
 
-    static final String IDBSNVER_FILENAME = "idbsnver.properties";
-    static final String BUNDLE_FEATURE_FILENAME = "bundles.properties";
-    static final String FEATURE_REGION_FILENAME = "features.properties";
-    static final String REGION_PACKAGE_FILENAME = "regions.properties";
-
-    static final Logger LOG = Logger.getLogger(ResolverHookImpl.class.getName());
-
-    final Map<Map.Entry<String, Version>, List<String>> bsnVerMap;
-    final Map<String, Set<String>> bundleFeatureMap;
-    final Map<String, Set<String>> featureRegionMap;
-    final Map<String, Set<String>> regionPackageMap;
-    final Set<String> defaultRegions;
-
-    RegionEnforcer(BundleContext context, Dictionary<String, Object> regProps)
+    RegionEnforcer(RegionConfiguration configuration)
             throws IOException, URISyntaxException {
-        URI idbsnverFile = getDataFileURI(context, IDBSNVER_FILENAME);
-        // Register the location as a service property for diagnostic purposes
-        regProps.put(IDBSNVER_FILENAME, idbsnverFile.toString());
-        Map<Entry<String, Version>, List<String>> bvm = populateBSNVerMap(idbsnverFile);
-
-        URI bundlesFile = getDataFileURI(context, BUNDLE_FEATURE_FILENAME);
-        // Register the location as a service property for diagnostic purposes
-        regProps.put(BUNDLE_FEATURE_FILENAME, bundlesFile.toString());
-        Map<String, Set<String>> bfm = populateBundleFeatureMap(bundlesFile);
-
-        URI featuresFile = getDataFileURI(context, FEATURE_REGION_FILENAME);
-        // Register the location as a service property for diagnostic purposes
-        regProps.put(FEATURE_REGION_FILENAME, featuresFile.toString());
-        Map<String, Set<String>> frm = populateFeatureRegionMap(featuresFile);
-
-        URI regionsFile = getDataFileURI(context, REGION_PACKAGE_FILENAME);
-        // Register the location as a service property for diagnostic purposes
-        regProps.put(REGION_PACKAGE_FILENAME, regionsFile.toString());
-        Map<String, Set<String>> rpm = populateRegionPackageMap(regionsFile);
-
-        String toglobal = context.getProperty(APIREGIONS_JOINGLOBAL);
-        if (toglobal != null) {
-            joinRegionsWithGlobal(toglobal, rpm);
-            regProps.put(APIREGIONS_JOINGLOBAL, toglobal);
-        }
-
-        String defRegProp = context.getProperty(DEFAULT_REGIONS);
-        if (defRegProp != null) {
-            Set<String> defRegs = new HashSet<>();
-            for (String region : Arrays.asList(defRegProp.split(","))) {
-                if (region.length() > 0) {
-                    defRegs.add(region);
-                }
-            }
-            defaultRegions = Collections.unmodifiableSet(defRegs);
-            if (defaultRegions.size() > 0) {
-                regProps.put(DEFAULT_REGIONS, defaultRegions.toString());
-            }
-        } else {
-            defaultRegions = Collections.emptySet();
-        }
-
-        // Make all maps and their contents unmodifiable
-        bsnVerMap = unmodifiableMapToList(bvm);
-        bundleFeatureMap = unmodifiableMapToSet(bfm);
-        featureRegionMap = unmodifiableMapToSet(frm);
-        regionPackageMap = unmodifiableMapToSet(rpm);
-    }
-
-    private static <K,V> Map<K, List<V>> unmodifiableMapToList(Map<K, List<V>> m) {
-        for (Map.Entry<K, List<V>> entry : m.entrySet()) {
-            m.put(entry.getKey(), Collections.unmodifiableList(entry.getValue()));
-        }
-        return Collections.unmodifiableMap(m);
-    }
-
-    private static <K,V> Map<K, Set<V>> unmodifiableMapToSet(Map<K, Set<V>> m) {
-        for (Map.Entry<K, Set<V>> entry : m.entrySet()) {
-            m.put(entry.getKey(), Collections.unmodifiableSet(entry.getValue()));
-        }
-        return Collections.unmodifiableMap(m);
-    }
-
-    private void joinRegionsWithGlobal(String toglobal, Map<String, Set<String>> rpm) {
-        for (String region : toglobal.split(",")) {
-            Set<String> packages = rpm.get(region);
-            if (packages == null)
-                continue;
-
-            addValuesToMap(rpm, GLOBAL_REGION, packages);
-            rpm.remove(region);
-        }
-    }
-
-    private static Map<Map.Entry<String, Version>, List<String>> populateBSNVerMap(URI idbsnverFile) throws IOException {
-        Map<Map.Entry<String, Version>, List<String>> m = new HashMap<>();
-
-        Properties p = new Properties();
-        try (InputStream is = idbsnverFile.toURL().openStream()) {
-            p.load(is);
-        }
-
-        for (String n : p.stringPropertyNames()) {
-            String[] bsnver = p.getProperty(n).split("~");
-            addBsnVerArtifact(m, bsnver[0], bsnver[1], n);
-        }
-
-        return m;
-    }
-
-    private static void addBsnVerArtifact(
-            Map<Map.Entry<String, Version>, List<String>> bsnVerMap,
-            String bundleSymbolicName, String bundleVersion,
-            String artifactId) {
-        Version version = Version.valueOf(bundleVersion);
-        Map.Entry<String, Version> bsnVer = new AbstractMap.SimpleEntry<>(bundleSymbolicName, version);
-        List<String> l = bsnVerMap.get(bsnVer);
-        if (l == null) {
-            l = new ArrayList<>();
-            bsnVerMap.put(bsnVer, l);
-        }
-        l.add(artifactId);
-    }
-
-    private static Map<String, Set<String>> populateBundleFeatureMap(URI bundlesFile) throws IOException {
-        return loadMap(bundlesFile);
-    }
-
-    private static Map<String, Set<String>> populateFeatureRegionMap(URI featuresFile) throws IOException {
-        return loadMap(featuresFile);
-    }
-
-    private static Map<String, Set<String>> populateRegionPackageMap(URI regionsFile) throws IOException {
-        return loadMap(regionsFile);
-    }
-
-    private static Map<String, Set<String>> loadMap(URI propsFile) throws IOException {
-        Map<String, Set<String>> m = new HashMap<>();
-
-        Properties p = new Properties();
-        try (InputStream is = propsFile.toURL().openStream()) {
-            p.load(is);
-        }
-
-        for (String n : p.stringPropertyNames()) {
-            String[] features = p.getProperty(n).split(",");
-            addValuesToMap(m, n, features);
-        }
-
-        return m;
-    }
-
-    private static void addValuesToMap(Map<String, Set<String>> map, String key, String ... values) {
-        addValuesToMap(map, key, Arrays.asList(values));
-
-    }
-    private static void addValuesToMap(Map<String, Set<String>> map, String key, Collection<String> values) {
-        Set<String> bf = map.get(key);
-        if (bf == null) {
-            bf = new LinkedHashSet<>(); // It's important that the insertion order is maintained.
-            map.put(key, bf);
-        }
-        bf.addAll(values);
-    }
-
-    private URI getDataFileURI(BundleContext ctx, String name) throws IOException, URISyntaxException {
-        String fn = ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + name);
-        if (fn == null) {
-            String loc = ctx.getProperty(PROPERTIES_FILE_LOCATION);
-            if (loc != null) {
-                fn = loc + "/" + name;
-            }
-        }
-
-        if (fn == null)
-            throw new IOException("API Region Enforcement enabled, but no configuration found to find "
-                    + "region definition resource: " + name);
-
-        if (fn.contains(":")) {
-            if (fn.startsWith(CLASSLOADER_PSEUDO_PROTOCOL)) {
-                // It's using the 'classloader:' protocol looks up the location from the classloader
-                String loc = fn.substring(CLASSLOADER_PSEUDO_PROTOCOL.length());
-                if (!loc.startsWith("/"))
-                    loc = "/" + loc;
-                fn = getClass().getResource(loc).toString();
-            }
-            // It's already a URL
-            return new URI(fn);
-        } else {
-            // It's a file location
-            return new File(fn).toURI();
-        }
+        this.configuration = configuration;
     }
 
     @Override
     public ResolverHook begin(Collection<BundleRevision> triggers) {
-        return new ResolverHookImpl(bsnVerMap, bundleFeatureMap, featureRegionMap, regionPackageMap, defaultRegions);
+        return new ResolverHookImpl(this.configuration);
     }
 }
diff --git a/src/main/java/org/apache/sling/feature/apiregions/impl/ResolverHookImpl.java b/src/main/java/org/apache/sling/feature/apiregions/impl/ResolverHookImpl.java
index 2164a86..3c1f4b3 100644
--- a/src/main/java/org/apache/sling/feature/apiregions/impl/ResolverHookImpl.java
+++ b/src/main/java/org/apache/sling/feature/apiregions/impl/ResolverHookImpl.java
@@ -18,14 +18,6 @@
  */
 package org.apache.sling.feature.apiregions.impl;
 
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Version;
-import org.osgi.framework.hooks.resolver.ResolverHook;
-import org.osgi.framework.namespace.PackageNamespace;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRequirement;
-import org.osgi.framework.wiring.BundleRevision;
-
 import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -35,24 +27,23 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 import java.util.logging.Level;
 
-class ResolverHookImpl implements ResolverHook {
-    final Map<Map.Entry<String, Version>, List<String>> bsnVerMap;
-    final Map<String, Set<String>> bundleFeatureMap;
-    final Map<String, Set<String>> featureRegionMap;
-    final Map<String, Set<String>> regionPackageMap;
-    final Set<String> defaultRegions;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+import org.osgi.framework.hooks.resolver.ResolverHook;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRequirement;
+import org.osgi.framework.wiring.BundleRevision;
 
-    ResolverHookImpl(Map<Entry<String, Version>, List<String>> bsnVerMap, Map<String, Set<String>> bundleFeatureMap,
-            Map<String, Set<String>> featureRegionMap, Map<String, Set<String>> regionPackageMap, Set<String> defaultRegions) {
-        this.bsnVerMap = bsnVerMap;
-        this.bundleFeatureMap = bundleFeatureMap;
-        this.featureRegionMap = featureRegionMap;
-        this.regionPackageMap = regionPackageMap;
-        this.defaultRegions = defaultRegions;
+class ResolverHookImpl implements ResolverHook {
+
+    final RegionConfiguration configuration;
+
+    ResolverHookImpl(RegionConfiguration cfg) {
+        this.configuration = cfg;
     }
 
     @Override
@@ -76,18 +67,18 @@
         String reqBundleName = reqBundle.getSymbolicName();
         Version reqBundleVersion = reqBundle.getVersion();
 
-        Set<String> reqRegions = new HashSet<>(defaultRegions);
+        Set<String> reqRegions = new HashSet<>(this.configuration.getDefaultRegions());
         List<String> reqFeatures = new ArrayList<>();
-        List<String> aids = bsnVerMap.get(new AbstractMap.SimpleEntry<String, Version>(reqBundleName, reqBundleVersion));
+        List<String> aids = this.configuration.getBsnVerMap().get(new AbstractMap.SimpleEntry<String, Version>(reqBundleName, reqBundleVersion));
         if (aids != null) {
             for (String aid : aids) {
-                Set<String> fid = bundleFeatureMap.get(aid);
+                Set<String> fid = this.configuration.getBundleFeatureMap().get(aid);
                 if (fid != null)
                     reqFeatures.addAll(fid);
             }
 
             for (String feature : reqFeatures) {
-                Set<String> fr = featureRegionMap.get(feature);
+                Set<String> fr = this.configuration.getFeatureRegionMap().get(feature);
                 if (fr != null) {
                     reqRegions.addAll(fr);
                 }
@@ -121,16 +112,16 @@
             String capBundleName = capBundle.getSymbolicName();
             Version capBundleVersion = capBundle.getVersion();
 
-            List<String> capBundleArtifacts = bsnVerMap.get(new AbstractMap.SimpleEntry<String, Version>(capBundleName, capBundleVersion));
+            List<String> capBundleArtifacts = this.configuration.getBsnVerMap().get(new AbstractMap.SimpleEntry<String, Version>(capBundleName, capBundleVersion));
             if (capBundleArtifacts == null) {
                 // Capability is not in any feature, everyone can access
-                coveredCaps.put(bc, RegionEnforcer.GLOBAL_REGION);
+                coveredCaps.put(bc, RegionConfiguration.GLOBAL_REGION);
                 continue nextCapability;
             }
 
             List<String> capFeatures = new ArrayList<>();
             for (String ba : capBundleArtifacts) {
-                Set<String> capfeats = bundleFeatureMap.get(ba);
+                Set<String> capfeats = this.configuration.getBundleFeatureMap().get(ba);
                 if (capfeats != null)
                     capFeatures.addAll(capfeats);
             }
@@ -141,7 +132,7 @@
             for (String capFeat : capFeatures) {
                 if (capFeat == null) {
                     // everyone can access capability not coming from a feature
-                    coveredCaps.put(bc, RegionEnforcer.GLOBAL_REGION);
+                    coveredCaps.put(bc, RegionConfiguration.GLOBAL_REGION);
                     continue nextCapability;
                 }
 
@@ -151,10 +142,10 @@
                     continue nextCapability;
                 }
 
-                Set<String> capRegions = featureRegionMap.get(capFeat);
+                Set<String> capRegions = this.configuration.getFeatureRegionMap().get(capFeat);
                 if (capRegions == null || capRegions.size() == 0) {
                     // If the feature hosting the capability has no regions defined, everyone can access
-                    coveredCaps.put(bc, RegionEnforcer.GLOBAL_REGION);
+                    coveredCaps.put(bc, RegionConfiguration.GLOBAL_REGION);
                     continue nextCapability;
                 }
                 bcFeatureMap.put(bc, capFeat);
@@ -168,7 +159,7 @@
 
                     // Look at specific regions first as they take precedence over the global region
                     for (String region : sharedRegions) {
-                        Set<String> regionPackages = regionPackageMap.get(region);
+                        Set<String> regionPackages = this.configuration.getRegionPackageMap().get(region);
                         if (regionPackages != null && regionPackages.contains(packageName)) {
                             // If the export is in a region that the feature is also in, then allow
                             coveredCaps.put(bc, region);
@@ -177,10 +168,10 @@
                     }
 
                     // Now check the global region
-                    Set<String> globalPackages = regionPackageMap.get(RegionEnforcer.GLOBAL_REGION);
+                    Set<String> globalPackages = this.configuration.getRegionPackageMap().get(RegionConfiguration.GLOBAL_REGION);
                     if (globalPackages != null && globalPackages.contains(packageName)) {
                         // If the export is in the global region everyone can access
-                        coveredCaps.put(bc, RegionEnforcer.GLOBAL_REGION);
+                        coveredCaps.put(bc, RegionConfiguration.GLOBAL_REGION);
                         continue nextCapability;
                     }
                 }
@@ -213,7 +204,7 @@
                 sb.append("]");
             }
 
-            RegionEnforcer.LOG.log(Level.WARNING,
+            Activator.LOG.log(Level.WARNING,
                     "API-Regions removed candidates {0} for requirement {1} as the requirement is in the following regions: {2} and in feature: {3}",
                     new Object[] {sb, requirement, reqRegions, reqFeatures});
         }
@@ -229,7 +220,7 @@
      */
     private void pruneCoveredCaps(Set<String> reqRegions, Map<BundleCapability,String> capMap) {
         Set<String> reqNonGlobalRegions = new HashSet<>(reqRegions);
-        reqNonGlobalRegions.remove(RegionEnforcer.GLOBAL_REGION);
+        reqNonGlobalRegions.remove(RegionConfiguration.GLOBAL_REGION);
 
         if (capMap.size() <= 1) {
             // Shortcut: there is only 0 or 1 capability, nothing to do
@@ -237,7 +228,7 @@
         }
 
         if (reqRegions.size() == 0
-                || Collections.singleton(RegionEnforcer.GLOBAL_REGION).equals(reqRegions)) {
+                || Collections.singleton(RegionConfiguration.GLOBAL_REGION).equals(reqRegions)) {
             // No regions (other than global) for the requirement: do nothing
             return;
         }
@@ -278,13 +269,13 @@
         if (packageName == null)
             return Collections.emptyList();
 
-        Set<String> regions = featureRegionMap.get(feature);
+        Set<String> regions = this.configuration.getFeatureRegionMap().get(feature);
         if (regions == null)
             return Collections.emptyList();
 
         List<String> res = new ArrayList<>();
         for (String region : regions) {
-            Set<String> packages = regionPackageMap.get(region);
+            Set<String> packages = this.configuration.getRegionPackageMap().get(region);
             if (packages == null)
                 continue;
 
diff --git a/src/test/java/org/apache/sling/feature/apiregions/impl/ActivatorTest.java b/src/test/java/org/apache/sling/feature/apiregions/impl/ActivatorTest.java
index 7deb0ea..94b639b 100644
--- a/src/test/java/org/apache/sling/feature/apiregions/impl/ActivatorTest.java
+++ b/src/test/java/org/apache/sling/feature/apiregions/impl/ActivatorTest.java
@@ -18,6 +18,24 @@
  */
 package org.apache.sling.feature.apiregions.impl;
 
+import static org.apache.sling.feature.apiregions.impl.RegionConfiguration.BUNDLE_FEATURE_FILENAME;
+import static org.apache.sling.feature.apiregions.impl.RegionConfiguration.FEATURE_REGION_FILENAME;
+import static org.apache.sling.feature.apiregions.impl.RegionConfiguration.IDBSNVER_FILENAME;
+import static org.apache.sling.feature.apiregions.impl.RegionConfiguration.PROPERTIES_RESOURCE_PREFIX;
+import static org.apache.sling.feature.apiregions.impl.RegionConfiguration.REGION_PACKAGE_FILENAME;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Properties;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -37,24 +55,6 @@
 import org.osgi.resource.Requirement;
 import org.osgi.service.cm.ManagedService;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Properties;
-
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.BUNDLE_FEATURE_FILENAME;
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.FEATURE_REGION_FILENAME;
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.IDBSNVER_FILENAME;
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.PROPERTIES_RESOURCE_PREFIX;
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.REGION_PACKAGE_FILENAME;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
 public class ActivatorTest {
     private Properties savedProps;
 
@@ -185,7 +185,7 @@
         BundleContext bc = Mockito.mock(BundleContext.class);
         Mockito.when(bc.getBundle()).thenReturn(fw);
         Mockito.when(bc.getProperty(Activator.REGIONS_PROPERTY_NAME)).thenReturn("*");
-        Mockito.when(bc.getProperty(RegionEnforcer.PROPERTIES_FILE_LOCATION)).thenReturn(resourceDir);
+        Mockito.when(bc.getProperty(RegionConfiguration.PROPERTIES_FILE_LOCATION)).thenReturn(resourceDir);
         Mockito.when(bc.registerService(
             Mockito.eq("org.osgi.service.cm.ManagedService"),
             Mockito.any(),
diff --git a/src/test/java/org/apache/sling/feature/apiregions/impl/RegionEnforcerTest.java b/src/test/java/org/apache/sling/feature/apiregions/impl/RegionConfigurationTest.java
similarity index 82%
rename from src/test/java/org/apache/sling/feature/apiregions/impl/RegionEnforcerTest.java
rename to src/test/java/org/apache/sling/feature/apiregions/impl/RegionConfigurationTest.java
index ac1d77d..218bfeb 100644
--- a/src/test/java/org/apache/sling/feature/apiregions/impl/RegionEnforcerTest.java
+++ b/src/test/java/org/apache/sling/feature/apiregions/impl/RegionConfigurationTest.java
@@ -18,11 +18,17 @@
  */
 package org.apache.sling.feature.apiregions.impl;
 
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Version;
-import org.osgi.framework.hooks.resolver.ResolverHook;
+import static org.apache.sling.feature.apiregions.impl.RegionConfiguration.APIREGIONS_JOINGLOBAL;
+import static org.apache.sling.feature.apiregions.impl.RegionConfiguration.BUNDLE_FEATURE_FILENAME;
+import static org.apache.sling.feature.apiregions.impl.RegionConfiguration.DEFAULT_REGIONS;
+import static org.apache.sling.feature.apiregions.impl.RegionConfiguration.FEATURE_REGION_FILENAME;
+import static org.apache.sling.feature.apiregions.impl.RegionConfiguration.IDBSNVER_FILENAME;
+import static org.apache.sling.feature.apiregions.impl.RegionConfiguration.PROPERTIES_FILE_LOCATION;
+import static org.apache.sling.feature.apiregions.impl.RegionConfiguration.PROPERTIES_RESOURCE_PREFIX;
+import static org.apache.sling.feature.apiregions.impl.RegionConfiguration.REGION_PACKAGE_FILENAME;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
 import java.io.IOException;
@@ -38,26 +44,20 @@
 import java.util.Map;
 import java.util.Set;
 
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.APIREGIONS_JOINGLOBAL;
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.BUNDLE_FEATURE_FILENAME;
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.DEFAULT_REGIONS;
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.FEATURE_REGION_FILENAME;
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.IDBSNVER_FILENAME;
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.PROPERTIES_FILE_LOCATION;
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.PROPERTIES_RESOURCE_PREFIX;
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.REGION_PACKAGE_FILENAME;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Version;
+import org.osgi.framework.hooks.resolver.ResolverHook;
 
-public class RegionEnforcerTest {
+public class RegionConfigurationTest {
     @Test
-    public void testRegionEnforcerNoConfiguration() throws Exception {
+    public void testRegionConfigurationNoConfiguration() throws Exception {
         BundleContext ctx = Mockito.mock(BundleContext.class);
 
         try {
-            new RegionEnforcer(ctx, new Hashtable<String, Object>());
-            fail("Expected exception. Enforcer is enabled but is missing configuration");
+            new RegionConfiguration(ctx, new Hashtable<String, Object>());
+            fail("Expected exception. Configuration is enabled but is missing configuration");
         } catch (Exception e) {
             // good
         }
@@ -74,7 +74,7 @@
         Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(e);
 
         Hashtable<String, Object> props = new Hashtable<>();
-        RegionEnforcer re = new RegionEnforcer(ctx, props);
+        RegionConfiguration re = new RegionConfiguration(ctx, props);
         assertEquals(2, re.bsnVerMap.size());
         assertEquals(Collections.singletonList("g:b1:1"),
                 re.bsnVerMap.get(new AbstractMap.SimpleEntry<String,Version>("b1", new Version(1,0,0))));
@@ -94,7 +94,7 @@
         Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(e);
 
         Hashtable<String, Object> props = new Hashtable<>();
-        RegionEnforcer re = new RegionEnforcer(ctx, props);
+        RegionConfiguration re = new RegionConfiguration(ctx, props);
         assertEquals(3, re.bundleFeatureMap.size());
         assertEquals(Collections.singleton("org.sling:something:1.2.3:slingosgifeature:myclassifier"),
                 re.bundleFeatureMap.get("org.sling:b1:1"));
@@ -116,7 +116,7 @@
         Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(e);
 
         Hashtable<String, Object> props = new Hashtable<>();
-        RegionEnforcer re = new RegionEnforcer(ctx, props);
+        RegionConfiguration re = new RegionConfiguration(ctx, props);
         assertEquals(2, re.featureRegionMap.size());
         assertEquals(Collections.singleton("global"),
                 re.featureRegionMap.get("an.other:feature:123"));
@@ -136,7 +136,7 @@
         Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(f);
 
         Hashtable<String, Object> props = new Hashtable<>();
-        RegionEnforcer re = new RegionEnforcer(ctx, props);
+        RegionConfiguration re = new RegionConfiguration(ctx, props);
         assertEquals(2, re.regionPackageMap.size());
         assertEquals(Collections.singleton("xyz"),
                 re.regionPackageMap.get("internal"));
@@ -156,7 +156,7 @@
         Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).thenReturn(e);
         Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(f);
 
-        RegionEnforcer re = new RegionEnforcer(ctx, new Hashtable<String, Object>());
+        RegionConfiguration re = new RegionConfiguration(ctx, new Hashtable<String, Object>());
         assertEquals(1, re.regionPackageMap.size());
         assertEquals(new HashSet<>(Arrays.asList("xyz", "a.b.c", "d.e.f", "test")),
                 re.regionPackageMap.get("global"));
@@ -174,17 +174,17 @@
         Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).
             thenReturn(getClass().getResource("/regions1.properties").getFile());
 
-        RegionEnforcer re = new RegionEnforcer(ctx, new Hashtable<String, Object>());
+        RegionConfiguration re = new RegionConfiguration(ctx, new Hashtable<String, Object>());
         assertTrue(re.bsnVerMap.size() > 0);
         assertTrue(re.bundleFeatureMap.size() > 0);
         assertTrue(re.featureRegionMap.size() > 0);
         assertTrue(re.regionPackageMap.size() > 0);
 
-        ResolverHookImpl hook = (ResolverHookImpl) re.begin(null);
-        assertEquals(re.bsnVerMap, hook.bsnVerMap);
-        assertEquals(re.bundleFeatureMap, hook.bundleFeatureMap);
-        assertEquals(re.featureRegionMap, hook.featureRegionMap);
-        assertEquals(re.regionPackageMap, hook.regionPackageMap);
+        ResolverHookImpl hook = (ResolverHookImpl) new RegionEnforcer(re).begin(null);
+        assertEquals(re.bsnVerMap, hook.configuration.bsnVerMap);
+        assertEquals(re.bundleFeatureMap, hook.configuration.bundleFeatureMap);
+        assertEquals(re.featureRegionMap, hook.configuration.featureRegionMap);
+        assertEquals(re.regionPackageMap, hook.configuration.regionPackageMap);
     }
 
     @Test
@@ -194,7 +194,7 @@
                 getFile()).getParentFile().toURI().toString();
         Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).thenReturn(location);
 
-        RegionEnforcer re = new RegionEnforcer(ctx, new Hashtable<String, Object>());
+        RegionConfiguration re = new RegionConfiguration(ctx, new Hashtable<String, Object>());
         assertTrue(re.bsnVerMap.size() > 0);
         assertTrue(re.bundleFeatureMap.size() > 0);
         assertTrue(re.featureRegionMap.size() > 0);
@@ -207,7 +207,7 @@
         Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).
             thenReturn("classloader://props1");
 
-        RegionEnforcer re = new RegionEnforcer(ctx, new Hashtable<String, Object>());
+        RegionConfiguration re = new RegionConfiguration(ctx, new Hashtable<String, Object>());
         assertTrue(re.bsnVerMap.size() > 0);
         assertTrue(re.bundleFeatureMap.size() > 0);
         assertTrue(re.featureRegionMap.size() > 0);
@@ -220,7 +220,7 @@
         Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).
             thenReturn("classloader://props2");
 
-        RegionEnforcer re = new RegionEnforcer(ctx, new Hashtable<String, Object>());
+        RegionConfiguration re = new RegionConfiguration(ctx, new Hashtable<String, Object>());
         assertEquals(Arrays.asList("r0", "r1", "r2", "r3"),
                 new ArrayList<>(re.featureRegionMap.get("org.sling:something:1.2.3")));
     }
@@ -231,7 +231,7 @@
         Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).
             thenReturn("classloader://props1");
 
-        RegionEnforcer re = new RegionEnforcer(ctx, new Hashtable<String, Object>());
+        RegionConfiguration re = new RegionConfiguration(ctx, new Hashtable<String, Object>());
         assertTrue(re.bsnVerMap.size() > 0);
         assertBSNVerMapUnmodifiable(re.bsnVerMap);
         assertTrue(re.bundleFeatureMap.size() > 0);
@@ -250,7 +250,6 @@
         testDefaultRegions(null, Collections.emptySet());
     }
 
-    @SuppressWarnings("unchecked")
     private void testDefaultRegions(String defProp, Set<String> expected)
             throws IOException, URISyntaxException, NoSuchFieldException, IllegalAccessException {
         BundleContext ctx = Mockito.mock(BundleContext.class);
@@ -258,12 +257,12 @@
         Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).
         thenReturn("classloader://props1");
 
-        RegionEnforcer re = new RegionEnforcer(ctx, new Hashtable<String, Object>());
-        ResolverHook hook = re.begin(Collections.emptySet());
-        Field f = ResolverHookImpl.class.getDeclaredField("defaultRegions");
+        RegionConfiguration re = new RegionConfiguration(ctx, new Hashtable<String, Object>());
+        ResolverHook hook = new RegionEnforcer(re).begin(Collections.emptySet());
+        Field f = ResolverHookImpl.class.getDeclaredField("configuration");
         f.setAccessible(true);
 
-        assertEquals(expected, f.get(hook));
+        assertEquals(expected, ((RegionConfiguration)f.get(hook)).getDefaultRegions());
     }
 
     private void assertBSNVerMapUnmodifiable(Map<Map.Entry<String, Version>, List<String>> m) {
diff --git a/src/test/java/org/apache/sling/feature/apiregions/impl/ResolverHookImplTest.java b/src/test/java/org/apache/sling/feature/apiregions/impl/ResolverHookImplTest.java
index 9768cdf..ebec9e1 100644
--- a/src/test/java/org/apache/sling/feature/apiregions/impl/ResolverHookImplTest.java
+++ b/src/test/java/org/apache/sling/feature/apiregions/impl/ResolverHookImplTest.java
@@ -18,14 +18,7 @@
  */
 package org.apache.sling.feature.apiregions.impl;
 
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Version;
-import org.osgi.framework.namespace.PackageNamespace;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleRequirement;
-import org.osgi.framework.wiring.BundleRevision;
+import static org.junit.Assert.assertEquals;
 
 import java.util.AbstractMap;
 import java.util.ArrayList;
@@ -39,7 +32,14 @@
 import java.util.Map.Entry;
 import java.util.Set;
 
-import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRequirement;
+import org.osgi.framework.wiring.BundleRevision;
 
 public class ResolverHookImplTest {
     @Test
@@ -59,7 +59,7 @@
 
         Map<String, Set<String>> rpmap = new HashMap<>();
 
-        ResolverHookImpl rh = new ResolverHookImpl(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("*"));
+        ResolverHookImpl rh = new ResolverHookImpl(new RegionConfiguration(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("*")));
 
         // b2 is in r2, it requires a capability that is provided by b1.
         // b1 is in a feature, but that feature is not in any region so it can provide access.
@@ -86,7 +86,7 @@
 
         Map<String, Set<String>> rpmap = new HashMap<>();
 
-        ResolverHookImpl rh = new ResolverHookImpl(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global"));
+        ResolverHookImpl rh = new ResolverHookImpl(new RegionConfiguration(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global")));
 
         // b2 is in r2, it requires a capability that is provided by b1.
         // b1 is not in any feature so it can provide access.
@@ -115,7 +115,7 @@
 
         Map<String, Set<String>> rpmap = new HashMap<>();
 
-        ResolverHookImpl rh = new ResolverHookImpl(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global"));
+        ResolverHookImpl rh = new ResolverHookImpl(new RegionConfiguration(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global")));
 
         // b2 is in r2, it requires a capability that is provided by b1.
         // b1 is in a feature that has an empty region set, any region so it can provide access.
@@ -144,7 +144,7 @@
 
         Map<String, Set<String>> rpmap = new HashMap<>();
 
-        ResolverHookImpl rh = new ResolverHookImpl(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global"));
+        ResolverHookImpl rh = new ResolverHookImpl(new RegionConfiguration(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global")));
 
         // b2 is in r2, it requires a capability that is provided by b1.
         // b1 is also in r2 but is not exporting the package in there, so b2 should not see the package.
@@ -183,7 +183,7 @@
         rpmap.put("r2", new HashSet<>(Arrays.asList("xxx", "yyy", "zzz")));
         rpmap.put("r3", new HashSet<>(Arrays.asList("org.foo.bar", "zzz")));
 
-        ResolverHookImpl rh = new ResolverHookImpl(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global"));
+        ResolverHookImpl rh = new ResolverHookImpl(new RegionConfiguration(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global")));
 
         // b2 needs to resolve to 'org.foo.bar' package. b2 is in region r1.
         // The package is provided by 3 bundles:
@@ -224,7 +224,7 @@
         Map<String, Set<String>> rpmap = new HashMap<>();
         rpmap.put("r1", Collections.emptySet());
 
-        ResolverHookImpl rh = new ResolverHookImpl(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global"));
+        ResolverHookImpl rh = new ResolverHookImpl(new RegionConfiguration(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global")));
 
         // b2 needs to resolve 'org.foo.bar' and there are 2 candidates:
         // b11 is in the same feature as b2
@@ -265,7 +265,7 @@
         rpmap.put("r2", new HashSet<>(Arrays.asList("xxx", "yyy", "zzz")));
         rpmap.put("r3", new HashSet<>(Arrays.asList("org.foo.bar", "zzz")));
 
-        ResolverHookImpl rh = new ResolverHookImpl(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global"));
+        ResolverHookImpl rh = new ResolverHookImpl(new RegionConfiguration(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global")));
 
         // b2 needs to resolve to 'org.foo.bar' package. b2 is in region r1.
         // However nobody in r1 exports the package
@@ -298,7 +298,7 @@
         Map<String, Set<String>> frmap = new HashMap<>();
         Map<String, Set<String>> rpmap = new HashMap<>();
 
-        ResolverHookImpl rh = new ResolverHookImpl(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global"));
+        ResolverHookImpl rh = new ResolverHookImpl(new RegionConfiguration(bsnvermap, bfmap, frmap, rpmap, Collections.singleton("global")));
 
         // b2 needs to resolve to 'org.foo.bar' package. b2 is in no region.
         // b18 and b19 export the package in the global region. They should both be allowed.
@@ -345,7 +345,7 @@
         bfmap.put("b20", Collections.singleton("f4"));
 
         Map<String, Set<String>> frmap = new HashMap<>();
-        frmap.put("f", new HashSet<>(Arrays.asList("r1", "r2", RegionEnforcer.GLOBAL_REGION)));
+        frmap.put("f", new HashSet<>(Arrays.asList("r1", "r2", RegionConfiguration.GLOBAL_REGION)));
         frmap.put("f1", Collections.singleton("r1"));
         frmap.put("f2", Collections.singleton("r2"));
         frmap.put("f3", Collections.singleton("r3"));
@@ -354,10 +354,10 @@
         Map<String, Set<String>> rpmap = new HashMap<>();
         rpmap.put("r0", Collections.singleton("org.bar"));
         rpmap.put("r1", new HashSet<>(Arrays.asList("org.blah", "org.foo")));
-        rpmap.put(RegionEnforcer.GLOBAL_REGION, Collections.singleton("org.bar.tar"));
+        rpmap.put(RegionConfiguration.GLOBAL_REGION, Collections.singleton("org.bar.tar"));
         rpmap.put("r3", Collections.singleton("xyz"));
 
-        ResolverHookImpl rh = new ResolverHookImpl(bsnvermap, bfmap, frmap, rpmap, Collections.emptySet());
+        ResolverHookImpl rh = new ResolverHookImpl(new RegionConfiguration(bsnvermap, bfmap, frmap, rpmap, Collections.emptySet()));
 
         // Check that we can get the capability from another bundle in the same region
         // where that region exports the package
@@ -485,16 +485,16 @@
 
         Map<String, Set<String>> frmap = new HashMap<>();
         frmap.put("f1", new HashSet<>(Arrays.asList(
-                RegionEnforcer.GLOBAL_REGION, "org.foo.blah")));
+                RegionConfiguration.GLOBAL_REGION, "org.foo.blah")));
         frmap.put("f2", new HashSet<>(Arrays.asList("org.foo.bar",
-                RegionEnforcer.GLOBAL_REGION, "org.foo.blah")));
+                RegionConfiguration.GLOBAL_REGION, "org.foo.blah")));
 
         Map<String, Set<String>> rpmap = new HashMap<>();
         rpmap.put("org.foo.bar", Collections.singleton("org.test"));
-        rpmap.put(RegionEnforcer.GLOBAL_REGION, Collections.singleton("org.something"));
+        rpmap.put(RegionConfiguration.GLOBAL_REGION, Collections.singleton("org.something"));
         rpmap.put("org.foo.blah", Collections.singleton("org.something"));
 
-        ResolverHookImpl rh = new ResolverHookImpl(bsnvermap, bfmap, frmap, rpmap, Collections.emptySet());
+        ResolverHookImpl rh = new ResolverHookImpl(new RegionConfiguration(bsnvermap, bfmap, frmap, rpmap, Collections.emptySet()));
 
         BundleRequirement req0 = mockRequirement("b1", bsnvermap);
         BundleCapability cap0 = mockCapability("org.test", "b2", bsnvermap);
@@ -516,8 +516,8 @@
         regionPackageMap.put("r3", pkgs);
 
         ResolverHookImpl rh = new ResolverHookImpl(
-                Collections.<Map.Entry<String, Version>, List<String>>emptyMap(),
-                Collections.<String, Set<String>>emptyMap(), featureRegionMap, regionPackageMap, Collections.emptySet());
+                new RegionConfiguration(Collections.<Map.Entry<String, Version>, List<String>>emptyMap(),
+                Collections.<String, Set<String>>emptyMap(), featureRegionMap, regionPackageMap, Collections.emptySet()));
 
         assertEquals(Collections.emptyList(), rh.getRegionsForPackage(null, "f1"));
         assertEquals(Collections.emptyList(), rh.getRegionsForPackage("org.foo", "f1"));
@@ -550,8 +550,8 @@
         rpmap.put("r1", Collections.singleton("org.test"));
         rpmap.put("r2", Collections.singleton("org.test"));
 
-        ResolverHookImpl rh = new ResolverHookImpl(bsnvermap, bfmap, frmap, rpmap,
-                new HashSet<>(Arrays.asList("r1", "r3")));
+        ResolverHookImpl rh = new ResolverHookImpl(new RegionConfiguration(bsnvermap, bfmap, frmap, rpmap,
+                new HashSet<>(Arrays.asList("r1", "r3"))));
 
         // b99 is not in any region itself and tries to resolve to b100 which is in r1
         // b99 can resolve to b100 because 'r1' is listed as a default region in the