Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 366972 - platform:/plugin/ URLs do not resolve items within embedded jars
Summary: platform:/plugin/ URLs do not resolve items within embedded jars
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Runtime (show other bugs)
Version: 4.2   Edit
Hardware: PC Mac OS X - Carbon (unsup.)
: P3 normal (vote)
Target Milestone: 3.8 M5   Edit
Assignee: platform-runtime-inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-12-16 14:33 EST by Brian de Alwis CLA
Modified: 2011-12-19 09:30 EST (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Brian de Alwis CLA 2011-12-16 14:33:04 EST
With E4, we write out a serialized form of the UI to be restored on subsequent sessions.  Icons and part implementation classes are referred to using URIs.

As we can't control when a user might start with -clean, or move the serialized model to another workspace (or another machine), we have some code that rewrites the bundleentry and bundleresource style URLs into their platform:/plugin equivalents.  This works fine for bundleentry:// URLs (i.e., they're able to be resolved from the bundle directly), but we've discovered that it doesn't work for bundleresource:// URLs, which reference items found within embedded jars.

In my case, the code is referencing icons that are stored in embedded .jar files; this is out of my control.

The issue here is that Equinox's PlatformURLPluginConnection uses Bundle#getEntry().  Ideally, I'd like to change PlatformURLPluginConnection#resolve() to try Bundle#getResource() if the URL can't be resolved by a getEntry() — as the code says at the bottom of the method, it creates a a URL that will force a FileNotFoundException anyways:

	protected URL resolve() throws IOException {
		String spec = url.getFile().trim();
		Object[] obj = parse(spec, url);
		Bundle b = (Bundle) obj[0];
		String path = (String) obj[1];
		URL result = b.getEntry(path);
		if (result != null || "/".equals(path)) //$NON-NLS-1$
			return result;
		// if the result is null then force the creation of a URL that will throw FileNotFoundExceptions
		return new URL(b.getEntry("/"), path); //$NON-NLS-1$
	}

This will also a problem for anybody trying to reference a class that's defined in an embedded jar file with a platform:/plugin URL.  

It seems strange that I import and use a class that is contained in an embedded jar, but cannot resolve tht class through a URL.  Or rather, that the layout of the bundle affects whether an item can be resolved or not.

The fix is straightforward:

--- org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/PlatformURLPluginConnection.java	.orig	2011-12-16 14:31:02.000000000 -0500
+++ org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/PlatformURLPluginConnection.java	2011-12-16 14:22:37.000000000 -0500
@@ -78,6 +79,10 @@
 		URL result = b.getEntry(path);
 		if (result != null || "/".equals(path)) //$NON-NLS-1$
 			return result;
+		// try resolving the path through the classloader
+		result = b.getResource(path);
+		if (result != null)
+			return result;
 		// if the result is null then force the creation of a URL that will throw FileNotFoundExceptions
 		return new URL(b.getEntry("/"), path); //$NON-NLS-1$
 	}