You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by da...@apache.org on 2019/02/08 21:20:57 UTC

[sling-org-apache-sling-feature-apiregions] branch master updated: Support looking up properties resources via class loader and from URLs

This is an automated email from the ASF dual-hosted git repository.

davidb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-apiregions.git


The following commit(s) were added to refs/heads/master by this push:
     new 6a0cab1  Support looking up properties resources via class loader and from URLs
6a0cab1 is described below

commit 6a0cab13efa07ca2e754f20b84828916d8996e94
Author: David Bosschaert <bo...@adobe.com>
AuthorDate: Fri Feb 8 13:19:29 2019 -0800

    Support looking up properties resources via class loader and from URLs
    
    A new framework property 'sling.feature.apiregions.location' is
    introduced to identify the directory where the apiregions properties
    files can be found.
    The system property prefix 'apiregions.' has been changed to
    'sling.feature.apiregions.resource.'
    Both properties now support URLs as well as file paths. Additionally,
    the 'classpath://' URL pseudo-protocol is introduced which looks up the
    location provided using the classloader’s getResource().
---
 pom.xml                                            |   1 +
 .../sling/feature/apiregions/impl/Activator.java   |   2 +-
 .../feature/apiregions/impl/RegionEnforcer.java    | 136 +++++++++++++--------
 .../feature/apiregions/impl/ActivatorTest.java     |   8 +-
 .../apiregions/impl/RegionEnforcerTest.java        | 102 +++++++++-------
 src/test/resources/props1/bundles.properties       |   5 +
 src/test/resources/props1/features.properties      |   4 +
 src/test/resources/props1/idbsnver.properties      |   6 +
 src/test/resources/props1/regions.properties       |   4 +
 9 files changed, 171 insertions(+), 97 deletions(-)

diff --git a/pom.xml b/pom.xml
index c4c8c1c..abeb95e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,6 +64,7 @@
                     <excludes>
                         <exclude>*.md</exclude>
                         <exclude>src/test/resources/*</exclude>
+                        <exclude>src/test/resources/props1/*</exclude>
                     </excludes>
                 </configuration>
             </plugin>
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 95f5cc7..8064b02 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
@@ -35,7 +35,7 @@ public class Activator implements BundleActivator {
             return; // Component not enabled
 
         Dictionary<String, Object> props = new Hashtable<>();
-        RegionEnforcer enforcer = new RegionEnforcer(props, regions);
+        RegionEnforcer enforcer = new RegionEnforcer(context, props, regions);
         context.registerService(ResolverHookFactory.class, enforcer, props);
     }
 
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 cf20e0d..7ab5bca 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,15 +18,17 @@
  */
 package org.apache.sling.feature.apiregions.impl;
 
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.Version;
 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.FileInputStream;
 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;
