Merge pull request #66 from apache/issues/FELIX-6294
FELIX-6294: add a slash to urls for directories
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
index 5aa9daa..388e426 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
@@ -514,6 +514,10 @@
{
if (contentPath.get(i).hasEntry(name))
{
+ if (!name.endsWith("/") && contentPath.get(i).isDirectory(name))
+ {
+ name += "/";
+ }
url = createURL(i + 1, name);
}
}
@@ -552,6 +556,10 @@
{
if (contentPath.get(i).hasEntry(name))
{
+ if (!name.endsWith("/") && contentPath.get(i).isDirectory(name))
+ {
+ name += "/";
+ }
// Use the class path index + 1 for creating the path so
// that we can differentiate between module content URLs
// (where the path will start with 0) and module class
@@ -588,6 +596,10 @@
// Check the module content.
if (getContent().hasEntry(name))
{
+ if (!name.endsWith("/") && getContent().isDirectory(name))
+ {
+ name += "/";
+ }
// Module content URLs start with 0, whereas module
// class path URLs start with the index into the class
// path + 1.
diff --git a/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java b/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
index 5ed9955..5f0ee34 100644
--- a/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
+++ b/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
@@ -869,7 +869,14 @@
};
}
- public boolean hasEntry(String name) {
+ public boolean hasEntry(String name)
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isDirectory(String name)
+ {
return false;
}
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/ConnectContentContent.java b/framework/src/main/java/org/apache/felix/framework/cache/ConnectContentContent.java
index 88e6dec..a37c598 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/ConnectContentContent.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/ConnectContentContent.java
@@ -68,6 +68,12 @@
}
@Override
+ public boolean isDirectory(String name)
+ {
+ return m_content.getEntry(name).map(entry -> entry.getName().endsWith("/")).orElse(false);
+ }
+
+ @Override
public Enumeration<String> getEntries()
{
try
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/Content.java b/framework/src/main/java/org/apache/felix/framework/cache/Content.java
index 79580c9..4ec2ecd 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/Content.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/Content.java
@@ -49,6 +49,18 @@
/**
* <p>
+ * This method determines if the specified named entry is contained in
+ * the associated content and is a directory. The entry name is a relative path with '/'
+ * separators.
+ * </p>
+ * @param name The name of the entry to find.
+ * @return <tt>true</tt> if a corresponding entry was found and is a directory, <tt>false</tt>
+ * otherwise.
+ **/
+ boolean isDirectory(String name);
+
+ /**
+ * <p>
* Returns an enumeration of entry names as <tt>String</tt> objects.
* An entry name is a path constructed with '/' as path element
* separators and is relative to the root of the content. Entry names
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java b/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java
index e1f04ac..1673270 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java
@@ -52,6 +52,14 @@
return m_content.hasEntry(m_rootPath + name);
}
+ @Override
+ public boolean isDirectory(String name)
+ {
+ name = getName(name);
+
+ return m_content.isDirectory(m_rootPath + name);
+ }
+
public Enumeration<String> getEntries()
{
Enumeration<String> result = new EntriesEnumeration(m_content.getEntries(), m_rootPath);
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java b/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
index 0240933..c462b55 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
@@ -83,6 +83,18 @@
? BundleCache.getSecureAction().isFileDirectory(file) : true);
}
+ @Override
+ public boolean isDirectory(String name)
+ {
+ name = getName(name);
+
+ // Return true if the file associated with the entry exists,
+ // unless the entry name ends with "/", in which case only
+ // return true if the file is really a directory.
+ File file = new File(m_dir, name);
+ return BundleCache.getSecureAction().isFileDirectory(file);
+ }
+
public Enumeration<String> getEntries()
{
// Wrap entries enumeration to filter non-matching entries.
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java b/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
index 79c2249..fd1dda0 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
@@ -101,7 +101,7 @@
}
}
- public boolean hasEntry(String name) throws IllegalStateException
+ public boolean hasEntry(String name)
{
try
{
@@ -114,6 +114,20 @@
}
}
+ @Override
+ public boolean isDirectory(String name)
+ {
+ try
+ {
+ ZipEntry ze = m_zipFile.getEntry(name);
+ return ze != null && ze.isDirectory();
+ }
+ catch (Exception ex)
+ {
+ return false;
+ }
+ }
+
public Enumeration<String> getEntries()
{
// Wrap entries enumeration to filter non-matching entries.
diff --git a/framework/src/main/java/org/apache/felix/framework/util/MultiReleaseContent.java b/framework/src/main/java/org/apache/felix/framework/util/MultiReleaseContent.java
index 29a5e30..fa1b48d 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/MultiReleaseContent.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/MultiReleaseContent.java
@@ -88,6 +88,12 @@
}
@Override
+ public boolean isDirectory(String name)
+ {
+ return m_content.isDirectory(findPath(name));
+ }
+
+ @Override
public Enumeration<String> getEntries()
{
Enumeration<String> entries = m_content.getEntries();
diff --git a/framework/src/test/java/org/apache/felix/framework/ResourceLoadingTest.java b/framework/src/test/java/org/apache/felix/framework/ResourceLoadingTest.java
index a89e430..19d6d07 100644
--- a/framework/src/test/java/org/apache/felix/framework/ResourceLoadingTest.java
+++ b/framework/src/test/java/org/apache/felix/framework/ResourceLoadingTest.java
@@ -79,7 +79,8 @@
cacheDir = null;
}
- public void testResourceLoadingWithHash() throws Exception {
+ public void testResourceLoadingWithHash() throws Exception
+ {
String bmf = "Bundle-SymbolicName: cap.bundle\n"
+ "Bundle-Version: 1.2.3.Blah\n"
+ "Bundle-ManifestVersion: 2\n"
@@ -132,6 +133,47 @@
}
}
+ public void testResourceLoadingWithDirectory() throws Exception
+ {
+ String bmf = "Bundle-SymbolicName: cap.bundle\n"
+ + "Bundle-Version: 1.2.3.Blah\n"
+ + "Bundle-ManifestVersion: 2\n"
+ + "Import-Package: org.osgi.framework\n";
+ File bundleFile = File.createTempFile("felix-bundle", ".jar", tempDir);
+
+ Manifest mf = new Manifest(new ByteArrayInputStream(bmf.getBytes("utf-8")));
+ mf.getMainAttributes().putValue("Manifest-Version", "1.0");
+ JarOutputStream os = new JarOutputStream(new FileOutputStream(bundleFile), mf);
+
+ String name = "bla/bli/blub";
+ os.putNextEntry(new ZipEntry("bla/"));
+ os.putNextEntry(new ZipEntry("bla/bli/"));
+ os.putNextEntry(new ZipEntry(name));
+ os.write("This is a Test".getBytes());
+ os.close();
+
+ Bundle testBundle = felix.getBundleContext().installBundle(bundleFile.toURI().toASCIIString());
+
+ testBundle.start();
+
+ assertEquals(Bundle.ACTIVE, testBundle.getState());
+ assertTrue(testBundle.getResource("bla").toExternalForm().endsWith("/"));
+ assertTrue(testBundle.getEntry("bla").toExternalForm().endsWith("/"));
+ assertTrue(testBundle.adapt(BundleWiring.class).getClassLoader().getResource("bla").toExternalForm().endsWith("/"));
+ assertTrue(testBundle.getResource("bla/").toExternalForm().endsWith("/"));
+ assertTrue(testBundle.getEntry("bla/").toExternalForm().endsWith("/"));
+ assertTrue(testBundle.adapt(BundleWiring.class).getClassLoader().getResource("bla/").toExternalForm().endsWith("/"));
+ assertTrue(testBundle.getResource("bla/bli").toExternalForm().endsWith("/"));
+ assertTrue(testBundle.getEntry("bla/bli").toExternalForm().endsWith("/"));
+ assertTrue(testBundle.adapt(BundleWiring.class).getClassLoader().getResource("bla/bli").toExternalForm().endsWith("/"));
+ assertTrue(testBundle.getResource("bla/bli/").toExternalForm().endsWith("/"));
+ assertTrue(testBundle.getEntry("bla/bli/").toExternalForm().endsWith("/"));
+ assertTrue(testBundle.adapt(BundleWiring.class).getClassLoader().getResource("bla/bli/").toExternalForm().endsWith("/"));
+ assertTrue(testBundle.getResource("bla/bli/blub").toExternalForm().endsWith("/blub"));
+ assertTrue(testBundle.getEntry("bla/bli/blub").toExternalForm().endsWith("/blub"));
+ assertTrue(testBundle.adapt(BundleWiring.class).getClassLoader().getResource("bla/bli/blub").toExternalForm().endsWith("/blub"));
+ }
+
private static void deleteDir(File root) throws IOException
{
if (root.isDirectory())