Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Watson2017-12-11 14:05:15 +0000
committerThomas Watson2017-12-13 17:13:03 +0000
commit03d4817df48f3857799ec0ec3439790e2c425bec (patch)
treec300a9f5adab6cb39184bdc2081e93292f19ac9f /bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage
parent6f2b763dc9c65ad86450ee6aec82da56d6c95617 (diff)
downloadrt.equinox.framework-03d4817df48f3857799ec0ec3439790e2c425bec.tar.gz
rt.equinox.framework-03d4817df48f3857799ec0ec3439790e2c425bec.tar.xz
rt.equinox.framework-03d4817df48f3857799ec0ec3439790e2c425bec.zip
Bug 528422 - [osgi R7] Support for Multi-Release jars
Change-Id: Iab950e54caa6fffb3c995694c0d7762111a846a3 Signed-off-by: Thomas Watson <tjwatson@us.ibm.com>
Diffstat (limited to 'bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage')
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleInfo.java40
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/Storage.java95
2 files changed, 111 insertions, 24 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleInfo.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleInfo.java
index c905d2832..286bcb7d1 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleInfo.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleInfo.java
@@ -48,9 +48,11 @@ import org.eclipse.osgi.storage.url.bundleentry.Handler;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
public final class BundleInfo {
public static final String OSGI_BUNDLE_MANIFEST = "META-INF/MANIFEST.MF"; //$NON-NLS-1$
+ public static final String MULTI_RELEASE_HEADER = "Multi-Release"; //$NON-NLS-1$
public final class Generation {
private final long generationId;
@@ -68,13 +70,14 @@ public final class BundleInfo {
private NativeCodeFinder nativeCodeFinder;
private List<StorageHook<?, ?>> storageHooks;
private long lastModified;
+ private boolean isMRJar;
Generation(long generationId) {
this.generationId = generationId;
this.cachedHeaders = new CachedManifest(this, Collections.<String, String> emptyMap());
}
- Generation(long generationId, File content, boolean isDirectory, boolean isReference, boolean hasPackageInfo, Map<String, String> cached, long lastModified) {
+ Generation(long generationId, File content, boolean isDirectory, boolean isReference, boolean hasPackageInfo, Map<String, String> cached, long lastModified, boolean isMRJar) {
this.generationId = generationId;
this.content = content;
this.isDirectory = isDirectory;
@@ -82,6 +85,7 @@ public final class BundleInfo {
this.hasPackageInfo = hasPackageInfo;
this.cachedHeaders = new CachedManifest(this, cached);
this.lastModified = lastModified;
+ this.isMRJar = isMRJar;
}
public BundleFile getBundleFile() {
@@ -121,7 +125,28 @@ public final class BundleInfo {
rawHeaders = Collections.emptyMap();
} else {
try {
- rawHeaders = Collections.unmodifiableMap(ManifestElement.parseBundleManifest(manifest.getInputStream(), new CaseInsensitiveDictionaryMap<String, String>()));
+ Map<String, String> merged = ManifestElement.parseBundleManifest(manifest.getInputStream(), new CaseInsensitiveDictionaryMap<String, String>());
+ // For MRJARs only replace Import-Package and Require-Capability if the versioned values are non-null
+ if (Boolean.parseBoolean(merged.get(MULTI_RELEASE_HEADER))) {
+ for (int i = getStorage().getRuntimeVersion().getMajor(); i > 8; i--) {
+ String versionManifest = "META-INF/versions/" + i + "/OSGI-INF/MANIFEST.MF"; //$NON-NLS-1$ //$NON-NLS-2$
+ BundleEntry versionEntry = getBundleFile().getEntry(versionManifest);
+ if (versionEntry != null) {
+ Map<String, String> versioned = ManifestElement.parseBundleManifest(versionEntry.getInputStream(), new CaseInsensitiveDictionaryMap<String, String>());
+ String versionedImport = versioned.get(Constants.IMPORT_PACKAGE);
+ String versionedRequireCap = versioned.get(Constants.REQUIRE_CAPABILITY);
+ if (versionedImport != null) {
+ merged.put(Constants.IMPORT_PACKAGE, versionedImport);
+ }
+ if (versionedRequireCap != null) {
+ merged.put(Constants.REQUIRE_CAPABILITY, versionedRequireCap);
+ }
+ // found a versioned entry; stop searching for more versions
+ break;
+ }
+ }
+ }
+ rawHeaders = Collections.unmodifiableMap(merged);
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
@@ -191,6 +216,12 @@ public final class BundleInfo {
}
}
+ public boolean isMRJar() {
+ synchronized (this.genMonitor) {
+ return this.isMRJar;
+ }
+ }
+
public File getContent() {
synchronized (this.genMonitor) {
return this.content;
@@ -222,6 +253,7 @@ public final class BundleInfo {
this.storageHooks = storageHooks;
if (install) {
this.hasPackageInfo = BundleInfo.hasPackageInfo(getBundleFile());
+ this.isMRJar = Boolean.parseBoolean(getRawHeaders().get(MULTI_RELEASE_HEADER));
}
}
}
@@ -433,9 +465,9 @@ public final class BundleInfo {
}
}
- Generation restoreGeneration(long generationId, File content, boolean isDirectory, boolean isReference, boolean hasPackageInfo, Map<String, String> cached, long lastModified) {
+ Generation restoreGeneration(long generationId, File content, boolean isDirectory, boolean isReference, boolean hasPackageInfo, Map<String, String> cached, long lastModified, boolean isMRJar) {
synchronized (this.infoMonitor) {
- Generation restoredGeneration = new Generation(generationId, content, isDirectory, isReference, hasPackageInfo, cached, lastModified);
+ Generation restoredGeneration = new Generation(generationId, content, isDirectory, isReference, hasPackageInfo, cached, lastModified, isMRJar);
return restoredGeneration;
}
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/Storage.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/Storage.java
index 0ed4743e7..31b4b6fdb 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/Storage.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/Storage.java
@@ -45,6 +45,7 @@ import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.core.runtime.adaptor.EclipseStarter;
import org.eclipse.osgi.container.Module;
import org.eclipse.osgi.container.ModuleCapability;
@@ -109,7 +110,9 @@ import org.osgi.resource.Namespace;
import org.osgi.resource.Requirement;
public class Storage {
- public static final int VERSION = 3;
+ public static final int VERSION = 4;
+ private static final int MR_JAR_VERSION = 4;
+ private static final int LOWEST_VERSION_SUPPORTED = 3;
public static final String BUNDLE_DATA_DIR = "data"; //$NON-NLS-1$
public static final String BUNDLE_FILE_NAME = "bundleFile"; //$NON-NLS-1$
public static final String FRAMEWORK_INFO = "framework.info"; //$NON-NLS-1$
@@ -140,6 +143,9 @@ public class Storage {
private final FrameworkExtensionInstaller extensionInstaller;
private final List<String> cachedHeaderKeys = Arrays.asList(Constants.BUNDLE_SYMBOLICNAME, Constants.BUNDLE_ACTIVATIONPOLICY, "Service-Component"); //$NON-NLS-1$
private final boolean allowRestrictedProvides;
+ private final AtomicBoolean refreshMRBundles = new AtomicBoolean(false);
+ private final Version runtimeVersion;
+ private final String javaSpecVersion;
public static Storage createStorage(EquinoxContainer container) throws IOException, BundleException {
Storage storage = new Storage(container);
@@ -153,6 +159,24 @@ public class Storage {
}
private Storage(EquinoxContainer container) throws IOException {
+ // default to Java 7 since that is our min
+ Version javaVersion = Version.valueOf("1.7"); //$NON-NLS-1$
+ // set the profile and EE based off of the java.specification.version
+ String javaSpecVersionProp = System.getProperty(EquinoxConfiguration.PROP_JVM_SPEC_VERSION);
+ StringTokenizer st = new StringTokenizer(javaSpecVersionProp, " _-"); //$NON-NLS-1$
+ javaSpecVersionProp = st.nextToken();
+ try {
+ String[] vComps = javaSpecVersionProp.split("\\."); //$NON-NLS-1$
+ // only pay attention to the first three components of the version
+ int major = vComps.length > 0 ? Integer.parseInt(vComps[0]) : 0;
+ int minor = vComps.length > 1 ? Integer.parseInt(vComps[1]) : 0;
+ int micro = vComps.length > 2 ? Integer.parseInt(vComps[2]) : 0;
+ javaVersion = new Version(major, minor, micro);
+ } catch (IllegalArgumentException e) {
+ // do nothing
+ }
+ runtimeVersion = javaVersion;
+ javaSpecVersion = javaSpecVersionProp;
mruList = new MRUBundleFileList(getBundleFileLimit(container.getConfiguration()));
equinoxContainer = container;
extensionInstaller = new FrameworkExtensionInstaller(container.getConfiguration());
@@ -230,6 +254,10 @@ public class Storage {
}
}
+ public Version getRuntimeVersion() {
+ return runtimeVersion;
+ }
+
private int getBundleFileLimit(EquinoxConfiguration configuration) {
int propValue = 100; // enable to 100 open files by default
try {
@@ -343,6 +371,10 @@ public class Storage {
moduleContainer.resolve(Collections.singleton(systemModule), true);
}
}
+ if (refreshMRBundles.get()) {
+ Collection<Module> toRefresh = refreshMRJarBundles();
+ moduleContainer.refresh(toRefresh);
+ }
} catch (BundleException e) {
throw new IllegalStateException("Could not create a builder for the system bundle.", e); //$NON-NLS-1$
}
@@ -376,6 +408,19 @@ public class Storage {
}
}
+ private Collection<Module> refreshMRJarBundles() throws BundleException {
+ Collection<Module> mrJarBundles = new ArrayList<>();
+ for (Module m : moduleContainer.getModules()) {
+ Generation generation = (Generation) m.getCurrentRevision().getRevisionInfo();
+ // Note that we check the raw headers here incase we are working off an old version of the persistent storage
+ if (Boolean.parseBoolean(generation.getRawHeaders().get(BundleInfo.MULTI_RELEASE_HEADER))) {
+ refresh(m);
+ mrJarBundles.add(m);
+ }
+ }
+ return mrJarBundles;
+ }
+
public void close() {
try {
save();
@@ -774,6 +819,20 @@ public class Storage {
return result.toString();
}
+ private void refresh(Module module) throws BundleException {
+ ModuleRevision current = module.getCurrentRevision();
+ Generation currentGen = (Generation) current.getRevisionInfo();
+ File content = currentGen.getContent();
+ String spec = (currentGen.isReference() ? "reference:" : "") + content.toURI().toString(); //$NON-NLS-1$ //$NON-NLS-2$
+ URLConnection contentConn;
+ try {
+ contentConn = getContentConnection(spec);
+ } catch (IOException e) {
+ throw new BundleException("Error reading bundle content.", e); //$NON-NLS-1$
+ }
+ update(module, contentConn);
+ }
+
public Generation update(Module module, URLConnection content) throws BundleException {
if (osgiLocation.isReadOnly()) {
throw new BundleException("The framework storage area is read only.", BundleException.INVALID_OPERATION); //$NON-NLS-1$
@@ -787,7 +846,6 @@ public class Storage {
}
boolean isReference = in instanceof ReferenceInputStream;
File staged = stageContent(in, sourceURL);
-
ModuleRevision current = module.getCurrentRevision();
Generation currentGen = (Generation) current.getRevisionInfo();
@@ -1146,6 +1204,8 @@ public class Storage {
}
out.writeInt(VERSION);
+ out.writeUTF(runtimeVersion.toString());
+
out.writeInt(cachedHeaderKeys.size());
for (String headerKey : cachedHeaderKeys) {
out.writeUTF(headerKey);
@@ -1184,6 +1244,8 @@ public class Storage {
out.writeUTF(NUL);
}
}
+
+ out.writeBoolean(generation.isMRJar());
}
saveStorageHookData(out, generations);
@@ -1222,9 +1284,13 @@ public class Storage {
return new HashMap<>(0);
}
int version = in.readInt();
- if (version != VERSION) {
+ if (version > VERSION || version < LOWEST_VERSION_SUPPORTED) {
throw new IllegalArgumentException("Found persistent version \"" + version + "\" expecting \"" + VERSION + "\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
+ Version savedRuntimeVersion = (version >= MR_JAR_VERSION) ? Version.parseVersion(in.readUTF()) : null;
+ if (savedRuntimeVersion == null || !savedRuntimeVersion.equals(runtimeVersion)) {
+ refreshMRBundles.set(true);
+ }
int numCachedHeaders = in.readInt();
List<String> storedCachedHeaderKeys = new ArrayList<>(numCachedHeaders);
for (int i = 0; i < numCachedHeaders; i++) {
@@ -1255,6 +1321,7 @@ public class Storage {
}
cachedHeaders.put(headerKey, value);
}
+ boolean isMRJar = (version >= MR_JAR_VERSION) ? in.readBoolean() : false;
File content;
if (infoId == 0) {
@@ -1278,7 +1345,7 @@ public class Storage {
}
BundleInfo info = new BundleInfo(this, infoId, infoLocation, nextGenId);
- Generation generation = info.restoreGeneration(generationId, content, isDirectory, isReference, hasPackageInfo, cachedHeaders, lastModified);
+ Generation generation = info.restoreGeneration(generationId, content, isDirectory, isReference, hasPackageInfo, cachedHeaders, lastModified, isMRJar);
result.put(infoId, generation);
generations.add(generation);
}
@@ -1428,20 +1495,8 @@ public class Storage {
return result;
}
- // default to Java 7 since that is our min
- Version javaVersion = Version.valueOf("1.7"); //$NON-NLS-1$
- // set the profile and EE based off of the java.specification.version
- String javaSpecVersion = System.getProperty(EquinoxConfiguration.PROP_JVM_SPEC_VERSION);
- StringTokenizer st = new StringTokenizer(javaSpecVersion, " _-"); //$NON-NLS-1$
- javaSpecVersion = st.nextToken();
- try {
- javaVersion = new Version(javaSpecVersion);
- } catch (IllegalArgumentException e) {
- // do nothing
- }
-
- if (Version.valueOf("9").compareTo(javaVersion) <= 0) { //$NON-NLS-1$
- result = calculateVMProfile(javaVersion);
+ if (Version.valueOf("9").compareTo(runtimeVersion) <= 0) { //$NON-NLS-1$
+ result = calculateVMProfile(runtimeVersion);
if (result != null) {
return result;
}
@@ -1450,7 +1505,7 @@ public class Storage {
String embeddedProfileName = "-"; //$NON-NLS-1$
// If javaSE 1.8 then check for release file for profile name.
- if (javaVersion != null && Version.valueOf("1.8").compareTo(javaVersion) <= 0) { //$NON-NLS-1$
+ if (runtimeVersion != null && Version.valueOf("1.8").compareTo(runtimeVersion) <= 0) { //$NON-NLS-1$
String javaHome = System.getProperty("java.home"); //$NON-NLS-1$
if (javaHome != null) {
File release = new File(javaHome, "release"); //$NON-NLS-1$
@@ -1479,7 +1534,7 @@ public class Storage {
String javaProfile = vmProfile + PROFILE_EXT;
profileIn = findInSystemBundle(systemGeneration, javaProfile);
if (profileIn == null)
- profileIn = getNextBestProfile(systemGeneration, JAVASE, javaVersion, embeddedProfileName);
+ profileIn = getNextBestProfile(systemGeneration, JAVASE, runtimeVersion, embeddedProfileName);
}
if (profileIn == null)
// the profile url is still null then use the min profile the framework can use

Back to the top