@@ -41,9 +43,13 @@ import java.util.Properties;
 import java.util.Set;
 
 class RegionEnforcer implements ResolverHookFactory {
-    public static String GLOBAL_REGION = "global";
+    private static final String CLASSLOADER_PSEUDO_PROTOCOL = "classloader://";
+
+    public static final String GLOBAL_REGION = "global";
+
+    static final String PROPERTIES_RESOURCE_PREFIX = "sling.feature.apiregions.resource.";
+    static final String PROPERTIES_FILE_LOCATION = "sling.feature.apiregions.location";
 
-    static final String PROPERTIES_FILE_PREFIX = "apiregions.";
     static final String IDBSNVER_FILENAME = "idbsnver.properties";
     static final String BUNDLE_FEATURE_FILENAME = "bundles.properties";
     static final String FEATURE_REGION_FILENAME = "features.properties";
@@ -55,101 +61,127 @@ class RegionEnforcer implements ResolverHookFactory {
     final Map<String, Set<String>> regionPackageMap;
     final Set<String> enabledRegions;
 
-    RegionEnforcer(Dictionary<String, Object> regProps, String regionsProp) throws IOException {
-        File idbsnverFile = getDataFile(IDBSNVER_FILENAME);
+    RegionEnforcer(BundleContext context, Dictionary<String, Object> regProps, String regionsProp) throws Exception {
+        URI idbsnverFile = getDataFileURI(context, IDBSNVER_FILENAME);
         bsnVerMap = populateBSNVerMap(idbsnverFile);
         if (idbsnverFile != null) {
-            regProps.put(IDBSNVER_FILENAME, idbsnverFile.getAbsolutePath());
+            // Register the location as a service property for diagnostic purposes
+            regProps.put(IDBSNVER_FILENAME, idbsnverFile.toString());
         }
 
-        File bundlesFile = getDataFile(BUNDLE_FEATURE_FILENAME);
+        URI bundlesFile = getDataFileURI(context, BUNDLE_FEATURE_FILENAME);
         bundleFeatureMap = populateBundleFeatureMap(bundlesFile);
         if (bundlesFile != null) {
-            regProps.put(BUNDLE_FEATURE_FILENAME, bundlesFile.getAbsolutePath());
+            // Register the location as a service property for diagnostic purposes
+            regProps.put(BUNDLE_FEATURE_FILENAME, bundlesFile.toString());
         }
 
-        File featuresFile = getDataFile(FEATURE_REGION_FILENAME);
+        URI featuresFile = getDataFileURI(context, FEATURE_REGION_FILENAME);
         featureRegionMap = populateFeatureRegionMap(featuresFile);
         if (featuresFile != null) {
-            regProps.put(FEATURE_REGION_FILENAME, featuresFile.getAbsolutePath());
+            // Register the location as a service property for diagnostic purposes
+            regProps.put(FEATURE_REGION_FILENAME, featuresFile.toString());
         }
 
-        File regionsFile = getDataFile(REGION_PACKAGE_FILENAME);
+        URI regionsFile = getDataFileURI(context, REGION_PACKAGE_FILENAME);
         regionPackageMap = populateRegionPackageMap(regionsFile);
         if (regionsFile != null) {
-            regProps.put(REGION_PACKAGE_FILENAME, regionsFile.getAbsolutePath());
+            // Register the location as a service property for diagnostic purposes
+            regProps.put(REGION_PACKAGE_FILENAME, regionsFile.toString());
         }
 
         enabledRegions = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(regionsProp.split(","))));
     }
 
-    private Map<Map.Entry<String, Version>, List<String>> populateBSNVerMap(File idbsnverFile) throws IOException {
-        if (idbsnverFile != null && idbsnverFile.exists()) {
-            Map<Map.Entry<String, Version>, List<String>> m = new HashMap<>();
-
-            Properties p = new Properties();
-            try (InputStream is = new FileInputStream(idbsnverFile)) {
-                p.load(is);
-            }
+    private Map<Map.Entry<String, Version>, List<String>> populateBSNVerMap(URI idbsnverFile) throws IOException {
+        if (idbsnverFile == null) {
+            return Collections.emptyMap();
+        }
 
-            for (String n : p.stringPropertyNames()) {
-                String[] bsnver = p.getProperty(n).split("~");
-                Map.Entry<String, Version> key = new AbstractMap.SimpleEntry<String, Version>(bsnver[0], Version.valueOf(bsnver[1]));
-                List<String> l = m.get(key);
-                if (l == null) {
-                    l = new ArrayList<>();
-                    m.put(key, l);
-                }
-                l.add(n);
-            }
+        Map<Map.Entry<String, Version>, List<String>> m = new HashMap<>();
 
-            Map<Map.Entry<String, Version>, List<String>> m2 = new HashMap<>();
+        Properties p = new Properties();
+        try (InputStream is = idbsnverFile.toURL().openStream()) {
+            p.load(is);
+        }
 
-            for (Map.Entry<Map.Entry<String, Version>, List<String>> entry : m.entrySet()) {
-                m2.put(entry.getKey(), Collections.unmodifiableList(entry.getValue()));
+        for (String n : p.stringPropertyNames()) {
+            String[] bsnver = p.getProperty(n).split("~");
+            Map.Entry<String, Version> key = new AbstractMap.SimpleEntry<String, Version>(bsnver[0], Version.valueOf(bsnver[1]));
+            List<String> l = m.get(key);
+            if (l == null) {
+                l = new ArrayList<>();
+                m.put(key, l);
             }
+            l.add(n);
+        }
 
-            return Collections.unmodifiableMap(m2);
-        } else {
-            return Collections.emptyMap();
+        Map<Map.Entry<String, Version>, List<String>> m2 = new HashMap<>();
+
+        for (Map.Entry<Map.Entry<String, Version>, List<String>> entry : m.entrySet()) {
+            m2.put(entry.getKey(), Collections.unmodifiableList(entry.getValue()));
         }
+
+        return Collections.unmodifiableMap(m2);
     }
 
-    private Map<String, Set<String>> populateBundleFeatureMap(File bundlesFile) throws IOException {
+    private Map<String, Set<String>> populateBundleFeatureMap(URI bundlesFile) throws IOException {
         return loadMap(bundlesFile);
     }
 
-    private Map<String, Set<String>> populateFeatureRegionMap(File featuresFile) throws IOException {
+    private Map<String, Set<String>> populateFeatureRegionMap(URI featuresFile) throws IOException {
         return loadMap(featuresFile);
     }
 
-    private Map<String, Set<String>> populateRegionPackageMap(File regionsFile) throws IOException {
+    private Map<String, Set<String>> populateRegionPackageMap(URI regionsFile) throws IOException {
         return loadMap(regionsFile);
     }
 
-    private Map<String, Set<String>> loadMap(File propsFile) throws IOException {
+    private Map<String, Set<String>> loadMap(URI propsFile) throws IOException {
+        if (propsFile == null) {
+            return Collections.emptyMap();
+        }
         Map<String, Set<String>> m = new HashMap<>();
 
-        if (propsFile != null && propsFile.exists()) {
-            Properties p = new Properties();
-            try (InputStream is = new FileInputStream(propsFile)) {
-                p.load(is);
-            }
+        Properties p = new Properties();
+        try (InputStream is = propsFile.toURL().openStream()) {
+            p.load(is);
+        }
 
-            for (String n : p.stringPropertyNames()) {
-                String[] features = p.getProperty(n).split(",");
-                m.put(n, Collections.unmodifiableSet(new HashSet<>(Arrays.asList(features))));
-            }
+        for (String n : p.stringPropertyNames()) {
+            String[] features = p.getProperty(n).split(",");
+            m.put(n, Collections.unmodifiableSet(new HashSet<>(Arrays.asList(features))));
         }
 
         return Collections.unmodifiableMap(m);
     }
 
-    private File getDataFile(String name) throws IOException {
-        String fn = System.getProperty(PROPERTIES_FILE_PREFIX + name);
+    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)
             return null;
-        return new File(fn);
+
+        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();
+        }
     }
 
     @Override
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 20924c9..9a279fd 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
@@ -25,12 +25,13 @@ import org.mockito.Mockito;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.hooks.resolver.ResolverHookFactory;
 
+import java.io.File;
 import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.Properties;
 
 import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.FEATURE_REGION_FILENAME;
-import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.PROPERTIES_FILE_PREFIX;
+import static org.apache.sling.feature.apiregions.impl.RegionEnforcer.PROPERTIES_RESOURCE_PREFIX;
 
 public class ActivatorTest {
     private Properties savedProps;
@@ -50,13 +51,14 @@ public class ActivatorTest {
     @Test
     public void testStart() throws Exception {
         String f = getClass().getResource("/features1.properties").getFile();
-        System.setProperty(PROPERTIES_FILE_PREFIX + FEATURE_REGION_FILENAME, f);
 
         Dictionary<String, Object> expectedProps = new Hashtable<>();
-        expectedProps.put(FEATURE_REGION_FILENAME, f);
+        expectedProps.put(FEATURE_REGION_FILENAME, new File(f).toURI().toString());
 
         BundleContext bc = Mockito.mock(BundleContext.class);
         Mockito.when(bc.getProperty(Activator.REGIONS_PROPERTY_NAME)).thenReturn("*");
+        Mockito.when(bc.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).
+            thenReturn(f);
 
         Activator a = new Activator();
         a.start(bc);
diff --git a/src/test/java/org/apache/sling/feature/apiregions/impl/RegionEnforcerTest.java b/src/test/java/org/apache/sling/feature/apiregions/impl/RegionEnforcerTest.java
index 322c3f3..7fd0be6 100644
--- a/src/test/java/org/apache/sling/feature/apiregions/impl/RegionEnforcerTest.java
+++ b/src/test/java/org/apache/sling/feature/apiregions/impl/RegionEnforcerTest.java
@@ -18,44 +18,33 @@
  */
 package org.apache.sling.feature.apiregions.impl;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.Version;
 
+import java.io.File;
 import java.util.AbstractMap;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Hashtable;
-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_FILE_PREFIX;
+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;
 
 public class RegionEnforcerTest {
-    private Properties savedProps;
-
-    @Before
-    public void setup() {
-        savedProps = new Properties(); // note that new Properties(props) doesn't copy
-        savedProps.putAll(System.getProperties());
-    }
-
-    @After
-    public void teardown() {
-        System.setProperties(savedProps);
-        savedProps = null;
-    }
-
     @Test
     public void testRegionEnforcerNoConfiguration() throws Exception {
-        RegionEnforcer re = new RegionEnforcer(new Hashtable<String, Object>(), "*");
+        BundleContext ctx = Mockito.mock(BundleContext.class);
+
+        RegionEnforcer re = new RegionEnforcer(ctx, new Hashtable<String, Object>(), "*");
         assertEquals(0, re.bsnVerMap.size());
         assertEquals(0, re.bundleFeatureMap.size());
         assertEquals(0, re.featureRegionMap.size());
@@ -65,25 +54,27 @@ public class RegionEnforcerTest {
     @Test
     public void testLoadBSNVerMap() throws Exception {
         String f = getClass().getResource("/idbsnver1.properties").getFile();
-        System.setProperty(PROPERTIES_FILE_PREFIX + IDBSNVER_FILENAME, f);
+        BundleContext ctx = Mockito.mock(BundleContext.class);
+        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + IDBSNVER_FILENAME)).thenReturn(f);
 
         Hashtable<String, Object> props = new Hashtable<>();
-        RegionEnforcer re = new RegionEnforcer(props, "*");
+        RegionEnforcer re = new RegionEnforcer(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))));
         assertEquals(new HashSet<>(Arrays.asList("g:b2:1.2.3", "g2:b2:1.2.4")),
                 new HashSet<>(re.bsnVerMap.get(new AbstractMap.SimpleEntry<String,Version>("b2", new Version(1,2,3)))));
-        assertEquals(f, props.get(IDBSNVER_FILENAME));
+        assertEquals(new File(f).toURI().toString(), props.get(IDBSNVER_FILENAME));
     }
 
     @Test
     public void testLoadBundleFeatureMap() throws Exception {
         String f = getClass().getResource("/bundles1.properties").getFile();
-        System.setProperty(PROPERTIES_FILE_PREFIX + BUNDLE_FEATURE_FILENAME, f);
+        BundleContext ctx = Mockito.mock(BundleContext.class);
+        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + BUNDLE_FEATURE_FILENAME)).thenReturn(f);
 
         Hashtable<String, Object> props = new Hashtable<>();
-        RegionEnforcer re = new RegionEnforcer(props, "*");
+        RegionEnforcer re = new RegionEnforcer(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"));
@@ -91,51 +82,54 @@ public class RegionEnforcerTest {
                 re.bundleFeatureMap.get("org.sling:b2:1"));
         assertEquals(new HashSet<>(Arrays.asList("some.other:feature:123", "org.sling:something:1.2.3:slingosgifeature:myclassifier")),
                 re.bundleFeatureMap.get("org.sling:b3:1"));
-        assertEquals(f, props.get(BUNDLE_FEATURE_FILENAME));
+        assertEquals(new File(f).toURI().toString(), props.get(BUNDLE_FEATURE_FILENAME));
     }
 
     @Test
     public void testLoadFeatureRegionMap() throws Exception {
         String f = getClass().getResource("/features1.properties").getFile();
-        System.setProperty(PROPERTIES_FILE_PREFIX + FEATURE_REGION_FILENAME, f);
+        BundleContext ctx = Mockito.mock(BundleContext.class);
+        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).thenReturn(f);
 
         Hashtable<String, Object> props = new Hashtable<>();
-        RegionEnforcer re = new RegionEnforcer(props, "*");
+        RegionEnforcer re = new RegionEnforcer(ctx, props, "*");
         assertEquals(2, re.featureRegionMap.size());
         assertEquals(Collections.singleton("global"),
                 re.featureRegionMap.get("an.other:feature:123"));
         assertEquals(new HashSet<>(Arrays.asList("global", "internal")),
                 re.featureRegionMap.get("org.sling:something:1.2.3"));
-        assertEquals(f, props.get(FEATURE_REGION_FILENAME));
+        assertEquals(new File(f).toURI().toString(), props.get(FEATURE_REGION_FILENAME));
     }
 
     @Test
     public void testLoadRegionPackageMap() throws Exception {
         String f = getClass().getResource("/regions1.properties").getFile();
-        System.setProperty(PROPERTIES_FILE_PREFIX + REGION_PACKAGE_FILENAME, f);
+        BundleContext ctx = Mockito.mock(BundleContext.class);
+        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + REGION_PACKAGE_FILENAME)).thenReturn(f);
 
         Hashtable<String, Object> props = new Hashtable<>();
-        RegionEnforcer re = new RegionEnforcer(props, "*");
+        RegionEnforcer re = new RegionEnforcer(ctx, props, "*");
         assertEquals(2, re.regionPackageMap.size());
         assertEquals(Collections.singleton("xyz"),
                 re.regionPackageMap.get("internal"));
         assertEquals(new HashSet<>(Arrays.asList("a.b.c", "d.e.f", "test")),
                 re.regionPackageMap.get("global"));
-        assertEquals(f, props.get(REGION_PACKAGE_FILENAME));
+        assertEquals(new File(f).toURI().toString(), props.get(REGION_PACKAGE_FILENAME));
     }
 
     @Test
     public void testBegin() throws Exception {
-        System.setProperty(PROPERTIES_FILE_PREFIX + IDBSNVER_FILENAME,
-                getClass().getResource("/idbsnver1.properties").getFile());
-        System.setProperty(PROPERTIES_FILE_PREFIX + BUNDLE_FEATURE_FILENAME,
-                getClass().getResource("/bundles1.properties").getFile());
-        System.setProperty(PROPERTIES_FILE_PREFIX + FEATURE_REGION_FILENAME,
-                getClass().getResource("/features1.properties").getFile());
-        System.setProperty(PROPERTIES_FILE_PREFIX + REGION_PACKAGE_FILENAME,
-                getClass().getResource("/regions1.properties").getFile());
-
-        RegionEnforcer re = new RegionEnforcer(new Hashtable<String, Object>(), "*");
+        BundleContext ctx = Mockito.mock(BundleContext.class);
+        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + IDBSNVER_FILENAME)).
+            thenReturn(getClass().getResource("/idbsnver1.properties").getFile());
+        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + BUNDLE_FEATURE_FILENAME)).
+            thenReturn(getClass().getResource("/bundles1.properties").getFile());
+        Mockito.when(ctx.getProperty(PROPERTIES_RESOURCE_PREFIX + FEATURE_REGION_FILENAME)).
+            thenReturn(getClass().getResource("/features1.properties").getFile());
+        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>(), "*");
         assertTrue(re.bsnVerMap.size() > 0);
         assertTrue(re.bundleFeatureMap.size() > 0);
         assertTrue(re.featureRegionMap.size() > 0);
