diff options
author | Thomas Watson | 2017-12-11 14:05:15 +0000 |
---|---|---|
committer | Thomas Watson | 2017-12-13 17:13:03 +0000 |
commit | 03d4817df48f3857799ec0ec3439790e2c425bec (patch) | |
tree | c300a9f5adab6cb39184bdc2081e93292f19ac9f /bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage | |
parent | 6f2b763dc9c65ad86450ee6aec82da56d6c95617 (diff) | |
download | rt.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.java | 40 | ||||
-rw-r--r-- | bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/Storage.java | 95 |
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 |