Merge pull request #81 from tjwatson/fixIssue76

Don't add empty directories as packages provided by a bundle
diff --git a/atomos.tests/atomos.tests.index.bundles/src/test/java/org/apache/felix/atomos/tests/index/bundles/IndexLaunchTest.java b/atomos.tests/atomos.tests.index.bundles/src/test/java/org/apache/felix/atomos/tests/index/bundles/IndexLaunchTest.java
index 80fe000..5bc58b0 100644
--- a/atomos.tests/atomos.tests.index.bundles/src/test/java/org/apache/felix/atomos/tests/index/bundles/IndexLaunchTest.java
+++ b/atomos.tests/atomos.tests.index.bundles/src/test/java/org/apache/felix/atomos/tests/index/bundles/IndexLaunchTest.java
@@ -25,7 +25,9 @@
 import java.io.InputStreamReader;
 import java.net.URL;
 import java.nio.file.Path;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -48,11 +50,17 @@
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.Version;
 import org.osgi.framework.launch.Framework;
+import org.osgi.framework.namespace.PackageNamespace;
 import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.framework.wiring.FrameworkWiring;
+import org.osgi.resource.Namespace;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
 
 public class IndexLaunchTest
 {
@@ -274,23 +282,26 @@
         {
             AtomosContent content = runtime.getBootLayer().findAtomosContent(
                 "bundle." + i).get();
-            List<String> expectedEntries = List.of( //
-                "/META-INF/", //
-                "/META-INF/MANIFEST.MF", //
-                "/OSGI-INF/", //
-                "/OSGI-INF/common.txt", //
-                "/OSGI-INF/bundle." + i + "-1.txt", //
-                "/OSGI-INF/bundle." + i + "-2.txt", //
-                "/org/", //
-                "/org/apache/", //
-                "/org/apache/felix/", //
-                "/org/apache/felix/atomos/", //
-                "/org/apache/felix/atomos/tests/", //
-                "/org/apache/felix/atomos/tests/index/", //
-                "/org/apache/felix/atomos/tests/index/bundles/", //
-                "/org/apache/felix/atomos/tests/index/bundles/b" + i + "/", //
-                "/org/apache/felix/atomos/tests/index/bundles/b" + i + "/ActivatorBundle" + i + ".class" //
-            );
+            List<String> expectedEntries = new ArrayList<>();
+            expectedEntries.add("/META-INF/");
+            expectedEntries.add("/META-INF/MANIFEST.MF");
+            expectedEntries.add("/OSGI-INF/");
+            expectedEntries.add("/OSGI-INF/common.txt");
+            expectedEntries.add("/OSGI-INF/bundle." + i + "-1.txt");
+            expectedEntries.add("/OSGI-INF/bundle." + i + "-2.txt");
+            expectedEntries.add("/org/");
+            expectedEntries.add("/org/apache/");
+            expectedEntries.add("/org/apache/felix/");
+            expectedEntries.add("/org/apache/felix/atomos/");
+            expectedEntries.add("/org/apache/felix/atomos/tests/");
+            expectedEntries.add("/org/apache/felix/atomos/tests/index/");
+            expectedEntries.add("/org/apache/felix/atomos/tests/index/bundles/");
+            if (i == 3) {
+                expectedEntries.add("/org/apache/felix/atomos/tests/index/bundles/TestClass.class");
+            }
+            expectedEntries.add("/org/apache/felix/atomos/tests/index/bundles/b" + i + "/");
+            expectedEntries.add("/org/apache/felix/atomos/tests/index/bundles/b" + i + "/ActivatorBundle" + i + ".class");
+
             Bundle bundle = content.getBundle();
             BundleWiring wiring = bundle.adapt(BundleWiring.class);
             List<URL> entryURLs = wiring.findEntries("/", "*",
@@ -305,6 +316,14 @@
         }
     }
 
+    @Test
+    void testEmptyDirectoryPackages(@TempDir Path storage) throws BundleException {
+        testFramework = getTestFramework(storage, null);
+        Bundle b3 = FrameworkUtil.getBundle(TestClass.class);
+        assertNotNull(b3, "no bundle found.");
+        assertEquals("bundle.3", b3.getSymbolicName(), "Wrong BSN");
+    }
+
     private void assertContent(String expected, URL url) throws IOException
     {
         try (BufferedReader br = new BufferedReader(
diff --git a/atomos.tests/atomos.tests.index.bundles/src/test/java/org/apache/felix/atomos/tests/index/bundles/TestClass.java b/atomos.tests/atomos.tests.index.bundles/src/test/java/org/apache/felix/atomos/tests/index/bundles/TestClass.java
new file mode 100644
index 0000000..432ce92
--- /dev/null
+++ b/atomos.tests/atomos.tests.index.bundles/src/test/java/org/apache/felix/atomos/tests/index/bundles/TestClass.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed 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.felix.atomos.tests.index.bundles;
+
+public class TestClass {
+    // nothing needed here; just need a class to load
+}
diff --git a/atomos.tests/atomos.tests.index.bundles/src/test/resources/atomos/bundles.index b/atomos.tests/atomos.tests.index.bundles/src/test/resources/atomos/bundles.index
index cb46df9..018f78e 100644
--- a/atomos.tests/atomos.tests.index.bundles/src/test/resources/atomos/bundles.index
+++ b/atomos.tests/atomos.tests.index.bundles/src/test/resources/atomos/bundles.index
@@ -53,6 +53,7 @@
 org/apache/felix/atomos/tests/
 org/apache/felix/atomos/tests/index/
 org/apache/felix/atomos/tests/index/bundles/
+org/apache/felix/atomos/tests/index/bundles/TestClass.class
 org/apache/felix/atomos/tests/index/bundles/b3/
 org/apache/felix/atomos/tests/index/bundles/b3/ActivatorBundle3.class
 ATOMOS_BUNDLE
diff --git a/atomos.tests/atomos.tests.index.bundles/src/test/resources/testIndex/test.index b/atomos.tests/atomos.tests.index.bundles/src/test/resources/testIndex/test.index
index 66e8d9a..d0e0a90 100644
--- a/atomos.tests/atomos.tests.index.bundles/src/test/resources/testIndex/test.index
+++ b/atomos.tests/atomos.tests.index.bundles/src/test/resources/testIndex/test.index
@@ -15,6 +15,7 @@
 org/apache/felix/atomos/tests/
 org/apache/felix/atomos/tests/index/
 org/apache/felix/atomos/tests/index/bundles/
+org/apache/felix/atomos/tests/index/bundles/TestClass.class
 org/apache/felix/atomos/tests/index/bundles/b3/
 org/apache/felix/atomos/tests/index/bundles/b3/ActivatorBundle3.class
 ATOMOS_BUNDLE
diff --git a/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosBase.java b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosBase.java
index 231786b..864342d 100644
--- a/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosBase.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosBase.java
@@ -1663,9 +1663,11 @@
                 try
                 {
                     content.getEntries().forEach((s) -> {
-                        if (s.length() > 1 && s.endsWith("/") && s.indexOf('-') < 0)
+                        int sLen = s.length();
+                        int lastSlash = s.lastIndexOf('/');
+                        if (sLen > 1 && s.indexOf('-') < 0 && lastSlash > 0 && lastSlash != sLen - 1)
                         {
-                            String pkg = s.substring(0, s.length() - 1).replace('/', '.');
+                            String pkg = s.substring(0, lastSlash).replace('/', '.');
                             packageToAtomosContent.put(pkg,
                                 (AtomosContentIndexed) atomosContent);
                         }