@@ -147,4 +141,30 @@ public class RegionEnforcerTest {
         assertEquals(re.featureRegionMap, hook.featureRegionMap);
         assertEquals(re.regionPackageMap, hook.regionPackageMap);
     }
+
+    @Test
+    public void testURLs() throws Exception {
+        BundleContext ctx = Mockito.mock(BundleContext.class);
+        String location = new File(getClass().getResource("/props1/idbsnver.properties").
+                getFile()).getParentFile().toURI().toString();
+        Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).thenReturn(location);
+
+        RegionEnforcer re = new RegionEnforcer(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);
+    }
+
+    @Test
+    public void testClassloaderURLs() throws Exception {
+        BundleContext ctx = Mockito.mock(BundleContext.class);
+        Mockito.when(ctx.getProperty(PROPERTIES_FILE_LOCATION)).thenReturn("classloader://props1");
+
+        RegionEnforcer re = new RegionEnforcer(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);
+    }
 }
diff --git a/src/test/resources/props1/bundles.properties b/src/test/resources/props1/bundles.properties
new file mode 100644
index 0000000..7497eaf
--- /dev/null
+++ b/src/test/resources/props1/bundles.properties
@@ -0,0 +1,5 @@
+#Generated at Sat Nov 03 10:58:58 GMT 2018
+#Sat Nov 03 10:58:58 GMT 2018
+org.sling\:b3\:1=some.other\:feature\:123,org.sling\:something\:1.2.3\:slingosgifeature\:myclassifier
+org.sling\:b2\:1=org.sling\:something\:1.2.3\:slingosgifeature\:myclassifier
+org.sling\:b1\:1=org.sling\:something\:1.2.3\:slingosgifeature\:myclassifier
diff --git a/src/test/resources/props1/features.properties b/src/test/resources/props1/features.properties
new file mode 100644
index 0000000..9efad8d
--- /dev/null
+++ b/src/test/resources/props1/features.properties
@@ -0,0 +1,4 @@
+#Generated at Sat Nov 03 11:10:29 GMT 2018
+#Sat Nov 03 11:10:29 GMT 2018
+an.other\:feature\:123=global
+org.sling\:something\:1.2.3=internal,global
diff --git a/src/test/resources/props1/idbsnver.properties b/src/test/resources/props1/idbsnver.properties
new file mode 100644
index 0000000..00a740d
--- /dev/null
+++ b/src/test/resources/props1/idbsnver.properties
@@ -0,0 +1,6 @@
+#Generated at Sat Nov 03 10:26:37 GMT 2018
+#Sat Nov 03 10:26:37 GMT 2018
+g\:b2\:1.2.3=b2~1.2.3
+g\:b1\:1=b1~1.0.0
+g2\:b2\:1.2.4=b2~1.2.3
+
diff --git a/src/test/resources/props1/regions.properties b/src/test/resources/props1/regions.properties
new file mode 100644
index 0000000..a4982d7
--- /dev/null
+++ b/src/test/resources/props1/regions.properties
@@ -0,0 +1,4 @@
+#Generated at Sat Nov 03 11:10:29 GMT 2018
+#Sat Nov 03 11:10:29 GMT 2018
+internal=xyz
+global=d.e.f,test,a.b.c