Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Watson2012-07-31 21:23:12 +0000
committerThomas Watson2012-08-01 20:56:58 +0000
commit10c452a1403362ab2e4d5d08938c8347ba53c8ef (patch)
tree17bf9955a538f0af4bde61e3725bacc8382042b5
parenta2763d35135b047fdc8aeddf5b63c240a2a79667 (diff)
downloadrt.equinox.framework-10c452a1403362ab2e4d5d08938c8347ba53c8ef.tar.gz
rt.equinox.framework-10c452a1403362ab2e4d5d08938c8347ba53c8ef.tar.xz
rt.equinox.framework-10c452a1403362ab2e4d5d08938c8347ba53c8ef.zip
update storage for new container
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleInfo.java390
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleLocalizationImpl.java11
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/ManifestLocalization.java84
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/NativeCodeFinder.java206
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/PermissionData.java198
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/Storage.java1433
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/SystemBundleFile.java106
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleEntry.java6
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFile.java85
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapperChain.java9
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/ZipBundleFile.java54
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleResourceHandler.java79
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleURLConnection.java3
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleURLConverter.java9
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/bundleentry/Handler.java33
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/bundleresource/Handler.java43
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/Debug.java42
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/EclipseDebugTrace.java2
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/FrameworkDebugOptions.java50
-rw-r--r--bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/next/internal/debug/Debug.java370
20 files changed, 2894 insertions, 319 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
new file mode 100644
index 000000000..1dedfc556
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleInfo.java
@@ -0,0 +1,390 @@
+/*******************************************************************************
+ * Copyright (c) 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osgi.storage;
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.ProtectionDomain;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import org.eclipse.osgi.container.ModuleRevision;
+import org.eclipse.osgi.framework.log.FrameworkLogEntry;
+import org.eclipse.osgi.framework.util.Headers;
+import org.eclipse.osgi.internal.container.LockSet;
+import org.eclipse.osgi.internal.framework.EquinoxConfiguration;
+import org.eclipse.osgi.internal.framework.EquinoxContainer;
+import org.eclipse.osgi.internal.hookregistry.StorageHookFactory;
+import org.eclipse.osgi.internal.hookregistry.StorageHookFactory.StorageHook;
+import org.eclipse.osgi.next.internal.debug.Debug;
+import org.eclipse.osgi.storage.bundlefile.BundleEntry;
+import org.eclipse.osgi.storage.bundlefile.BundleFile;
+import org.eclipse.osgi.storage.url.BundleResourceHandler;
+import org.eclipse.osgi.storage.url.bundleentry.Handler;
+import org.osgi.framework.BundleException;
+
+public final class BundleInfo {
+ public static final String OSGI_BUNDLE_MANIFEST = "META-INF/MANIFEST.MF"; //$NON-NLS-1$
+
+ public final class Generation {
+ private final long generationId;
+ private final Object genMonitor = new Object();
+ private File content;
+ private boolean isDirectory;
+ private boolean hasPackageInfo;
+ private BundleFile bundleFile;
+ private Dictionary<String, String> headers;
+ private ModuleRevision revision;
+ private ManifestLocalization headerLocalization;
+ private ProtectionDomain domain;
+ private NativeCodeFinder nativeCodeFinder;
+ private List<StorageHook<?, ?>> storageHooks;
+
+ Generation(long generationId) {
+ this.generationId = generationId;
+ }
+
+ Generation(long generationId, File content, boolean isDirectory, boolean hasPackageInfo) {
+ this.generationId = generationId;
+ this.content = content;
+ this.isDirectory = isDirectory;
+ this.hasPackageInfo = hasPackageInfo;
+ }
+
+ public BundleFile getBundleFile() {
+ synchronized (genMonitor) {
+ if (bundleFile == null) {
+ if (getBundleId() == 0 && content == null) {
+ bundleFile = new SystemBundleFile();
+ } else {
+ bundleFile = getStorage().createBundleFile(content, this, isDirectory, true);
+ }
+ }
+ return bundleFile;
+ }
+ }
+
+ public void close() {
+ synchronized (genMonitor) {
+ if (bundleFile != null) {
+ try {
+ bundleFile.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ public Dictionary<String, String> getHeaders() {
+ synchronized (genMonitor) {
+ if (headers == null) {
+ BundleEntry manifest = getBundleFile().getEntry(OSGI_BUNDLE_MANIFEST);
+ try {
+ headers = Headers.parseManifest(manifest.getInputStream());
+ } catch (Exception e) {
+ if (e instanceof RuntimeException) {
+ throw (RuntimeException) e;
+ }
+ throw new RuntimeException("Error occurred getting the bundle manifest.", e); //$NON-NLS-1$
+ }
+ }
+ return headers;
+ }
+ }
+
+ public Dictionary<String, String> getHeaders(String locale) {
+ ManifestLocalization current = getManifestLocalization();
+ return current.getHeaders(locale);
+ }
+
+ public ResourceBundle getResourceBundle(String locale) {
+ ManifestLocalization current = getManifestLocalization();
+ String defaultLocale = Locale.getDefault().toString();
+ if (locale == null) {
+ locale = defaultLocale;
+ }
+ return current.getResourceBundle(locale, defaultLocale.equals(locale));
+ }
+
+ private ManifestLocalization getManifestLocalization() {
+ synchronized (genMonitor) {
+ if (headerLocalization == null) {
+ headerLocalization = new ManifestLocalization(this, getHeaders(), getStorage().getConfiguration().getConfiguration(EquinoxConfiguration.PROP_ROOT_LOCALE, "en")); //$NON-NLS-1$
+ }
+ return headerLocalization;
+ }
+ }
+
+ public void clearManifestCache() {
+ synchronized (genMonitor) {
+ if (headerLocalization != null) {
+ headerLocalization.clearCache();
+ }
+ }
+ }
+
+ public long getGenerationId() {
+ return this.generationId;
+ }
+
+ public boolean isDirectory() {
+ synchronized (this.genMonitor) {
+ return this.isDirectory;
+ }
+ }
+
+ public boolean hasPackageInfo() {
+ synchronized (this.genMonitor) {
+ return this.hasPackageInfo;
+ }
+ }
+
+ public File getContent() {
+ synchronized (this.genMonitor) {
+ return this.content;
+ }
+ }
+
+ void setContent(File content) {
+ synchronized (this.genMonitor) {
+ this.content = content;
+ this.isDirectory = content == null ? false : content.isDirectory();
+ }
+ }
+
+ void setStorageHooks(List<StorageHook<?, ?>> storageHooks, boolean install) {
+ synchronized (this.genMonitor) {
+ this.storageHooks = storageHooks;
+ if (install) {
+ this.hasPackageInfo = BundleInfo.hasPackageInfo(getBundleFile());
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public <S, L, H extends StorageHook<S, L>> H getStorageHook(Class<? extends StorageHookFactory<S, L, H>> factoryClass) {
+ synchronized (this.genMonitor) {
+ if (this.storageHooks == null)
+ return null;
+ for (StorageHook<?, ?> hook : storageHooks) {
+ if (hook.getFactoryClass().equals(factoryClass)) {
+ return (H) hook;
+ }
+ }
+ }
+ return null;
+ }
+
+ public ModuleRevision getRevision() {
+ synchronized (this.genMonitor) {
+ return this.revision;
+ }
+ }
+
+ public void setRevision(ModuleRevision revision) {
+ synchronized (this.genMonitor) {
+ this.revision = revision;
+ }
+ }
+
+ public ProtectionDomain getDomain() {
+ if (getBundleId() == 0) {
+ return null;
+ }
+ synchronized (this.genMonitor) {
+ if (domain == null) {
+ if (revision == null) {
+ throw new IllegalStateException("The revision is not yet set for this generation."); //$NON-NLS-1$
+ }
+ domain = getStorage().getSecurityAdmin().createProtectionDomain(revision.getBundle());
+ }
+ return domain;
+ }
+ }
+
+ /**
+ * Gets called by BundleFile during {@link BundleFile#getFile(String, boolean)}. This method
+ * will allocate a File object where content of the specified path may be
+ * stored for this generation. The returned File object may
+ * not exist if the content has not previously been stored.
+ * @param path the path to the content to extract from the generation
+ * @return a file object where content of the specified path may be stored.
+ */
+ public File getExtractFile(String path) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(getBundleId()).append('/').append(getGenerationId());
+ if (path.length() > 0 && path.charAt(0) != '/') {
+ builder.append('/');
+ }
+ builder.append(path);
+ return getStorage().getFile(builder.toString(), true);
+ }
+
+ public BundleInfo getBundleInfo() {
+ return BundleInfo.this;
+ }
+
+ public void delete() {
+ getBundleInfo().delete(this);
+ }
+
+ public URL getEntry(String path) {
+ BundleEntry entry = getBundleFile().getEntry(path);
+ if (entry == null)
+ return null;
+ path = BundleFile.fixTrailingSlash(path, entry);
+ try {
+ //use the constant string for the protocol to prevent duplication
+ return Storage.secureAction.getURL(BundleResourceHandler.OSGI_ENTRY_URL_PROTOCOL, Long.toString(getBundleId()) + BundleResourceHandler.BID_FWKID_SEPARATOR + Integer.toString(getStorage().getModuleContainer().hashCode()), 0, path, new Handler(getStorage().getModuleContainer(), entry));
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ }
+
+ public String findLibrary(String libname) {
+ NativeCodeFinder currentFinder;
+ synchronized (this.genMonitor) {
+ if (nativeCodeFinder == null) {
+ nativeCodeFinder = new NativeCodeFinder(this);
+ }
+ currentFinder = nativeCodeFinder;
+ }
+ return currentFinder.findLibrary(libname);
+ }
+ }
+
+ private final Storage storage;
+ private final long bundleId;
+ private long nextGenerationId;
+ private final Object infoMonitor = new Object();
+ private LockSet<Long> generationLocks;
+
+ public BundleInfo(Storage storage, long bundleId, long nextGenerationId) {
+ this.storage = storage;
+ this.bundleId = bundleId;
+ this.nextGenerationId = nextGenerationId;
+ }
+
+ public long getBundleId() {
+ return bundleId;
+ }
+
+ Generation createGeneration() throws BundleException {
+ synchronized (this.infoMonitor) {
+ if (generationLocks == null) {
+ generationLocks = new LockSet<Long>(false);
+ }
+ boolean lockedID;
+ try {
+ lockedID = generationLocks.tryLock(nextGenerationId, 5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new BundleException("Failed to obtain id locks for generation.", BundleException.STATECHANGE_ERROR, e); //$NON-NLS-1$
+ }
+ if (!lockedID) {
+ throw new BundleException("Failed to obtain id locks for generation.", BundleException.STATECHANGE_ERROR); //$NON-NLS-1$
+ }
+ Generation newGeneration = new Generation(nextGenerationId++);
+ return newGeneration;
+ }
+ }
+
+ void unlockGeneration(Generation generation) {
+ synchronized (this.infoMonitor) {
+ if (generationLocks == null) {
+ throw new IllegalStateException("The generation id was not locked."); //$NON-NLS-1$
+ }
+ generationLocks.unlock(generation.getGenerationId());
+ }
+ }
+
+ Generation restoreGeneration(long generationId, File content, boolean isDirectory, boolean hasPackageInfo) {
+ synchronized (this.infoMonitor) {
+ Generation restoredGeneration = new Generation(generationId, content, isDirectory, hasPackageInfo);
+ return restoredGeneration;
+ }
+ }
+
+ public Storage getStorage() {
+ return storage;
+ }
+
+ void delete(Generation generation) {
+ synchronized (this.infoMonitor) {
+ try {
+ getStorage().delete(getStorage().getFile(getBundleId() + "/" + generation.getGenerationId(), false)); //$NON-NLS-1$
+ } catch (IOException e) {
+ storage.getLogServices().log(EquinoxContainer.NAME, FrameworkLogEntry.WARNING, "Error deleting generation.", e); //$NON-NLS-1$
+ }
+ }
+ }
+
+ public long getNextGenerationId() {
+ synchronized (this.infoMonitor) {
+ return nextGenerationId;
+ }
+ }
+
+ public File getDataFile(String path) {
+ File dataRoot = getStorage().getFile(getBundleId() + "/" + Storage.BUNDLE_DATA_DIR, false); //$NON-NLS-1$
+ if (!dataRoot.exists() && (storage.isReadOnly() || !dataRoot.mkdirs())) {
+ if (getStorage().getConfiguration().getDebug().DEBUG_GENERAL)
+ Debug.println("Unable to create bundle data directory: " + dataRoot.getAbsolutePath()); //$NON-NLS-1$
+ return null;
+ }
+ return path == null ? dataRoot : new File(dataRoot, path);
+ }
+
+ // Used to check the bundle manifest file for any package information.
+ // This is used when '.' is on the Bundle-ClassPath to prevent reading
+ // the bundle manifest for package information when loading classes.
+ static boolean hasPackageInfo(BundleFile bundleFile) {
+ if (bundleFile == null) {
+ return false;
+ }
+ BundleEntry manifest = bundleFile.getEntry(OSGI_BUNDLE_MANIFEST);
+ if (manifest == null) {
+ return false;
+ }
+ BufferedReader br = null;
+ try {
+ br = new BufferedReader(new InputStreamReader(manifest.getInputStream()));
+ String line;
+ while ((line = br.readLine()) != null) {
+ if (line.length() < 20)
+ continue;
+ switch (line.charAt(0)) {
+ case 'S' :
+ if (line.charAt(1) == 'p')
+ if (line.startsWith("Specification-Title: ") || line.startsWith("Specification-Version: ") || line.startsWith("Specification-Vendor: ")) //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$
+ return true;
+ break;
+ case 'I' :
+ if (line.startsWith("Implementation-Title: ") || line.startsWith("Implementation-Version: ") || line.startsWith("Implementation-Vendor: ")) //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$
+ return true;
+ break;
+ }
+ }
+ } catch (IOException ioe) {
+ // do nothing
+ } finally {
+ if (br != null)
+ try {
+ br.close();
+ } catch (IOException e) {
+ // do nothing
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleLocalizationImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleLocalizationImpl.java
index e2eb1d829..c9c0303b5 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleLocalizationImpl.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/BundleLocalizationImpl.java
@@ -8,10 +8,14 @@
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
-package org.eclipse.core.runtime.internal.adaptor;
+package org.eclipse.osgi.storage;
import java.util.ResourceBundle;
+import org.eclipse.osgi.container.Module;
+import org.eclipse.osgi.container.ModuleRevision;
+import org.eclipse.osgi.internal.framework.EquinoxBundle;
import org.eclipse.osgi.service.localization.BundleLocalization;
+import org.eclipse.osgi.storage.BundleInfo.Generation;
import org.osgi.framework.Bundle;
/**
@@ -30,6 +34,9 @@ public class BundleLocalizationImpl implements BundleLocalization {
* If null is passed for the locale parameter, the default locale is used.
*/
public ResourceBundle getLocalization(Bundle bundle, String locale) {
- return ((org.eclipse.osgi.framework.internal.core.AbstractBundle) (bundle)).getResourceBundle(locale);
+ Module m = ((EquinoxBundle) bundle).getModule();
+ ModuleRevision r = m.getCurrentRevision();
+ Generation g = (Generation) r.getRevisionInfo();
+ return g.getResourceBundle(locale);
}
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/ManifestLocalization.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/ManifestLocalization.java
index 5180da3b5..58eaf6e19 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/ManifestLocalization.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/ManifestLocalization.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2011 IBM Corporation and others.
+ * Copyright (c) 2004, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -14,27 +14,39 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
-import org.eclipse.osgi.framework.internal.core.*;
+import org.eclipse.osgi.container.*;
import org.eclipse.osgi.framework.util.Headers;
-import org.osgi.framework.Bundle;
+import org.eclipse.osgi.storage.BundleInfo.Generation;
import org.osgi.framework.Constants;
+import org.osgi.framework.namespace.HostNamespace;
+import org.osgi.framework.wiring.BundleRevision;
/**
- * This class is used by the Bundle Class to localize manifest headers.
+ * This class is used to localize manifest headers for a revision.
*/
public class ManifestLocalization {
- final static String DEFAULT_ROOT = FrameworkProperties.getProperty("equinox.root.locale", "en"); //$NON-NLS-1$ //$NON-NLS-2$
- private final AbstractBundle bundle;
+ final String defaultRoot;
+ private final Generation generation;
private final Dictionary<String, String> rawHeaders;
- private Dictionary<String, String> defaultLocaleHeaders = null;
+ private volatile Dictionary<String, String> defaultLocaleHeaders = null;
private final Hashtable<String, BundleResourceBundle> cache = new Hashtable<String, BundleResourceBundle>(5);
- public ManifestLocalization(AbstractBundle bundle, Dictionary<String, String> rawHeaders) {
- this.bundle = bundle;
+ public ManifestLocalization(Generation generation, Dictionary<String, String> rawHeaders, String defaultRoot) {
+ this.generation = generation;
this.rawHeaders = rawHeaders;
+ this.defaultRoot = defaultRoot;
}
- public Dictionary<String, String> getHeaders(String localeString) {
+ public void clearCache() {
+ synchronized (cache) {
+ cache.clear();
+ defaultLocaleHeaders = null;
+ }
+ }
+
+ Dictionary<String, String> getHeaders(String localeString) {
+ if (localeString == null)
+ localeString = Locale.getDefault().toString();
if (localeString.length() == 0)
return rawHeaders;
boolean isDefaultLocale = localeString.equals(Locale.getDefault().toString());
@@ -42,19 +54,17 @@ public class ManifestLocalization {
if (isDefaultLocale && currentDefault != null) {
return currentDefault;
}
- try {
- bundle.checkValid();
- } catch (IllegalStateException ex) {
+ if (generation.getRevision().getRevisions().getModule().getState().equals(Module.State.UNINSTALLED)) {
// defaultLocaleHeaders should have been initialized on uninstall
if (currentDefault != null)
return currentDefault;
return rawHeaders;
}
ResourceBundle localeProperties = getResourceBundle(localeString, isDefaultLocale);
- Enumeration<String> e = this.rawHeaders.keys();
+ Enumeration<String> eKeys = this.rawHeaders.keys();
Headers<String, String> localeHeaders = new Headers<String, String>(this.rawHeaders.size());
- while (e.hasMoreElements()) {
- String key = e.nextElement();
+ while (eKeys.hasMoreElements()) {
+ String key = eKeys.nextElement();
String value = this.rawHeaders.get(key);
if (value.startsWith("%") && (value.length() > 1)) { //$NON-NLS-1$
String propertiesKey = value.substring(1);
@@ -88,7 +98,7 @@ public class ManifestLocalization {
* This method find the appropriate Manifest Localization file inside the
* bundle. If not found, return null.
*/
- public ResourceBundle getResourceBundle(String localeString, boolean isDefaultLocale) {
+ ResourceBundle getResourceBundle(String localeString, boolean isDefaultLocale) {
BundleResourceBundle resourceBundle = lookupResourceBundle(localeString);
if (isDefaultLocale)
return (ResourceBundle) resourceBundle;
@@ -148,34 +158,22 @@ public class ManifestLocalization {
}
private URL findResource(String resource) {
- AbstractBundle searchBundle = bundle;
- if (bundle.isResolved()) {
- if (bundle.isFragment() && bundle.getHosts() != null) {
- //if the bundle is a fragment, look in the host first
- searchBundle = bundle.getHosts()[0];
- if (searchBundle.getState() == Bundle.UNINSTALLED)
- searchBundle = bundle;
+ ModuleWiring searchWiring = generation.getRevision().getWiring();
+ if (searchWiring != null) {
+ if ((generation.getRevision().getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) {
+ List<ModuleWire> hostWires = searchWiring.getRequiredModuleWires(HostNamespace.HOST_NAMESPACE);
+ searchWiring = (hostWires == null || hostWires.isEmpty()) ? null : hostWires.get(0).getProviderWiring();
}
- return findInResolved(resource, searchBundle);
}
- return searchBundle.getEntry0(resource);
- }
-
- private static URL findInResolved(String filePath, AbstractBundle bundleHost) {
- URL result = bundleHost.getEntry0(filePath);
- if (result != null)
- return result;
- return findInFragments(filePath, bundleHost);
- }
-
- private static URL findInFragments(String filePath, AbstractBundle searchBundle) {
- BundleFragment[] fragments = searchBundle.getFragments();
- URL fileURL = null;
- for (int i = 0; fragments != null && i < fragments.length && fileURL == null; i++) {
- if (fragments[i].getState() != Bundle.UNINSTALLED)
- fileURL = fragments[i].getEntry0(filePath);
+ if (searchWiring != null) {
+ int lastSlash = resource.lastIndexOf('/');
+ String path = lastSlash > 0 ? resource.substring(0, lastSlash) : "/"; //$NON-NLS-1$
+ String fileName = lastSlash != -1 ? resource.substring(lastSlash + 1) : resource;
+ List<URL> result = searchWiring.findEntries(path, fileName, 0);
+ return (result == null || result.isEmpty()) ? null : result.get(0);
}
- return fileURL;
+ // search the raw bundle file for the generation
+ return generation.getEntry(resource);
}
private interface BundleResourceBundle {
@@ -232,7 +230,7 @@ public class ManifestLocalization {
}
public boolean isStemEmpty() {
- if (DEFAULT_ROOT.equals(localeString))
+ if (defaultRoot.equals(localeString))
return false;
if (parent == null)
return true;
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/NativeCodeFinder.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/NativeCodeFinder.java
new file mode 100644
index 000000000..2e014a920
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/NativeCodeFinder.java
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.storage;
+
+import java.io.File;
+import java.util.*;
+import org.eclipse.osgi.container.*;
+import org.eclipse.osgi.container.namespaces.EquinoxNativeCodeNamespace;
+import org.eclipse.osgi.internal.hookregistry.ClassLoaderHook;
+import org.eclipse.osgi.next.internal.debug.Debug;
+import org.eclipse.osgi.storage.BundleInfo.Generation;
+import org.eclipse.osgi.storage.bundlefile.BundleEntry;
+import org.eclipse.osgi.storage.bundlefile.BundleFile;
+import org.osgi.framework.namespace.HostNamespace;
+import org.osgi.framework.wiring.BundleRevision;
+
+public class NativeCodeFinder {
+ private static final String[] EMPTY_STRINGS = new String[0];
+ public static final String EXTERNAL_LIB_PREFIX = "external:"; //$NON-NLS-1$
+ private final Generation generation;
+ private final Debug debug;
+ // This is only used to keep track of when the same native library is loaded more than once
+ private final Collection<String> loadedNativeCode = new ArrayList<String>(1);
+
+ public NativeCodeFinder(Generation generation) {
+ this.generation = generation;
+ this.debug = generation.getBundleInfo().getStorage().getConfiguration().getDebug();
+ }
+
+ /*
+ * Maps an already mapped library name to additional library file extensions.
+ * This is needed on platforms like AIX where .a and .so can be used as library file
+ * extensions, but System.mapLibraryName only returns a single string.
+ */
+ public String[] mapLibraryNames(String mappedLibName) {
+ int extIndex = mappedLibName.lastIndexOf('.');
+ List<String> LIB_EXTENSIONS = generation.getBundleInfo().getStorage().getConfiguration().LIB_EXTENSIONS;
+ if (LIB_EXTENSIONS.isEmpty() || extIndex < 0)
+ return EMPTY_STRINGS;
+ String libNameBase = mappedLibName.substring(0, extIndex);
+ String[] results = new String[LIB_EXTENSIONS.size()];
+ for (int i = 0; i < results.length; i++)
+ results[i] = libNameBase + LIB_EXTENSIONS.get(i);
+ return results;
+ }
+
+ String findLibrary(String libname) {
+ String path = findLibrary0(libname);
+ if (path != null) {
+ synchronized (loadedNativeCode) {
+ if (loadedNativeCode.contains(path) || generation.getBundleInfo().getStorage().getConfiguration().COPY_NATIVES) {
+ // we must copy the library to a temp space to allow another class loader to load the library
+ String temp = generation.getBundleInfo().getStorage().copyToTempLibrary(generation, path);
+ if (temp != null)
+ path = temp;
+ } else {
+ loadedNativeCode.add(path);
+ }
+ }
+ }
+ return path;
+ }
+
+ private String findLibrary0(String libname) {
+ String path = null;
+ List<ClassLoaderHook> hooks = generation.getBundleInfo().getStorage().getConfiguration().getHookRegistry().getClassLoaderHooks();
+ for (ClassLoaderHook hook : hooks) {
+ path = hook.findLocalLibrary(generation, libname);
+ if (path != null) {
+ return path;
+ }
+ }
+ String mappedName = System.mapLibraryName(libname);
+ String[] altMappedNames = mapLibraryNames(mappedName);
+
+ // first check Bundle-NativeCode header
+ path = findBundleNativeCode(libname, mappedName, altMappedNames);
+ // next check eclipse specific support
+ return path != null ? path : findEclipseNativeCode(libname, mappedName, altMappedNames);
+ }
+
+ private String findEclipseNativeCode(String libname, String mappedName, String[] altMappedNames) {
+ if (libname.length() == 0)
+ return null;
+ if (libname.charAt(0) == '/' || libname.charAt(0) == '\\')
+ libname = libname.substring(1);
+ String result = searchEclipseVariants(mappedName);
+ if (result != null)
+ return result;
+ for (int i = 0; i < altMappedNames.length && result == null; i++)
+ result = searchEclipseVariants(altMappedNames[i]);
+ return result;
+ }
+
+ private String searchEclipseVariants(String path) {
+ List<String> ECLIPSE_LIB_VARIANTS = generation.getBundleInfo().getStorage().getConfiguration().ECLIPSE_LIB_VARIANTS;
+ for (String variant : ECLIPSE_LIB_VARIANTS) {
+ BundleFile baseBundleFile = generation.getBundleFile();
+ BundleEntry libEntry = baseBundleFile.getEntry(variant + path);
+ if (libEntry != null) {
+ File libFile = baseBundleFile.getFile(variant + path, true);
+ if (libFile == null)
+ return null;
+ // see bug 88697 - HP requires libraries to have executable permissions
+ if (org.eclipse.osgi.service.environment.Constants.OS_HPUX.equals(generation.getBundleInfo().getStorage().getConfiguration().getOS())) {
+ try {
+ // use the string array method in case there is a space in the path
+ Runtime.getRuntime().exec(new String[] {"chmod", "755", libFile.getAbsolutePath()}).waitFor(); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return libFile.getAbsolutePath();
+ }
+ }
+ return null;
+ }
+
+ private String findBundleNativeCode(String libname, String mappedName, String[] altMappedNames) {
+ String path = null;
+ if (debug.DEBUG_LOADER)
+ Debug.println(" mapped library name: " + mappedName); //$NON-NLS-1$
+ List<String> nativePaths = getNativePaths();
+ if (nativePaths.isEmpty()) {
+ return null;
+ }
+ path = findNativePath(nativePaths, mappedName);
+ if (path == null) {
+ for (int i = 0; i < altMappedNames.length && path == null; i++)
+ path = findNativePath(nativePaths, altMappedNames[i]);
+ }
+ if (path == null) {
+ if (debug.DEBUG_LOADER)
+ Debug.println(" library does not exist: " + mappedName); //$NON-NLS-1$
+ path = findNativePath(nativePaths, libname);
+ }
+ if (debug.DEBUG_LOADER)
+ Debug.println(" returning library: " + path); //$NON-NLS-1$
+ return path;
+ }
+
+ private List<String> getNativePaths() {
+ ModuleRevision revision = generation.getRevision();
+ ModuleWiring wiring = revision.getWiring();
+ if (wiring == null) {
+ // unresolved? should not be possible
+ return Collections.emptyList();
+ }
+ if ((revision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) {
+ List<ModuleWire> hosts = wiring.getRequiredModuleWires(HostNamespace.HOST_NAMESPACE);
+ if (!hosts.isEmpty()) {
+ // just use the first host wiring
+ wiring = hosts.get(0).getProviderWiring();
+ }
+ }
+
+ List<ModuleWire> nativeCode = wiring.getRequiredModuleWires(EquinoxNativeCodeNamespace.EQUINOX_NATIVECODE_NAMESPACE);
+ if (nativeCode.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ // TODO just taking the first paths for the revision, need to sort correctly
+ for (ModuleWire moduleWire : nativeCode) {
+ if (moduleWire.getRequirer().equals(revision)) {
+ @SuppressWarnings("unchecked")
+ List<String> result = (List<String>) nativeCode.get(0).getRequirement().getAttributes().get(EquinoxNativeCodeNamespace.REQUIREMENT_NATIVE_PATHS_ATTRIBUTE);
+ if (result != null)
+ return result;
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ private String findNativePath(List<String> nativePaths, String libname) {
+ int slash = libname.lastIndexOf('/');
+ if (slash >= 0)
+ libname = libname.substring(slash + 1);
+ for (String nativePath : nativePaths) {
+ slash = nativePath.lastIndexOf('/');
+ String path = slash < 0 ? nativePath : nativePath.substring(slash + 1);
+ if (path.equals(libname)) {
+ if (nativePath.startsWith(NativeCodeFinder.EXTERNAL_LIB_PREFIX)) {
+ // references an external library; do variable substitution
+ String externalPath = generation.getBundleInfo().getStorage().getConfiguration().substituteVars(nativePath.substring(NativeCodeFinder.EXTERNAL_LIB_PREFIX.length()));
+ File nativeFile = new File(externalPath);
+ return nativeFile.getAbsolutePath();
+ }
+ // this is a normal library contained within the bundle
+ File nativeFile = generation.getBundleFile().getFile(nativePath, true);
+ if (nativeFile != null)
+ return nativeFile.getAbsolutePath();
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/PermissionData.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/PermissionData.java
new file mode 100644
index 000000000..b45e3ee7f
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/PermissionData.java
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.storage;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Permission Storage interface for managing a persistent storage of
+ * bundle permissions.
+ *
+ * <p>This class is used to provide methods to manage
+ * persistent storage of bundle permissions.
+ */
+public class PermissionData {
+ private static final int PERMDATA_VERSION = 1;
+ private final Map<String, String[]> locations = new HashMap<String, String[]>();
+ private String[] defaultInfos;
+ private String[] condPermInfos;
+ private boolean dirty;
+
+ /**
+ * Returns the locations that have permission data assigned to them,
+ * that is, locations for which permission data
+ * exists in persistent storage.
+ *
+ * @return The locations that have permission data in
+ * persistent storage, or <tt>null</tt> if there is no permission data
+ * in persistent storage.
+ */
+ public String[] getLocations() {
+ synchronized (locations) {
+ String[] result = new String[locations.size()];
+ int i = 0;
+ for (Iterator<String> iLocs = locations.keySet().iterator(); iLocs.hasNext(); i++)
+ result[i] = iLocs.next();
+ return result;
+ }
+ }
+
+ /**
+ * Gets the permission data assigned to the specified
+ * location.
+ *
+ * @param location The location whose permission data is to
+ * be returned.
+ * The location can be <tt>null</tt> for the default permission data.
+ *
+ * @return The permission data assigned to the specified
+ * location, or <tt>null</tt> if that location has not been assigned any
+ * permission data.
+ */
+ public String[] getPermissionData(String location) {
+ if (location == null)
+ return defaultInfos;
+ synchronized (locations) {
+ if (locations.size() == 0)
+ return null;
+ return locations.get(location);
+ }
+ }
+
+ /**
+ * Assigns the specified permission data to the specified
+ * location.
+ *
+ * @param location The location that will be assigned the
+ * permissions.
+ * The location can be <tt>null</tt> for the default permission data.
+ * @param data The permission data to be assigned, or <tt>null</tt>
+ * if the specified location is to be removed from persistent storaqe.
+ */
+ public void setPermissionData(String location, String[] data) {
+ if (location == null) {
+ defaultInfos = data;
+ return;
+ }
+ synchronized (locations) {
+ if (data == null)
+ locations.remove(location);
+ else
+ locations.put(location, data);
+ }
+ setDirty(true);
+ }
+
+ /**
+ * Persists the array of encoded ConditionalPermissionInfo strings
+ * @param infos an array of encoded ConditionalPermissionInfo strings
+ */
+ public void saveConditionalPermissionInfos(String[] infos) {
+ condPermInfos = infos;
+ setDirty(true);
+ }
+
+ /**
+ * Returns the persistent array of encoded ConditionalPermissionInfo strings
+ * @return an array of encoded ConditionalPermissionInfo strings or null
+ * if none exist in persistent storage.
+ */
+ public String[] getConditionalPermissionInfos() {
+ return condPermInfos;
+ }
+
+ boolean isDirty() {
+ return dirty;
+ }
+
+ private void setDirty(boolean dirty) {
+ this.dirty = dirty;
+ }
+
+ void readPermissionData(DataInputStream in) throws IOException {
+ int version = in.readInt();
+ int dataSize = in.readInt();
+ byte[] bytes = new byte[dataSize];
+ in.readFully(bytes);
+ if (PERMDATA_VERSION == version) {
+ DataInputStream temp = new DataInputStream(new ByteArrayInputStream(bytes));
+ try {
+ // read the default permissions first
+ int numPerms = temp.readInt();
+ if (numPerms > 0) {
+ String[] perms = new String[numPerms];
+ for (int i = 0; i < numPerms; i++)
+ perms[i] = temp.readUTF();
+ setPermissionData(null, perms);
+ }
+ int numLocs = temp.readInt();
+ if (numLocs > 0) {
+ for (int i = 0; i < numLocs; i++) {
+ String loc = temp.readUTF();
+ numPerms = temp.readInt();
+ String[] perms = new String[numPerms];
+ for (int j = 0; j < numPerms; j++)
+ perms[j] = temp.readUTF();
+ setPermissionData(loc, perms);
+ }
+ }
+ int numCondPerms = temp.readInt();
+ if (numCondPerms > 0) {
+ String[] condPerms = new String[numCondPerms];
+ for (int i = 0; i < numCondPerms; i++) {
+ condPerms[i] = temp.readUTF();
+ }
+ saveConditionalPermissionInfos(condPerms);
+ }
+
+ } finally {
+ setDirty(false);
+ temp.close();
+ }
+ }
+ }
+
+ void savePermissionData(DataOutputStream out) throws IOException {
+ out.writeInt(PERMDATA_VERSION);
+ // create a temporary in memory stream so we can figure out the length
+ ByteArrayOutputStream tempBytes = new ByteArrayOutputStream();
+ DataOutputStream temp = new DataOutputStream(tempBytes);
+ // always write the default permissions first
+ String[] defaultPerms = getPermissionData(null);
+ temp.writeInt(defaultPerms == null ? 0 : defaultPerms.length);
+ if (defaultPerms != null)
+ for (int i = 0; i < defaultPerms.length; i++)
+ temp.writeUTF(defaultPerms[i]);
+ String[] locs = getLocations();
+ temp.writeInt(locs == null ? 0 : locs.length);
+ if (locs != null)
+ for (int i = 0; i < locs.length; i++) {
+ temp.writeUTF(locs[i]);
+ String[] perms = getPermissionData(locs[i]);
+ temp.writeInt(perms == null ? 0 : perms.length);
+ if (perms != null)
+ for (int j = 0; j < perms.length; j++)
+ temp.writeUTF(perms[j]);
+ }
+ String[] condPerms = getConditionalPermissionInfos();
+ temp.writeInt(condPerms == null ? 0 : condPerms.length);
+ if (condPerms != null)
+ for (int i = 0; i < condPerms.length; i++)
+ temp.writeUTF(condPerms[i]);
+ temp.close();
+
+ out.writeInt(tempBytes.size());
+ out.write(tempBytes.toByteArray());
+ setDirty(false);
+ }
+}
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
new file mode 100644
index 000000000..ec1f252e2
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/Storage.java
@@ -0,0 +1,1433 @@
+/*******************************************************************************
+ * Copyright (c) 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osgi.storage;
+
+import org.eclipse.osgi.storage.url.reference.ReferenceInputStream;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.*;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import org.eclipse.osgi.container.*;
+import org.eclipse.osgi.container.ModuleRevisionBuilder.GenericInfo;
+import org.eclipse.osgi.container.builders.OSGiManifestBuilderFactory;
+import org.eclipse.osgi.container.namespaces.EclipsePlatformNamespace;
+import org.eclipse.osgi.container.namespaces.EquinoxNativeCodeNamespace;
+import org.eclipse.osgi.framework.log.FrameworkLogEntry;
+import org.eclipse.osgi.framework.util.FilePath;
+import org.eclipse.osgi.framework.util.SecureAction;
+import org.eclipse.osgi.internal.baseadaptor.AdaptorMsg;
+import org.eclipse.osgi.internal.baseadaptor.AdaptorUtil;
+import org.eclipse.osgi.internal.container.LockSet;
+import org.eclipse.osgi.internal.framework.*;
+import org.eclipse.osgi.internal.hookregistry.*;
+import org.eclipse.osgi.internal.hookregistry.StorageHookFactory.StorageHook;
+import org.eclipse.osgi.internal.log.EquinoxLogServices;
+import org.eclipse.osgi.internal.permadmin.SecurityAdmin;
+import org.eclipse.osgi.next.internal.debug.Debug;
+import org.eclipse.osgi.service.datalocation.Location;
+import org.eclipse.osgi.storage.BundleInfo.Generation;
+import org.eclipse.osgi.storage.bundlefile.*;
+import org.eclipse.osgi.util.ManifestElement;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.framework.*;
+import org.osgi.framework.wiring.BundleWiring;
+
+public class Storage {
+ public static final int VERSION = 1;
+ 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$
+ public static final String ECLIPSE_SYSTEMBUNDLE = "Eclipse-SystemBundle"; //$NON-NLS-1$
+ public static final String DELETE_FLAG = ".delete"; //$NON-NLS-1$
+ public static final String LIB_TEMP = "libtemp"; //$NON-NLS-1$
+
+ private static final String J2SE = "J2SE-"; //$NON-NLS-1$
+ private static final String JAVASE = "JavaSE-"; //$NON-NLS-1$
+ private static final String PROFILE_EXT = ".profile"; //$NON-NLS-1$
+ static final SecureAction secureAction = AccessController.doPrivileged(SecureAction.createSecureAction());
+
+ private final EquinoxContainer equinoxContainer;
+ private final String installPath;
+ private final Location osgiLocation;
+ private final File childRoot;
+ private final File parentRoot;
+ private final PermissionData permissionData;
+ private final SecurityAdmin securityAdmin;
+ private final ModuleContainerAdaptor adaptor;
+ private final ModuleDatabase moduleDatabase;
+ private final ModuleContainer moduleContainer;
+ private final Object saveMonitor = new Object();
+ private long lastSavedTimestamp = -1;
+ private final LockSet<Long> idLocks = new LockSet<Long>(false);
+ private final MRUBundleFileList mruList = new MRUBundleFileList();
+
+ public Storage(EquinoxContainer container) throws IOException {
+ equinoxContainer = container;
+
+ // we need to set the install path as soon as possible so we can determine
+ // the absolute location of install relative URLs
+ Location installLoc = container.getLocations().getInstallLocation();
+ URL installURL = installLoc.getURL();
+ // assume install URL is file: based
+ installPath = installURL.getPath();
+
+ Location configLocation = container.getLocations().getConfigurationLocation();
+ Location parentConfigLocation = configLocation.getParentLocation();
+ Location osgiParentLocation = null;
+ if (parentConfigLocation != null) {
+ osgiParentLocation = parentConfigLocation.createLocation(null, parentConfigLocation.getDataArea(EquinoxContainer.NAME), true);
+ }
+ this.osgiLocation = configLocation.createLocation(osgiParentLocation, configLocation.getDataArea(EquinoxContainer.NAME), configLocation.isReadOnly());
+ this.childRoot = new File(osgiLocation.getURL().getFile());
+
+ if (Boolean.valueOf(container.getConfiguration().getConfiguration(EquinoxConfiguration.PROP_CLEAN)).booleanValue()) {
+ cleanOSGiStorage(osgiLocation, childRoot);
+ }
+ if (!this.osgiLocation.isReadOnly()) {
+ this.childRoot.mkdirs();
+ }
+ Location parent = this.osgiLocation.getParentLocation();
+ parentRoot = parent == null ? null : new File(osgiLocation.getURL().getFile(), EquinoxContainer.NAME);
+
+ File frameworkInfo = getFile(FRAMEWORK_INFO, true);
+ DataInputStream in = null;
+ if (frameworkInfo.exists()) {
+ try {
+ in = new DataInputStream(new FileInputStream(frameworkInfo));
+ } catch (IOException e) {
+ // do nothing
+ }
+ }
+ try {
+ Map<Long, Generation> generations = loadGenerations(in);
+ this.permissionData = loadPermissionData(in);
+ this.securityAdmin = new SecurityAdmin(null, this.permissionData);
+ this.adaptor = new EquinoxContainerAdaptor(equinoxContainer, this, generations);
+ this.moduleDatabase = new ModuleDatabase(adaptor);
+ this.moduleContainer = new ModuleContainer(this.adaptor, this.moduleDatabase);
+ if (in != null) {
+ moduleDatabase.load(in);
+ }
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ // just move on
+ }
+ }
+ }
+ checkSystemBundle();
+ }
+
+ private static PermissionData loadPermissionData(DataInputStream in) throws IOException {
+ PermissionData permData = new PermissionData();
+ if (in != null) {
+ permData.readPermissionData(in);
+ }
+ return permData;
+ }
+
+ private void checkSystemBundle() {
+ Module systemModule = moduleContainer.getModule(0);
+ Generation newGeneration = null;
+ try {
+ if (systemModule == null) {
+ BundleInfo info = new BundleInfo(this, 0, 0);
+ newGeneration = info.createGeneration();
+
+ File contentFile = getSystemContent();
+ newGeneration.setContent(contentFile);
+
+ ModuleRevisionBuilder builder = getBuilder(newGeneration);
+ systemModule = moduleContainer.install(null, Constants.SYSTEM_BUNDLE_LOCATION, builder, newGeneration);
+ moduleContainer.resolve(Arrays.asList(systemModule), false);
+ } else {
+ ModuleRevision currentRevision = systemModule.getCurrentRevision();
+ Generation currentGeneration = currentRevision == null ? null : (Generation) currentRevision.getRevisionInfo();
+ if (currentGeneration == null) {
+ throw new IllegalStateException("No current revision for system bundle."); //$NON-NLS-1$
+ }
+ try {
+ ModuleRevisionBuilder newBuilder = getBuilder(currentGeneration);
+ if (needUpdate(currentRevision, newBuilder)) {
+ newGeneration = currentGeneration.getBundleInfo().createGeneration();
+ moduleContainer.update(systemModule, newBuilder, newGeneration);
+ moduleContainer.refresh(Arrays.asList(systemModule));
+ }
+ } catch (BundleException e) {
+ throw new IllegalStateException("Could not create a builder for the system bundle.", e); //$NON-NLS-1$
+ }
+ }
+ } catch (Exception e) {
+ if (e instanceof RuntimeException) {
+ throw (RuntimeException) e;
+ }
+ throw new RuntimeException("Error occurred while checking the system module.", e); //$NON-NLS-1$
+ } finally {
+ if (newGeneration != null) {
+ newGeneration.getBundleInfo().unlockGeneration(newGeneration);
+ }
+ }
+ }
+
+ public void close() {
+ try {
+ save();
+ } catch (IOException e) {
+ getLogServices().log(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, "Error saving on shutdown", e);
+ }
+
+ // close all the generations
+ List<Module> modules = moduleContainer.getModules();
+ for (Module module : modules) {
+ for (ModuleRevision revision : module.getRevisions().getModuleRevisions()) {
+ Generation generation = (Generation) revision.getRevisionInfo();
+ if (generation != null) {
+ generation.close();
+ }
+ }
+ }
+ mruList.shutdown();
+ }
+
+ private boolean needUpdate(ModuleRevision currentRevision, ModuleRevisionBuilder newBuilder) {
+ if (!currentRevision.getVersion().equals(newBuilder.getVersion())) {
+ return true;
+ }
+ // only do this advanced check if in dev mode
+ if (!equinoxContainer.getConfiguration().inDevelopmentMode()) {
+ return false;
+ }
+ List<ModuleCapability> currentCapabilities = currentRevision.getModuleCapabilities(null);
+ List<GenericInfo> newCapabilities = newBuilder.getCapabilities();
+ if (currentCapabilities.size() != newCapabilities.size()) {
+ return true;
+ }
+
+ int size = currentCapabilities.size();
+ for (int i = 0; i < size; i++) {
+ if (!equivilant(currentCapabilities.get(i), newCapabilities.get(i))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean equivilant(ModuleCapability moduleCapability, GenericInfo genericInfo) {
+ if (!moduleCapability.getNamespace().equals(genericInfo.getNamespace())) {
+ return false;
+ }
+ if (!moduleCapability.getAttributes().equals(genericInfo.getAttributes())) {
+ return false;
+ }
+ if (!moduleCapability.getDirectives().equals(genericInfo.getDirectives())) {
+ return false;
+ }
+ return true;
+ }
+
+ private void cleanOSGiStorage(Location location, File root) {
+ if (location.isReadOnly() || !AdaptorUtil.rm(root)) {
+ equinoxContainer.getLogServices().log(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, "The -clean (osgi.clean) option was not successful. Unable to clean the storage area: " + root.getAbsolutePath(), null); //$NON-NLS-1$
+ }
+ }
+
+ public ModuleDatabase getModuleDatabase() {
+ return moduleDatabase;
+ }
+
+ public ModuleContainerAdaptor getAdaptor() {
+ return adaptor;
+ }
+
+ public ModuleContainer getModuleContainer() {
+ return moduleContainer;
+ }
+
+ public EquinoxConfiguration getConfiguration() {
+ return equinoxContainer.getConfiguration();
+ }
+
+ public EquinoxLogServices getLogServices() {
+ return equinoxContainer.getLogServices();
+ }
+
+ public boolean isReadOnly() {
+ return osgiLocation.isReadOnly();
+ }
+
+ public URLConnection getContentConnection(Module module, String bundleLocation, final InputStream in) throws IOException {
+ if (in != null) {
+ return new URLConnection(null) {
+ /**
+ * @throws IOException
+ */
+ public void connect() throws IOException {
+ connected = true;
+ }
+
+ /**
+ * @throws IOException
+ */
+ public InputStream getInputStream() throws IOException {
+ return (in);
+ }
+ };
+ }
+ if (module == null) {
+ if (bundleLocation == null) {
+ throw new IllegalArgumentException("Module and location cannot be null"); //$NON-NLS-1$
+ }
+ return getContentConnection(bundleLocation);
+ }
+ return getContentConnection(getUpdateLocation(module));
+ }
+
+ private String getUpdateLocation(final Module module) {
+ if (System.getSecurityManager() == null)
+ return getUpdateLocation0(module);
+ return AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ return getUpdateLocation0(module);
+ }
+ });
+ }
+
+ String getUpdateLocation0(Module module) {
+ ModuleRevision current = module.getCurrentRevision();
+ Generation generation = (Generation) current.getRevisionInfo();
+ String updateLocation = generation.getHeaders().get(Constants.BUNDLE_UPDATELOCATION);
+ return updateLocation == null ? module.getLocation() : updateLocation;
+ }
+
+ private URLConnection getContentConnection(String spec) throws IOException {
+ return new URL(spec).openConnection();
+ }
+
+ public Generation install(Module origin, String bundleLocation, URLConnection content) throws BundleException {
+ if (osgiLocation.isReadOnly()) {
+ throw new BundleException("The framework storage area is read only.", BundleException.INVALID_OPERATION); //$NON-NLS-1$
+ }
+ Module existing = moduleContainer.getModule(bundleLocation);
+ if (existing != null) {
+ return (Generation) existing.getCurrentRevision().getRevisionInfo();
+ }
+ URL sourceURL = content.getURL();
+ InputStream in;
+ try {
+ in = content.getInputStream();
+ } catch (IOException e) {
+ throw new BundleException("Error reading bundle content.", e); //$NON-NLS-1$
+ }
+ boolean isReference = in instanceof ReferenceInputStream;
+ File staged = stageContent(in, sourceURL);
+ Generation generation = null;
+ Long lockedID = getNextRootID();
+ try {
+ BundleInfo info = new BundleInfo(this, lockedID, 0);
+ generation = info.createGeneration();
+
+ File contentFile = getContentFile(staged, isReference, lockedID, generation.getGenerationId());
+ generation.setContent(contentFile);
+ setStorageHooks(generation);
+
+ ModuleRevisionBuilder builder = getBuilder(generation);
+ Module m = moduleContainer.install(origin, bundleLocation, builder, generation);
+ if (!lockedID.equals(m.getId())) {
+ // this revision is already installed. delete the generation
+ generation.delete();
+ return (Generation) m.getCurrentRevision().getRevisionInfo();
+ }
+ return generation;
+ } catch (Throwable t) {
+ if (!isReference) {
+ try {
+ delete(staged);
+ } catch (IOException e) {
+ // tried our best
+ }
+ }
+ if (generation != null) {
+ generation.delete();
+ }
+ if (t instanceof BundleException) {
+ throw (BundleException) t;
+ }
+ throw new BundleException("Error occurred installing a bundle.", t); //$NON-NLS-1$
+ } finally {
+ if (generation != null) {
+ generation.getBundleInfo().unlockGeneration(generation);
+ }
+ idLocks.unlock(lockedID);
+ }
+ }
+
+ private void setStorageHooks(Generation generation) throws BundleException {
+ if (generation.getBundleInfo().getBundleId() == 0) {
+ return; // ignore system bundle
+ }
+ List<StorageHookFactory<?, ?, ?>> factories = new ArrayList<StorageHookFactory<?, ?, ?>>(getConfiguration().getHookRegistry().getStorageHookFactories());
+ List<StorageHook<?, ?>> hooks = new ArrayList<StorageHook<?, ?>>(factories.size());
+ for (Iterator<StorageHookFactory<?, ?, ?>> iFactories = factories.iterator(); iFactories.hasNext();) {
+ @SuppressWarnings("unchecked")
+ StorageHookFactory<Object, Object, StorageHook<Object, Object>> next = (StorageHookFactory<Object, Object, StorageHook<Object, Object>>) iFactories.next();
+ StorageHook<Object, Object> hook = next.createStorageHook(generation);
+ hooks.add(hook);
+ }
+ generation.setStorageHooks(Collections.unmodifiableList(hooks), true);
+ for (StorageHook<?, ?> hook : hooks) {
+ hook.initialize(generation.getHeaders());
+ }
+ }
+
+ public ModuleRevisionBuilder getBuilder(Generation generation) throws BundleException {
+ Dictionary<String, String> headers = generation.getHeaders();
+ Map<String, String> mapHeaders;
+ if (headers instanceof Map) {
+ @SuppressWarnings("unchecked")
+ Map<String, String> unchecked = (Map<String, String>) headers;
+ mapHeaders = unchecked;
+ } else {
+ mapHeaders = new HashMap<String, String>();
+ for (Enumeration<String> eKeys = headers.keys(); eKeys.hasMoreElements();) {
+ String key = eKeys.nextElement();
+ mapHeaders.put(key, headers.get(key));
+ }
+ }
+ if (generation.getBundleInfo().getBundleId() != 0) {
+ return OSGiManifestBuilderFactory.createBuilder(mapHeaders);
+ }
+ // First we must make sure the VM profile has been loaded
+ loadVMProfile(generation);
+ // dealing with system bundle find the extra capabilities and exports
+ String extraCapabilities = getSystemExtraCapabilities();
+ String extraExports = getSystemExtraPackages();
+ return OSGiManifestBuilderFactory.createBuilder(mapHeaders, Constants.SYSTEM_BUNDLE_SYMBOLICNAME, extraExports, extraCapabilities);
+ }
+
+ private String getSystemExtraCapabilities() {
+ EquinoxConfiguration equinoxConfig = equinoxContainer.getConfiguration();
+ StringBuilder result = new StringBuilder();
+
+ String systemCapabilities = equinoxConfig.getConfiguration(Constants.FRAMEWORK_SYSTEMCAPABILITIES);
+ if (systemCapabilities != null) {
+ result.append(systemCapabilities).append(", "); //$NON-NLS-1$
+ }
+
+ String extraSystemCapabilities = equinoxConfig.getConfiguration(Constants.FRAMEWORK_SYSTEMCAPABILITIES_EXTRA);
+ if (extraSystemCapabilities != null) {
+ result.append(extraSystemCapabilities).append(", "); //$NON-NLS-1$
+ }
+
+ result.append(EclipsePlatformNamespace.ECLIPSE_PLATFORM_NAMESPACE).append("; "); //$NON-NLS-1$
+ result.append(EquinoxConfiguration.PROP_OSGI_OS).append("=").append(equinoxConfig.getOS()).append("; "); //$NON-NLS-1$ //$NON-NLS-2$
+ result.append(EquinoxConfiguration.PROP_OSGI_WS).append("=").append(equinoxConfig.getWS()).append("; "); //$NON-NLS-1$ //$NON-NLS-2$
+ result.append(EquinoxConfiguration.PROP_OSGI_ARCH).append("=").append(equinoxConfig.getOSArch()).append("; "); //$NON-NLS-1$ //$NON-NLS-2$
+ result.append(EquinoxConfiguration.PROP_OSGI_NL).append("=").append(equinoxConfig.getNL()); //$NON-NLS-1$
+
+ String osName = equinoxConfig.getConfiguration(Constants.FRAMEWORK_OS_NAME);
+ osName = osName == null ? null : osName.toLowerCase();
+ String processor = equinoxConfig.getConfiguration(Constants.FRAMEWORK_PROCESSOR);
+ processor = processor == null ? null : processor.toLowerCase();
+ String osVersion = equinoxConfig.getConfiguration(Constants.FRAMEWORK_OS_VERSION);
+ osVersion = osVersion == null ? null : osVersion.toLowerCase();
+ String language = equinoxConfig.getConfiguration(Constants.FRAMEWORK_LANGUAGE);
+ language = language == null ? null : language.toLowerCase();
+
+ result.append(", "); //$NON-NLS-1$
+ result.append(EquinoxNativeCodeNamespace.EQUINOX_NATIVECODE_NAMESPACE).append("; "); //$NON-NLS-1$
+ result.append(EquinoxNativeCodeNamespace.CAPABILITY_OS_NAME_ATTRIBUTE).append("=").append(osName).append("; "); //$NON-NLS-1$ //$NON-NLS-2$
+ result.append(EquinoxNativeCodeNamespace.CAPABILITY_PROCESSOR_ATTRIBUTE).append("=").append(processor).append("; "); //$NON-NLS-1$ //$NON-NLS-2$
+ result.append(EquinoxNativeCodeNamespace.CAPABILITY_OS_VERSION_ATTRIBUTE + ":Version").append("=").append(osVersion).append("; "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ result.append(EquinoxNativeCodeNamespace.CAPABILITY_LANGUAGE_ATTRIBUTE).append("=").append(language); //$NON-NLS-1$
+ // TODO need a way to configure in arbitrary native code matching attributes
+
+ return result.toString();
+ }
+
+ private String getSystemExtraPackages() {
+ EquinoxConfiguration equinoxConfig = equinoxContainer.getConfiguration();
+ StringBuilder result = new StringBuilder();
+
+ String systemPackages = equinoxConfig.getConfiguration(Constants.FRAMEWORK_SYSTEMPACKAGES);
+ if (systemPackages != null) {
+ result.append(systemPackages);
+ }
+
+ String extraSystemPackages = equinoxConfig.getConfiguration(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA);
+ if (extraSystemPackages != null) {
+ if (result.length() > 0) {
+ result.append(", "); //$NON-NLS-1$
+ }
+ result.append(extraSystemPackages).append(", "); //$NON-NLS-1$
+ }
+
+ return result.toString();
+ }
+
+ 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$
+ }
+ URL sourceURL = content.getURL();
+ InputStream in;
+ try {
+ in = content.getInputStream();
+ } catch (IOException e) {
+ throw new BundleException("Error reading bundle content.", e); //$NON-NLS-1$
+ }
+ boolean isReference = in instanceof ReferenceInputStream;
+ File staged = stageContent(in, sourceURL);
+
+ ModuleRevision current = module.getCurrentRevision();
+ Generation currentGen = (Generation) current.getRevisionInfo();
+
+ BundleInfo bundleInfo = currentGen.getBundleInfo();
+ Generation newGen = bundleInfo.createGeneration();
+
+ try {
+ File contentFile = getContentFile(staged, isReference, bundleInfo.getBundleId(), newGen.getGenerationId());
+ newGen.setContent(contentFile);
+ setStorageHooks(newGen);
+
+ ModuleRevisionBuilder builder = getBuilder(newGen);
+ moduleContainer.update(module, builder, newGen);
+ } catch (Throwable t) {
+ if (!isReference) {
+ try {
+ delete(staged);
+ } catch (IOException e) {
+ // tried our best
+ }
+ }
+ newGen.delete();
+ if (t instanceof BundleException) {
+ throw (BundleException) t;
+ }
+ throw new BundleException("Error occurred installing a bundle.", t); //$NON-NLS-1$
+ } finally {
+ bundleInfo.unlockGeneration(newGen);
+ }
+ return newGen;
+ }
+
+ private File getContentFile(final File staged, final boolean isReference, final long bundleID, final long generationID) throws BundleException {
+ if (System.getSecurityManager() == null)
+ return getContentFile0(staged, isReference, bundleID, generationID);
+ try {
+ return AccessController.doPrivileged(new PrivilegedExceptionAction<File>() {
+ public File run() throws BundleException {
+ return getContentFile0(staged, isReference, bundleID, generationID);
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ if (e.getException() instanceof BundleException)
+ throw (BundleException) e.getException();
+ throw (RuntimeException) e.getException();
+ }
+ }
+
+ File getContentFile0(File staged, boolean isReference, long bundleID, long generationID) throws BundleException {
+ File contentFile;
+ if (!isReference) {
+ File generationRoot = new File(childRoot, bundleID + "/" + generationID); //$NON-NLS-1$
+ if (!generationRoot.mkdirs()) {
+ throw new BundleException("Could not create generation directory: " + generationRoot.getAbsolutePath()); //$NON-NLS-1$
+ }
+ contentFile = new File(generationRoot, BUNDLE_FILE_NAME);
+ staged.renameTo(contentFile);
+ } else {
+ contentFile = staged;
+ }
+ return contentFile;
+ }
+
+ public File getFile(String path, boolean checkParent) {
+ // first check the child location
+ File childPath = new File(childRoot, path);
+ // now check the parent
+ if (checkParent && parentRoot != null) {
+ if (childPath.exists()) {
+ return childPath;
+ }
+ File parentPath = new File(parentRoot, path);
+ if (parentPath.exists()) {
+ // only use the parent file only if it exists;
+ return parentPath;
+ }
+ }
+ // did not exist in both locations; use the child path
+ return childPath;
+ }
+
+ private File stageContent(final InputStream in, final URL sourceURL) throws BundleException {
+ if (System.getSecurityManager() == null)
+ return stageContent0(in, sourceURL);
+ try {
+ return AccessController.doPrivileged(new PrivilegedExceptionAction<File>() {
+ public File run() throws BundleException {
+ return stageContent0(in, sourceURL);
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ if (e.getException() instanceof BundleException)
+ throw (BundleException) e.getException();
+ throw (RuntimeException) e.getException();
+ }
+ }
+
+ File stageContent0(InputStream in, URL sourceURL) throws BundleException {
+ File outFile = null;
+ try {
+ if (in instanceof ReferenceInputStream) {
+ URL reference = ((ReferenceInputStream) in).getReference();
+ if (!"file".equals(reference.getProtocol())) //$NON-NLS-1$
+ throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_URL_CREATE_EXCEPTION, reference));
+ return new File(reference.getPath());
+ }
+
+ outFile = File.createTempFile(BUNDLE_FILE_NAME, ".tmp", childRoot); //$NON-NLS-1$
+ String protocol = sourceURL == null ? null : sourceURL.getProtocol();
+
+ if ("file".equals(protocol)) { //$NON-NLS-1$
+ File inFile = new File(sourceURL.getPath());
+ if (inFile.isDirectory()) {
+ // need to delete the outFile because it is not a directory
+ outFile.delete();
+ AdaptorUtil.copyDir(inFile, outFile);
+ } else {
+ AdaptorUtil.readFile(in, outFile);
+ }
+ } else {
+ AdaptorUtil.readFile(in, outFile);
+ }
+ return outFile;
+ } catch (IOException e) {
+ if (outFile != null) {
+ outFile.delete();
+ }
+ throw new BundleException(AdaptorMsg.BUNDLE_READ_EXCEPTION, BundleException.READ_ERROR, e);
+ }
+ }
+
+ private Long getNextRootID() throws BundleException {
+ moduleDatabase.lockRead();
+ try {
+ Long nextID = moduleDatabase.getNextId();
+ boolean lockedID;
+ try {
+ lockedID = idLocks.tryLock(nextID, 5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new BundleException("Failed to obtain id locks for installation.", BundleException.STATECHANGE_ERROR, e); //$NON-NLS-1$
+ }
+ if (!lockedID) {
+ throw new BundleException("Failed to obtain id locks for installation.", BundleException.STATECHANGE_ERROR); //$NON-NLS-1$
+ }
+ return nextID;
+ } finally {
+ moduleDatabase.unlockRead();
+ }
+ }
+
+ /**
+ * Attempts to set the permissions of the file in a system dependent way.
+ * @param file the file to set the permissions on
+ */
+ public void setPermissions(File file) {
+ String commandProp = getConfiguration().getConfiguration(EquinoxConfiguration.PROP_SETPERMS_CMD);
+ if (commandProp == null)
+ commandProp = getConfiguration().getConfiguration(Constants.FRAMEWORK_EXECPERMISSION);
+ if (commandProp == null)
+ return;
+ String[] temp = ManifestElement.getArrayFromList(commandProp, " "); //$NON-NLS-1$
+ List<String> command = new ArrayList<String>(temp.length + 1);
+ boolean foundFullPath = false;
+ for (int i = 0; i < temp.length; i++) {
+ if ("[fullpath]".equals(temp[i]) || "${abspath}".equals(temp[i])) { //$NON-NLS-1$ //$NON-NLS-2$
+ command.add(file.getAbsolutePath());
+ foundFullPath = true;
+ } else
+ command.add(temp[i]);
+ }
+ if (!foundFullPath)
+ command.add(file.getAbsolutePath());
+ try {
+ Runtime.getRuntime().exec(command.toArray(new String[command.size()])).waitFor();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public BundleFile createBundleFile(File content, Generation generation, boolean isDirectory, boolean isBase) {
+ BundleFile result;
+ try {
+ if (isDirectory) {
+ result = new DirBundleFile(content);
+ } else {
+ result = new ZipBundleFile(content, generation, mruList);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Could not create bundle file.", e); //$NON-NLS-1$
+ }
+ return wrapBundleFile(result, generation, isBase);
+ }
+
+ public BundleFile createNestedBundleFile(String nestedDir, BundleFile bundleFile, Generation generation) {
+ // here we assume the content is a path offset into the base bundle file; create a NestedDirBundleFile
+ return wrapBundleFile(new NestedDirBundleFile(bundleFile, nestedDir), generation, false);
+ }
+
+ public BundleFile wrapBundleFile(BundleFile bundleFile, Generation generation, boolean isBase) {
+ // try creating a wrapper bundlefile out of it.
+ List<BundleFileWrapperFactoryHook> wrapperFactories = getConfiguration().getHookRegistry().getBundleFileWrapperFactoryHooks();
+ BundleFileWrapperChain wrapped = wrapperFactories.isEmpty() ? null : new BundleFileWrapperChain(bundleFile, null);
+ for (BundleFileWrapperFactoryHook wrapperFactory : wrapperFactories) {
+ BundleFile wrapperBundle = wrapperFactory.wrapBundleFile(bundleFile, generation, isBase);
+ if (wrapperBundle != null && wrapperBundle != bundleFile)
+ bundleFile = wrapped = new BundleFileWrapperChain(wrapperBundle, wrapped);
+ }
+
+ return bundleFile;
+ }
+
+ public void compact() {
+ if (!osgiLocation.isReadOnly()) {
+ compact(childRoot);
+ }
+ }
+
+ private void compact(File directory) {
+ if (getConfiguration().getDebug().DEBUG_GENERAL)
+ Debug.println("compact(" + directory.getPath() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ String list[] = directory.list();
+ if (list == null)
+ return;
+
+ int len = list.length;
+ for (int i = 0; i < len; i++) {
+ if (BUNDLE_DATA_DIR.equals(list[i]))
+ continue; /* do not examine the bundles data dir. */
+ File target = new File(directory, list[i]);
+ // if the file is a directory
+ if (!target.isDirectory())
+ continue;
+ File delete = new File(target, DELETE_FLAG);
+ // and the directory is marked for delete
+ if (delete.exists()) {
+ // if rm fails to delete the directory and .delete was removed
+ if (!AdaptorUtil.rm(target) && !delete.exists()) {
+ try {
+ // recreate .delete
+ FileOutputStream out = new FileOutputStream(delete);
+ out.close();
+ } catch (IOException e) {
+ if (getConfiguration().getDebug().DEBUG_GENERAL)
+ Debug.println("Unable to write " + delete.getPath() + ": " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ } else {
+ compact(target); /* descend into directory */
+ }
+ }
+ }
+
+ void delete(final File delete) throws IOException {
+ if (System.getSecurityManager() == null)
+ delete0(delete);
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ public Object run() throws IOException {
+ delete0(delete);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ if (e.getException() instanceof IOException)
+ throw (IOException) e.getException();
+ throw (RuntimeException) e.getException();
+ }
+ }
+
+ void delete0(File delete) throws IOException {
+ if (!AdaptorUtil.rm(delete)) {
+ /* create .delete */
+ FileOutputStream out = new FileOutputStream(new File(delete, DELETE_FLAG));
+ out.close();
+ }
+ }
+
+ public void save() throws IOException {
+ if (isReadOnly()) {
+ return;
+ }
+ if (System.getSecurityManager() == null) {
+ save0();
+ } else {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ public Object run() throws IOException {
+ save0();
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ if (e.getException() instanceof IOException)
+ throw (IOException) e.getException();
+ throw (RuntimeException) e.getException();
+ }
+ }
+ }
+
+ void save0() throws IOException {
+ DataOutputStream out = null;
+ boolean lockedLocation = false;
+ moduleDatabase.lockRead();
+ try {
+ lockedLocation = osgiLocation.lock();
+ synchronized (this.saveMonitor) {
+ if (lastSavedTimestamp == moduleDatabase.getTimestamp())
+ return;
+ out = new DataOutputStream(new FileOutputStream(getFile(FRAMEWORK_INFO, false)));
+ saveGenerations(out);
+ savePermissionData(out);
+ moduleDatabase.store(out, true);
+ lastSavedTimestamp = moduleDatabase.getTimestamp();
+ }
+ } finally {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e) {
+ // tried our best
+ }
+ }
+ if (lockedLocation) {
+ osgiLocation.release();
+ }
+ moduleDatabase.unlockRead();
+ }
+ }
+
+ private void savePermissionData(DataOutputStream out) throws IOException {
+ permissionData.savePermissionData(out);
+ }
+
+ private void saveGenerations(DataOutputStream out) throws IOException {
+ List<Module> modules = moduleContainer.getModules();
+ List<Generation> generations = new ArrayList<Generation>();
+ for (Module module : modules) {
+ ModuleRevision revision = module.getCurrentRevision();
+ if (revision != null) {
+ Generation generation = (Generation) revision.getRevisionInfo();
+ if (generation != null) {
+ generations.add(generation);
+ }
+ }
+ }
+ out.writeInt(VERSION);
+ out.writeInt(generations.size());
+ for (Generation generation : generations) {
+ BundleInfo bundleInfo = generation.getBundleInfo();
+ out.writeLong(bundleInfo.getBundleId());
+ out.writeLong(bundleInfo.getNextGenerationId());
+ out.writeLong(generation.getGenerationId());
+ out.writeBoolean(generation.isDirectory());
+ out.writeBoolean(generation.hasPackageInfo());
+ if (bundleInfo.getBundleId() == 0) {
+ // just write empty string for system bundle content in this case
+ out.writeUTF(""); //$NON-NLS-1$
+ } else {
+ out.writeUTF(new FilePath(installPath).makeRelative(new FilePath(generation.getContent().getAbsolutePath())));
+ }
+ }
+
+ saveStorageHookData(out, generations);
+ }
+
+ private void saveStorageHookData(DataOutputStream out, List<Generation> generations) throws IOException {
+ List<StorageHookFactory<?, ?, ?>> factories = getConfiguration().getHookRegistry().getStorageHookFactories();
+ out.writeInt(factories.size());
+ for (StorageHookFactory<?, ?, ?> factory : factories) {
+ out.writeUTF(factory.getKey());
+ out.writeInt(factory.getStorageVersion());
+
+ // create a temporary in memory stream so we can figure out the length
+ ByteArrayOutputStream tempBytes = new ByteArrayOutputStream();
+ DataOutputStream temp = new DataOutputStream(tempBytes);
+ try {
+ Object saveContext = factory.createSaveContext();
+ for (Generation generation : generations) {
+ if (generation.getBundleInfo().getBundleId() == 0) {
+ continue; // ignore system bundle
+ }
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ StorageHook<Object, Object> hook = generation.getStorageHook((Class) factory.getClass());
+ hook.save(saveContext, temp);
+ }
+ } finally {
+ temp.close();
+ }
+ out.writeInt(tempBytes.size());
+ out.write(tempBytes.toByteArray());
+ }
+ }
+
+ private Map<Long, Generation> loadGenerations(DataInputStream in) throws IOException {
+ if (in == null) {
+ return new HashMap<Long, Generation>(0);
+ }
+ int version = in.readInt();
+ if (version < VERSION)
+ throw new IOException("Perstence version is not correct for loading: " + version + " expecting: " + VERSION); //$NON-NLS-1$ //$NON-NLS-2$
+
+ int numInfos = in.readInt();
+ Map<Long, Generation> result = new HashMap<Long, Generation>(numInfos);
+ List<Generation> generations = new ArrayList<BundleInfo.Generation>(numInfos);
+ for (int i = 0; i < numInfos; i++) {
+ long infoId = in.readLong();
+ long nextGenId = in.readLong();
+ long generationId = in.readLong();
+ boolean isDirectory = in.readBoolean();
+ boolean hasPackageInfo = in.readBoolean();
+ String contentPath = in.readUTF();
+
+ File content;
+ if (infoId == 0) {
+ content = getSystemContent();
+ isDirectory = content != null ? content.isDirectory() : false;
+ } else {
+ content = new File(contentPath);
+ }
+
+ if (content != null && !content.isAbsolute()) {
+ // make sure it has the absolute location instead
+ content = new File(installPath, contentPath);
+ }
+
+ BundleInfo info = new BundleInfo(this, infoId, nextGenId);
+ Generation generation = info.restoreGeneration(generationId, content, isDirectory, hasPackageInfo);
+ result.put(infoId, generation);
+ generations.add(generation);
+ }
+
+ loadStorageHookData(generations, in);
+ return result;
+ }
+
+ private void loadStorageHookData(List<Generation> generations, DataInputStream in) throws IOException {
+ List<StorageHookFactory<?, ?, ?>> factories = new ArrayList<StorageHookFactory<?, ?, ?>>(getConfiguration().getHookRegistry().getStorageHookFactories());
+ Map<Generation, List<StorageHook<?, ?>>> hookMap = new HashMap<Generation, List<StorageHook<?, ?>>>();
+ int numFactories = in.readInt();
+ for (int i = 0; i < numFactories; i++) {
+ String factoryName = in.readUTF();
+ int version = in.readInt();
+ StorageHookFactory<Object, Object, StorageHook<Object, Object>> factory = null;
+ for (Iterator<StorageHookFactory<?, ?, ?>> iFactories = factories.iterator(); iFactories.hasNext();) {
+ @SuppressWarnings("unchecked")
+ StorageHookFactory<Object, Object, StorageHook<Object, Object>> next = (StorageHookFactory<Object, Object, StorageHook<Object, Object>>) iFactories.next();
+ if (next.getKey().equals(factoryName)) {
+ factory = next;
+ iFactories.remove();
+ break;
+ }
+ }
+ int dataSize = in.readInt();
+ byte[] bytes = new byte[dataSize];
+ in.readFully(bytes);
+ if (factory != null) {
+ DataInputStream temp = new DataInputStream(new ByteArrayInputStream(bytes));
+ try {
+ if (factory.isCompatibleWith(version)) {
+ Object loadContext = factory.createLoadContext(version);
+ for (Generation generation : generations) {
+ if (generation.getBundleInfo().getBundleId() == 0) {
+ continue; // ignore system bundle
+ }
+ StorageHook<Object, Object> hook = factory.createStorageHook(generation);
+ hook.load(loadContext, temp);
+ getHooks(hookMap, generation).add(hook);
+ }
+ } else {
+ // recover by reinitializing the hook
+ for (Generation generation : generations) {
+ if (generation.getBundleInfo().getBundleId() == 0) {
+ continue; // ignore system bundle
+ }
+ StorageHook<Object, Object> hook = factory.createStorageHook(generation);
+ hook.initialize(generation.getHeaders());
+ getHooks(hookMap, generation).add(hook);
+ }
+ }
+ } catch (BundleException e) {
+ throw new IOException(e);
+ } finally {
+ temp.close();
+ }
+ }
+ }
+ // now we need to recover for any hooks that are left
+ for (Iterator<StorageHookFactory<?, ?, ?>> iFactories = factories.iterator(); iFactories.hasNext();) {
+ @SuppressWarnings("unchecked")
+ StorageHookFactory<Object, Object, StorageHook<Object, Object>> next = (StorageHookFactory<Object, Object, StorageHook<Object, Object>>) iFactories.next();
+ // recover by reinitializing the hook
+ for (Generation generation : generations) {
+ if (generation.getBundleInfo().getBundleId() == 0) {
+ continue; // ignore system bundle
+ }
+ StorageHook<Object, Object> hook = next.createStorageHook(generation);
+ try {
+ hook.initialize(generation.getHeaders());
+ getHooks(hookMap, generation).add(hook);
+ } catch (BundleException e) {
+ throw new IOException(e);
+ }
+ }
+ }
+ // now set the hooks to the generations
+ for (Generation generation : generations) {
+ generation.setStorageHooks(Collections.unmodifiableList(getHooks(hookMap, generation)), false);
+ }
+ }
+
+ private static List<StorageHook<?, ?>> getHooks(Map<Generation, List<StorageHook<?, ?>>> hookMap, Generation generation) {
+ List<StorageHook<?, ?>> result = hookMap.get(generation);
+ if (result == null) {
+ result = new ArrayList<StorageHook<?, ?>>();
+ hookMap.put(generation, result);
+ }
+ return result;
+ }
+
+ private File getSystemContent() {
+ String frameworkValue = equinoxContainer.getConfiguration().getConfiguration(EquinoxConfiguration.PROP_FRAMEWORK);
+ if (frameworkValue == null || !frameworkValue.startsWith("file:")) { //$NON-NLS-1$
+ return null;
+ }
+ // TODO assumes the location is a file URL
+ File result = new File(frameworkValue.substring(5));
+ if (!result.exists()) {
+ throw new IllegalStateException("Configured framework location does not exist: " + result.getAbsolutePath()); //$NON-NLS-1$
+ }
+ return result;
+ }
+
+ private void loadVMProfile(Generation systemGeneration) {
+ EquinoxConfiguration equinoxConfig = equinoxContainer.getConfiguration();
+ Properties profileProps = findVMProfile(systemGeneration);
+ String systemExports = equinoxConfig.getConfiguration(Constants.FRAMEWORK_SYSTEMPACKAGES);
+ // set the system exports property using the vm profile; only if the property is not already set
+ if (systemExports == null) {
+ systemExports = profileProps.getProperty(Constants.FRAMEWORK_SYSTEMPACKAGES);
+ if (systemExports != null)
+ equinoxConfig.setConfiguration(Constants.FRAMEWORK_SYSTEMPACKAGES, systemExports);
+ }
+
+ // set the org.osgi.framework.bootdelegation property according to the java profile
+ String type = equinoxConfig.getConfiguration(EquinoxConfiguration.PROP_OSGI_JAVA_PROFILE_BOOTDELEGATION); // a null value means ignore
+ String profileBootDelegation = profileProps.getProperty(Constants.FRAMEWORK_BOOTDELEGATION);
+ if (EquinoxConfiguration.PROP_OSGI_BOOTDELEGATION_OVERRIDE.equals(type)) {
+ if (profileBootDelegation == null)
+ equinoxConfig.clearConfiguration(Constants.FRAMEWORK_BOOTDELEGATION); // override with a null value
+ else
+ equinoxConfig.setConfiguration(Constants.FRAMEWORK_BOOTDELEGATION, profileBootDelegation); // override with the profile value
+ } else if (EquinoxConfiguration.PROP_OSGI_BOOTDELEGATION_NONE.equals(type))
+ equinoxConfig.clearConfiguration(Constants.FRAMEWORK_BOOTDELEGATION); // remove the bootdelegation property in case it was set
+ // set the org.osgi.framework.executionenvironment property according to the java profile
+ if (equinoxConfig.getConfiguration(Constants.FRAMEWORK_EXECUTIONENVIRONMENT) == null) {
+ // get the ee from the java profile; if no ee is defined then try the java profile name
+ String ee = profileProps.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT, profileProps.getProperty(EquinoxConfiguration.PROP_OSGI_JAVA_PROFILE_NAME));
+ if (ee != null)
+ equinoxConfig.setConfiguration(Constants.FRAMEWORK_EXECUTIONENVIRONMENT, ee);
+ }
+ // set the org.osgi.framework.system.capabilities property according to the java profile
+ if (equinoxConfig.getConfiguration(Constants.FRAMEWORK_SYSTEMCAPABILITIES) == null) {
+ String systemCapabilities = profileProps.getProperty(Constants.FRAMEWORK_SYSTEMCAPABILITIES);
+ if (systemCapabilities != null)
+ equinoxConfig.setConfiguration(Constants.FRAMEWORK_SYSTEMCAPABILITIES, systemCapabilities);
+ }
+ }
+
+ private Properties findVMProfile(Generation systemGeneration) {
+ Properties result = new Properties();
+ // Find the VM profile name using J2ME properties
+ String j2meConfig = System.getProperty(EquinoxConfiguration.PROP_J2ME_MICROEDITION_CONFIGURATION);
+ String j2meProfiles = System.getProperty(EquinoxConfiguration.PROP_J2ME_MICROEDITION_PROFILES);
+ String vmProfile = null;
+ String javaEdition = null;
+ Version javaVersion = null;
+ if (j2meConfig != null && j2meConfig.length() > 0 && j2meProfiles != null && j2meProfiles.length() > 0) {
+ // save the vmProfile based off of the config and profile
+ // use the last profile; assuming that is the highest one
+ String[] j2meProfileList = ManifestElement.getArrayFromList(j2meProfiles, " "); //$NON-NLS-1$
+ if (j2meProfileList != null && j2meProfileList.length > 0)
+ vmProfile = j2meConfig + '_' + j2meProfileList[j2meProfileList.length - 1];
+ } else {
+ // No J2ME properties; use J2SE properties
+ // Note that the CDC spec appears not to require VM implementations to set the
+ // javax.microedition properties!! So we will try to fall back to the
+ // java.specification.name property, but this is pretty ridiculous!!
+ String javaSpecVersion = System.getProperty(EquinoxConfiguration.PROP_JVM_SPEC_VERSION);
+ // set the profile and EE based off of the java.specification.version
+ // TODO We assume J2ME Foundation and J2SE here. need to support other profiles J2EE ...
+ if (javaSpecVersion != null) {
+ StringTokenizer st = new StringTokenizer(javaSpecVersion, " _-"); //$NON-NLS-1$
+ javaSpecVersion = st.nextToken();
+ String javaSpecName = System.getProperty(EquinoxConfiguration.PROP_JVM_SPEC_NAME);
+ // See bug 291269 we check for Foundation Specification and Foundation Profile Specification
+ if (javaSpecName != null && (javaSpecName.indexOf("Foundation Specification") >= 0 || javaSpecName.indexOf("Foundation Profile Specification") >= 0)) //$NON-NLS-1$ //$NON-NLS-2$
+ vmProfile = "CDC-" + javaSpecVersion + "_Foundation-" + javaSpecVersion; //$NON-NLS-1$ //$NON-NLS-2$
+ else {
+ // look for JavaSE if 1.6 or greater; otherwise look for J2SE
+ Version v16 = new Version("1.6"); //$NON-NLS-1$
+ javaEdition = J2SE;
+ try {
+ javaVersion = new Version(javaSpecVersion);
+ if (v16.compareTo(javaVersion) <= 0)
+ javaEdition = JAVASE;
+ } catch (IllegalArgumentException e) {
+ // do nothing
+ }
+ vmProfile = javaEdition + javaSpecVersion;
+ }
+ }
+ }
+ InputStream profileIn = null;
+ // check for the java profile property for a url
+ String propJavaProfile = equinoxContainer.getConfiguration().getConfiguration(EquinoxConfiguration.PROP_OSGI_JAVA_PROFILE);
+ if (propJavaProfile != null)
+ try {
+ // we assume a URL
+ profileIn = new URL(propJavaProfile).openStream();
+ } catch (IOException e) {
+ // try using a relative path in the system bundle
+ profileIn = findInSystemBundle(systemGeneration, propJavaProfile);
+ }
+ if (profileIn == null && vmProfile != null) {
+ // look for a profile in the system bundle based on the vm profile
+ String javaProfile = vmProfile + PROFILE_EXT;
+ profileIn = findInSystemBundle(systemGeneration, javaProfile);
+ if (profileIn == null)
+ profileIn = getNextBestProfile(systemGeneration, javaEdition, javaVersion);
+ }
+ if (profileIn == null)
+ // the profile url is still null then use the osgi min profile in OSGi by default
+ profileIn = findInSystemBundle(systemGeneration, "JavaSE-1.6.profile"); //$NON-NLS-1$
+ if (profileIn != null) {
+ try {
+ result.load(new BufferedInputStream(profileIn));
+ } catch (IOException e) {
+ // TODO consider logging ...
+ } finally {
+ try {
+ profileIn.close();
+ } catch (IOException ee) {
+ // do nothing
+ }
+ }
+ }
+ // set the profile name if it does not provide one
+ if (result.getProperty(EquinoxConfiguration.PROP_OSGI_JAVA_PROFILE_NAME) == null)
+ if (vmProfile != null)
+ result.put(EquinoxConfiguration.PROP_OSGI_JAVA_PROFILE_NAME, vmProfile.replace('_', '/'));
+ else
+ // last resort; default to the absolute minimum profile name for the framework
+ result.put(EquinoxConfiguration.PROP_OSGI_JAVA_PROFILE_NAME, "JavaSE-1.6"); //$NON-NLS-1$
+ return result;
+ }
+
+ private InputStream getNextBestProfile(Generation systemGeneration, String javaEdition, Version javaVersion) {
+ if (javaVersion == null || (javaEdition != J2SE && javaEdition != JAVASE))
+ return null; // we cannot automatically choose the next best profile unless this is a J2SE or JavaSE vm
+ InputStream bestProfile = findNextBestProfile(systemGeneration, javaEdition, javaVersion);
+ if (bestProfile == null && javaEdition == JAVASE)
+ // if this is a JavaSE VM then search for a lower J2SE profile
+ bestProfile = findNextBestProfile(systemGeneration, J2SE, javaVersion);
+ return bestProfile;
+ }
+
+ private InputStream findNextBestProfile(Generation systemGeneration, String javaEdition, Version javaVersion) {
+ InputStream result = null;
+ int minor = javaVersion.getMinor();
+ do {
+ result = findInSystemBundle(systemGeneration, javaEdition + javaVersion.getMajor() + "." + minor + PROFILE_EXT); //$NON-NLS-1$
+ minor = minor - 1;
+ } while (result == null && minor > 0);
+ return result;
+ }
+
+ private InputStream findInSystemBundle(Generation systemGeneration, String entry) {
+ BundleFile systemContent = systemGeneration.getBundleFile();
+ BundleEntry systemEntry = systemContent != null ? systemContent.getEntry(entry) : null;
+ InputStream result = null;
+ if (systemEntry != null) {
+ try {
+ result = systemEntry.getInputStream();
+ } catch (IOException e) {
+ // Do nothing
+ }
+ }
+ if (result == null) {
+ // Check the ClassLoader in case we're launched off the Java boot classpath
+ ClassLoader loader = getClass().getClassLoader();
+ result = loader == null ? ClassLoader.getSystemResourceAsStream(entry) : loader.getResourceAsStream(entry);
+ }
+ return result;
+ }
+
+ public static Enumeration<URL> findEntries(List<Generation> generations, String path, String filePattern, int options) {
+ List<BundleFile> bundleFiles = new ArrayList<BundleFile>(generations.size());
+ for (Generation generation : generations)
+ bundleFiles.add(generation.getBundleFile());
+ // search all the bundle files
+ List<String> pathList = listEntryPaths(bundleFiles, path, filePattern, options);
+ // return null if no entries found
+ if (pathList.size() == 0)
+ return null;
+ // create an enumeration to enumerate the pathList
+ final String[] pathArray = pathList.toArray(new String[pathList.size()]);
+ final Generation[] generationArray = generations.toArray(new Generation[generations.size()]);
+ return new Enumeration<URL>() {
+ private int curPathIndex = 0;
+ private int curDataIndex = 0;
+ private URL nextElement = null;
+
+ public boolean hasMoreElements() {
+ if (nextElement != null)
+ return true;
+ getNextElement();
+ return nextElement != null;
+ }
+
+ public URL nextElement() {
+ if (!hasMoreElements())
+ throw new NoSuchElementException();
+ URL result = nextElement;
+ // force the next element search
+ getNextElement();
+ return result;
+ }
+
+ private void getNextElement() {
+ nextElement = null;
+ if (curPathIndex >= pathArray.length)
+ // reached the end of the pathArray; no more elements
+ return;
+ while (nextElement == null && curPathIndex < pathArray.length) {
+ String curPath = pathArray[curPathIndex];
+ // search the generation until we have searched them all
+ while (nextElement == null && curDataIndex < generationArray.length)
+ nextElement = generationArray[curDataIndex++].getEntry(curPath);
+ // we have searched all datas then advance to the next path
+ if (curDataIndex >= generationArray.length) {
+ curPathIndex++;
+ curDataIndex = 0;
+ }
+ }
+ }
+ };
+ }
+
+ /**
+ * Returns the names of resources available from a list of bundle files.
+ * No duplicate resource names are returned, each name is unique.
+ * @param bundleFiles the list of bundle files to search in
+ * @param path The path name in which to look.
+ * @param filePattern The file name pattern for selecting resource names in
+ * the specified path.
+ * @param options The options for listing resource names.
+ * @return a list of resource names. If no resources are found then
+ * the empty list is returned.
+ * @see BundleWiring#listResources(String, String, int)
+ */
+ public static List<String> listEntryPaths(List<BundleFile> bundleFiles, String path, String filePattern, int options) {
+ // a list used to store the results of the search
+ List<String> pathList = new ArrayList<String>();
+ Filter patternFilter = null;
+ Hashtable<String, String> patternProps = null;
+ if (filePattern != null) {
+ // Optimization: If the file pattern does not include a wildcard or escape char then it must represent a single file.
+ // Avoid pattern matching and use BundleFile.getEntry() if recursion was not requested.
+ if ((options & BundleWiring.FINDENTRIES_RECURSE) == 0 && filePattern.indexOf('*') == -1 && filePattern.indexOf('\\') == -1) {
+ if (path.length() == 0)
+ path = filePattern;
+ else
+ path += path.charAt(path.length() - 1) == '/' ? filePattern : '/' + filePattern;
+ for (BundleFile bundleFile : bundleFiles) {
+ if (bundleFile.getEntry(path) != null && !pathList.contains(path))
+ pathList.add(path);
+ }
+ return pathList;
+ }
+ // For when the file pattern includes a wildcard.
+ try {
+ // create a file pattern filter with 'filename' as the key
+ patternFilter = FilterImpl.newInstance("(filename=" + sanitizeFilterInput(filePattern) + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ // create a single hashtable to be shared during the recursive search
+ patternProps = new Hashtable<String, String>(2);
+ } catch (InvalidSyntaxException e) {
+ // TODO something unexpected happened; log error and return nothing
+ // Bundle b = context == null ? null : context.getBundle();
+ // eventPublisher.publishFrameworkEvent(FrameworkEvent.ERROR, b, e);
+ return pathList;
+ }
+ }
+ // find the entry paths for the datas
+ for (BundleFile bundleFile : bundleFiles) {
+ listEntryPaths(bundleFile, path, patternFilter, patternProps, options, pathList);
+ }
+ return pathList;
+ }
+
+ private static String sanitizeFilterInput(String filePattern) throws InvalidSyntaxException {
+ StringBuffer buffer = null;
+ boolean foundEscape = false;
+ for (int i = 0; i < filePattern.length(); i++) {
+ char c = filePattern.charAt(i);
+ switch (c) {
+ case '\\' :
+ // we either used the escape found or found a new escape.
+ foundEscape = foundEscape ? false : true;
+ if (buffer != null)
+ buffer.append(c);
+ break;
+ case '(' :
+ case ')' :
+ if (!foundEscape) {
+ if (buffer == null) {
+ buffer = new StringBuffer(filePattern.length() + 16);
+ buffer.append(filePattern.substring(0, i));
+ }
+ // must escape with '\'
+ buffer.append('\\');
+ } else {
+ foundEscape = false; // used the escape found
+ }
+ if (buffer != null)
+ buffer.append(c);
+ break;
+ default :
+ // if we found an escape it has been used
+ foundEscape = false;
+ if (buffer != null)
+ buffer.append(c);
+ break;
+ }
+ }
+ if (foundEscape)
+ throw new InvalidSyntaxException("Trailing escape characters must be escaped.", filePattern); //$NON-NLS-1$
+ return buffer == null ? filePattern : buffer.toString();
+ }
+
+ private static List<String> listEntryPaths(BundleFile bundleFile, String path, Filter patternFilter, Hashtable<String, String> patternProps, int options, List<String> pathList) {
+ if (pathList == null)
+ pathList = new ArrayList<String>();
+ Enumeration<String> entryPaths = bundleFile.getEntryPaths(path);
+ if (entryPaths == null)
+ return pathList;
+ while (entryPaths.hasMoreElements()) {
+ String entry = entryPaths.nextElement();
+ int lastSlash = entry.lastIndexOf('/');
+ if (patternProps != null) {
+ int secondToLastSlash = entry.lastIndexOf('/', lastSlash - 1);
+ int fileStart;
+ int fileEnd = entry.length();
+ if (lastSlash < 0)
+ fileStart = 0;
+ else if (lastSlash != entry.length() - 1)
+ fileStart = lastSlash + 1;
+ else {
+ fileEnd = lastSlash; // leave the lastSlash out
+ if (secondToLastSlash < 0)
+ fileStart = 0;
+ else
+ fileStart = secondToLastSlash + 1;
+ }
+ String fileName = entry.substring(fileStart, fileEnd);
+ // set the filename to the current entry
+ patternProps.put("filename", fileName); //$NON-NLS-1$
+ }
+ // prevent duplicates and match on the patternFilter
+ if (!pathList.contains(entry) && (patternFilter == null || patternFilter.matchCase(patternProps)))
+ pathList.add(entry);
+ // recurse only into entries that are directories
+ if (((options & BundleWiring.FINDENTRIES_RECURSE) != 0) && !entry.equals(path) && entry.length() > 0 && lastSlash == (entry.length() - 1))
+ listEntryPaths(bundleFile, entry, patternFilter, patternProps, options, pathList);
+ }
+ return pathList;
+ }
+
+ public String copyToTempLibrary(Generation generation, String absolutePath) {
+ File libTempDir = new File(childRoot, LIB_TEMP);
+ // we assume the absolutePath is a File path
+ File realLib = new File(absolutePath);
+ String libName = realLib.getName();
+ // find a temp dir for the bundle data and the library;
+ File bundleTempDir = null;
+ File libTempFile = null;
+ // We need a somewhat predictable temp dir for the libraries of a given bundle;
+ // This is not strictly necessary but it does help scenarios where one native library loads another native library without using java.
+ // On some OSes this causes issues because the second library is cannot be found.
+ // This has been worked around by the bundles loading the libraries in a particular order (and setting some LIB_PATH env).
+ // The one catch is that the libraries need to be in the same directory and they must use their original lib names.
+ //
+ // This bit of code attempts to do that by using the bundle ID as an ID for the temp dir along with an incrementing ID
+ // in cases where the temp dir may already exist.
+ Long bundleID = new Long(generation.getBundleInfo().getBundleId());
+ for (int i = 0; i < Integer.MAX_VALUE; i++) {
+ bundleTempDir = new File(libTempDir, bundleID.toString() + "_" + new Integer(i).toString()); //$NON-NLS-1$
+ libTempFile = new File(bundleTempDir, libName);
+ if (bundleTempDir.exists()) {
+ if (libTempFile.exists())
+ continue; // to to next temp file
+ break;
+ }
+ break;
+ }
+ if (!bundleTempDir.exists()) {
+ bundleTempDir.mkdirs();
+ bundleTempDir.deleteOnExit();
+ // This is just a safeguard incase the VM is terminated unexpectantly, it also looks like deleteOnExit cannot really work because
+ // the VM likely will still have a lock on the lib file at the time of VM exit.
+ File deleteFlag = new File(libTempDir, DELETE_FLAG);
+ if (!deleteFlag.exists()) {
+ // need to create a delete flag to force removal the temp libraries
+ try {
+ FileOutputStream out = new FileOutputStream(deleteFlag);
+ out.close();
+ } catch (IOException e) {
+ // do nothing; that would mean we did not make the temp dir successfully
+ }
+ }
+ }
+ // copy the library file
+ try {
+ InputStream in = new FileInputStream(realLib);
+ AdaptorUtil.readFile(in, libTempFile);
+ // set permissions if needed
+ setPermissions(libTempFile);
+ libTempFile.deleteOnExit(); // this probably will not work because the VM will probably have the lib locked at exit
+ // return the temporary path
+ return libTempFile.getAbsolutePath();
+ } catch (IOException e) {
+ equinoxContainer.getLogServices().log(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, e.getMessage(), e);
+ return null;
+ }
+ }
+
+ public SecurityAdmin getSecurityAdmin() {
+ return securityAdmin;
+ }
+}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/SystemBundleFile.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/SystemBundleFile.java
new file mode 100644
index 000000000..c75524400
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/SystemBundleFile.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osgi.storage;
+
+import java.io.*;
+import java.net.URL;
+import java.util.Enumeration;
+import org.eclipse.osgi.framework.util.Headers;
+import org.eclipse.osgi.storage.bundlefile.BundleEntry;
+import org.eclipse.osgi.storage.bundlefile.BundleFile;
+import org.osgi.framework.BundleException;
+
+public class SystemBundleFile extends BundleFile {
+
+ public SystemBundleFile() {
+ super(null);
+ }
+
+ @Override
+ public File getFile(String path, boolean nativeCode) {
+ return null;
+ }
+
+ @Override
+ public BundleEntry getEntry(String path) {
+ if (BundleInfo.OSGI_BUNDLE_MANIFEST.equals(path)) {
+ return new BundleEntry() {
+
+ public InputStream getInputStream() throws IOException {
+ return getManifestURL().openStream();
+ }
+
+ public long getSize() {
+ return 0;
+ }
+
+ public String getName() {
+ return BundleInfo.OSGI_BUNDLE_MANIFEST;
+ }
+
+ public long getTime() {
+ return 0;
+ }
+
+ public URL getLocalURL() {
+ return getManifestURL();
+ }
+
+ public URL getFileURL() {
+ return null;
+ }
+ };
+ }
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getEntryPaths(String path) {
+ return null;
+ }
+
+ @Override
+ public void close() throws IOException {
+ // nothing
+ }
+
+ @Override
+ public void open() throws IOException {
+ // nothing
+ }
+
+ @Override
+ public boolean containsDir(String dir) {
+ return false;
+ }
+
+ URL getManifestURL() {
+ ClassLoader cl = getClass().getClassLoader();
+ try {
+ // get all manifests in your classloader delegation
+ Enumeration<URL> manifests = cl != null ? cl.getResources(BundleInfo.OSGI_BUNDLE_MANIFEST) : ClassLoader.getSystemResources(BundleInfo.OSGI_BUNDLE_MANIFEST);
+ while (manifests.hasMoreElements()) {
+ URL url = manifests.nextElement();
+ try {
+ // check each manifest until we find one with the Eclipse-SystemBundle: true header
+ Headers<String, String> headers = Headers.parseManifest(url.openStream());
+ if ("true".equals(headers.get(Storage.ECLIPSE_SYSTEMBUNDLE))) //$NON-NLS-1$
+ return url;
+ } catch (BundleException e) {
+ // ignore and continue to next URL
+ }
+ }
+ } catch (IOException e) {
+ // ignore and return null
+ }
+ return null;
+ }
+}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleEntry.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleEntry.java
index 91711eada..5819728d8 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleEntry.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleEntry.java
@@ -11,8 +11,6 @@
package org.eclipse.osgi.storage.bundlefile;
-import org.eclipse.osgi.internal.debug.Debug;
-
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
@@ -92,8 +90,8 @@ public abstract class BundleEntry {
public byte[] getBytes() throws IOException {
InputStream in = getInputStream();
int length = (int) getSize();
- if (Debug.DEBUG_LOADER)
- Debug.println(" about to read " + length + " bytes from " + getName()); //$NON-NLS-1$ //$NON-NLS-2$
+ // if (Debug.DEBUG_LOADER)
+ // Debug.println(" about to read " + length + " bytes from " + getName()); //$NON-NLS-1$ //$NON-NLS-2$
return AdaptorUtil.getBytes(in, length, BUF_SIZE);
}
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFile.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFile.java
index 711a056df..320fdc3ba 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFile.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFile.java
@@ -11,19 +11,16 @@
package org.eclipse.osgi.storage.bundlefile;
-import org.eclipse.osgi.storage.url.BundleResourceHandler;
-
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessController;
-import java.util.*;
-import org.eclipse.osgi.baseadaptor.BaseData;
-import org.eclipse.osgi.framework.internal.core.*;
-import org.eclipse.osgi.framework.internal.protocol.bundleresource.Handler;
+import java.util.Enumeration;
+import org.eclipse.osgi.container.Module;
import org.eclipse.osgi.framework.util.SecureAction;
-import org.eclipse.osgi.util.ManifestElement;
+import org.eclipse.osgi.storage.url.BundleResourceHandler;
+import org.eclipse.osgi.storage.url.bundleresource.Handler;
/**
* The BundleFile API is used by Adaptors to read resources out of an
@@ -34,7 +31,6 @@ import org.eclipse.osgi.util.ManifestElement;
* @since 3.2
*/
abstract public class BundleFile {
- protected static final String PROP_SETPERMS_CMD = "osgi.filepermissions.command"; //$NON-NLS-1$
static final SecureAction secureAction = AccessController.doPrivileged(SecureAction.createSecureAction());
/**
* The File object for this BundleFile.
@@ -43,14 +39,6 @@ abstract public class BundleFile {
private int mruIndex = -1;
/**
- * Default constructor
- *
- */
- public BundleFile() {
- // do nothing
- }
-
- /**
* BundleFile constructor
* @param basefile The File object where this BundleFile is
* persistently stored.
@@ -117,47 +105,19 @@ abstract public class BundleFile {
/**
* Returns a URL to access the contents of the entry specified by the path
* @param path the path to the resource
- * @param hostBundleID the host bundle ID
- * @return a URL to access the contents of the entry specified by the path
- * @deprecated use {@link #getResourceURL(String, BaseData, int)}
- */
- public URL getResourceURL(String path, long hostBundleID) {
- return getResourceURL(path, hostBundleID, 0);
- }
-
- /**
- * Returns a URL to access the contents of the entry specified by the path
- * @param path the path to the resource
- * @param hostBundleID the host bundle ID
- * @param index the resource index
- * @return a URL to access the contents of the entry specified by the path
- * @deprecated use {@link #getResourceURL(String, BaseData, int)}
- */
- public URL getResourceURL(String path, long hostBundleID, int index) {
- return internalGetResourceURL(path, null, hostBundleID, index);
- }
-
- /**
- * Returns a URL to access the contents of the entry specified by the path
- * @param path the path to the resource
- * @param hostData the host BaseData
+ * @param hostModule the host module
* @param index the resource index
* @return a URL to access the contents of the entry specified by the path
*/
- public URL getResourceURL(String path, BaseData hostData, int index) {
- return internalGetResourceURL(path, hostData, 0, index);
- }
-
- private URL internalGetResourceURL(String path, BaseData hostData, long hostBundleID, int index) {
+ public URL getResourceURL(String path, Module hostModule, int index) {
BundleEntry bundleEntry = getEntry(path);
if (bundleEntry == null)
return null;
- if (hostData != null)
- hostBundleID = hostData.getBundleID();
+ long hostBundleID = hostModule.getId();
path = fixTrailingSlash(path, bundleEntry);
try {
//use the constant string for the protocol to prevent duplication
- return secureAction.getURL(Constants.OSGI_RESOURCE_URL_PROTOCOL, Long.toString(hostBundleID) + BundleResourceHandler.BID_FWKID_SEPARATOR + Integer.toString(hostData.getAdaptor().hashCode()), index, path, new Handler(bundleEntry, hostData == null ? null : hostData.getAdaptor()));
+ return secureAction.getURL(BundleResourceHandler.OSGI_RESOURCE_URL_PROTOCOL, Long.toString(hostBundleID) + BundleResourceHandler.BID_FWKID_SEPARATOR + Integer.toString(hostModule.getContainer().hashCode()), index, path, new Handler(hostModule.getContainer(), bundleEntry));
} catch (MalformedURLException e) {
return null;
}
@@ -179,35 +139,6 @@ abstract public class BundleFile {
return mruIndex;
}
- /**
- * Attempts to set the permissions of the file in a system dependent way.
- * @param file the file to set the permissions on
- */
- public static void setPermissions(File file) {
- String commandProp = FrameworkProperties.getProperty(PROP_SETPERMS_CMD);
- if (commandProp == null)
- commandProp = FrameworkProperties.getProperty(Constants.FRAMEWORK_EXECPERMISSION);
- if (commandProp == null)
- return;
- String[] temp = ManifestElement.getArrayFromList(commandProp, " "); //$NON-NLS-1$
- List<String> command = new ArrayList<String>(temp.length + 1);
- boolean foundFullPath = false;
- for (int i = 0; i < temp.length; i++) {
- if ("[fullpath]".equals(temp[i]) || "${abspath}".equals(temp[i])) { //$NON-NLS-1$ //$NON-NLS-2$
- command.add(file.getAbsolutePath());
- foundFullPath = true;
- } else
- command.add(temp[i]);
- }
- if (!foundFullPath)
- command.add(file.getAbsolutePath());
- try {
- Runtime.getRuntime().exec(command.toArray(new String[command.size()])).waitFor();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
public String toString() {
return String.valueOf(basefile);
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapperChain.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapperChain.java
index e04011a23..e77aa015b 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapperChain.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapperChain.java
@@ -15,8 +15,8 @@ import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
-import org.eclipse.osgi.baseadaptor.BaseData;
-import org.eclipse.osgi.baseadaptor.hooks.BundleFileWrapperFactoryHook;
+import org.eclipse.osgi.container.Module;
+import org.eclipse.osgi.internal.hookregistry.BundleFileWrapperFactoryHook;
/**
* Used to chain the BundleFile objects returned from {@link BundleFileWrapperFactoryHook}.
@@ -27,6 +27,7 @@ public class BundleFileWrapperChain extends BundleFile {
private final BundleFileWrapperChain next;
public BundleFileWrapperChain(BundleFile wrapped, BundleFileWrapperChain next) {
+ super(null);
this.wrapped = wrapped;
this.next = next;
}
@@ -59,8 +60,8 @@ public class BundleFileWrapperChain extends BundleFile {
return wrapped.getBaseFile();
}
- public URL getResourceURL(String path, BaseData hostData, int index) {
- return wrapped.getResourceURL(path, hostData, index);
+ public URL getResourceURL(String path, Module hostModule, int index) {
+ return wrapped.getResourceURL(path, hostModule, index);
}
public String toString() {
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/ZipBundleFile.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/ZipBundleFile.java
index 598c2e8f3..968011c3f 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/ZipBundleFile.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/ZipBundleFile.java
@@ -12,17 +12,16 @@
package org.eclipse.osgi.storage.bundlefile;
-import org.eclipse.osgi.internal.debug.Debug;
-
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
-import org.eclipse.osgi.baseadaptor.BaseData;
+import org.eclipse.osgi.container.ModuleContainerAdaptor.ContainerEvent;
import org.eclipse.osgi.internal.baseadaptor.AdaptorMsg;
import org.eclipse.osgi.internal.baseadaptor.AdaptorUtil;
+import org.eclipse.osgi.next.internal.debug.Debug;
+import org.eclipse.osgi.storage.BundleInfo;
import org.eclipse.osgi.util.NLS;
-import org.osgi.framework.FrameworkEvent;
/**
* A BundleFile that uses a ZipFile as it base file.
@@ -31,10 +30,10 @@ import org.osgi.framework.FrameworkEvent;
public class ZipBundleFile extends BundleFile {
private final MRUBundleFileList mruList;
- /**
- * The bundle data
- */
- protected BaseData bundledata;
+
+ private final BundleInfo.Generation generation;
+
+ private final Debug debug;
/**
* The zip file
*/
@@ -46,21 +45,12 @@ public class ZipBundleFile extends BundleFile {
private int referenceCount = 0;
- /**
- * Constructs a ZipBundle File
- * @param basefile the base file
- * @param bundledata the bundle data
- * @throws IOException
- */
- public ZipBundleFile(File basefile, BaseData bundledata) throws IOException {
- this(basefile, bundledata, null);
- }
-
- public ZipBundleFile(File basefile, BaseData bundledata, MRUBundleFileList mruList) throws IOException {
+ public ZipBundleFile(File basefile, BundleInfo.Generation generation, MRUBundleFileList mruList) throws IOException {
super(basefile);
if (!BundleFile.secureAction.exists(basefile))
throw new IOException(NLS.bind(AdaptorMsg.ADAPTER_FILEEXIST_EXCEPTION, basefile));
- this.bundledata = bundledata;
+ this.debug = generation.getBundleInfo().getStorage().getConfiguration().getDebug();
+ this.generation = generation;
this.closed = true;
this.mruList = mruList;
}
@@ -73,8 +63,9 @@ public class ZipBundleFile extends BundleFile {
try {
return getZipFile() != null;
} catch (IOException e) {
- if (bundledata != null)
- bundledata.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, bundledata.getBundle(), e);
+ if (generation != null) {
+ generation.getBundleInfo().getStorage().getAdaptor().publishContainerEvent(ContainerEvent.ERROR, null, e);
+ }
return false;
}
}
@@ -145,7 +136,7 @@ public class ZipBundleFile extends BundleFile {
}
protected File getExtractFile(String entryName) {
- if (bundledata == null)
+ if (generation == null)
return null;
String path = ".cp"; /* put all these entries in this subdir *///$NON-NLS-1$
String name = entryName.replace('/', File.separatorChar);
@@ -153,7 +144,7 @@ public class ZipBundleFile extends BundleFile {
path = path.concat(name);
else
path = path + File.separator + name;
- return bundledata.getExtractFile(path);
+ return generation.getExtractFile(path);
}
public synchronized File getFile(String entry, boolean nativeCode) {
@@ -168,7 +159,7 @@ public class ZipBundleFile extends BundleFile {
if (nested != null) {
if (nested.exists()) {
/* the entry is already cached */
- if (Debug.DEBUG_GENERAL)
+ if (debug.DEBUG_GENERAL)
Debug.println("File already present: " + nested.getPath()); //$NON-NLS-1$
if (nested.isDirectory())
// must ensure the complete directory is extracted (bug 182585)
@@ -176,7 +167,7 @@ public class ZipBundleFile extends BundleFile {
} else {
if (zipEntry.getName().endsWith("/")) { //$NON-NLS-1$
if (!nested.mkdirs()) {
- if (Debug.DEBUG_GENERAL)
+ if (debug.DEBUG_GENERAL)
Debug.println("Unable to create directory: " + nested.getPath()); //$NON-NLS-1$
throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, nested.getAbsolutePath()));
}
@@ -186,26 +177,27 @@ public class ZipBundleFile extends BundleFile {
if (in == null)
return null;
/* the entry has not been cached */
- if (Debug.DEBUG_GENERAL)
+ if (debug.DEBUG_GENERAL)
Debug.println("Creating file: " + nested.getPath()); //$NON-NLS-1$
/* create the necessary directories */
File dir = new File(nested.getParent());
if (!dir.exists() && !dir.mkdirs()) {
- if (Debug.DEBUG_GENERAL)
+ if (debug.DEBUG_GENERAL)
Debug.println("Unable to create directory: " + dir.getPath()); //$NON-NLS-1$
throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, dir.getAbsolutePath()));
}
/* copy the entry to the cache */
AdaptorUtil.readFile(in, nested);
- if (nativeCode)
- setPermissions(nested);
+ if (nativeCode) {
+ generation.getBundleInfo().getStorage().setPermissions(nested);
+ }
}
}
return nested;
}
} catch (IOException e) {
- if (Debug.DEBUG_GENERAL)
+ if (debug.DEBUG_GENERAL)
Debug.printStackTrace(e);
}
return null;
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleResourceHandler.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleResourceHandler.java
index a301ae678..61015d734 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleResourceHandler.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleResourceHandler.java
@@ -11,48 +11,35 @@
package org.eclipse.osgi.storage.url;
-import org.eclipse.osgi.framework.internal.core.AbstractBundle;
-
-import org.eclipse.osgi.internal.url.ProtocolActivator;
-
-import org.eclipse.osgi.internal.loader.classpath.BaseClassLoader;
-
-import org.eclipse.osgi.storage.bundlefile.BundleEntry;
-
import java.io.IOException;
import java.net.*;
-import org.eclipse.osgi.baseadaptor.BaseAdaptor;
-import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor;
+import org.eclipse.osgi.container.Module;
+import org.eclipse.osgi.container.ModuleContainer;
import org.eclipse.osgi.internal.baseadaptor.AdaptorMsg;
-import org.eclipse.osgi.internal.loader.BundleLoader;
+import org.eclipse.osgi.storage.bundlefile.BundleEntry;
import org.eclipse.osgi.util.NLS;
-import org.osgi.framework.*;
+import org.osgi.framework.AdminPermission;
+import org.osgi.framework.Bundle;
/**
* URLStreamHandler the bundleentry and bundleresource protocols.
*/
-public abstract class BundleResourceHandler extends URLStreamHandler implements ProtocolActivator {
+public abstract class BundleResourceHandler extends URLStreamHandler {
+ // Bundle resource URL protocol
+ public static final String OSGI_RESOURCE_URL_PROTOCOL = "bundleresource"; //$NON-NLS-1$
+ // Bundle entry URL protocol
+ public static final String OSGI_ENTRY_URL_PROTOCOL = "bundleentry"; //$NON-NLS-1$
+
public static final String SECURITY_CHECKED = "SECURITY_CHECKED"; //$NON-NLS-1$
public static final String SECURITY_UNCHECKED = "SECURITY_UNCHECKED"; //$NON-NLS-1$
public static final String BID_FWKID_SEPARATOR = ".fwk"; //$NON-NLS-1$
- private BaseAdaptor adaptor;
+ protected final ModuleContainer container;
protected BundleEntry bundleEntry;
- /**
- * Constructor for a bundle protocol resource URLStreamHandler.
- */
- public BundleResourceHandler() {
- this(null, null);
- }
-
- public BundleResourceHandler(BundleEntry bundleEntry, BaseAdaptor adaptor) {
+ public BundleResourceHandler(ModuleContainer container, BundleEntry bundleEntry) {
+ this.container = container;
this.bundleEntry = bundleEntry;
- this.adaptor = adaptor;
- }
-
- public void start(BundleContext context, FrameworkAdaptor baseAdaptor) {
- this.adaptor = (BaseAdaptor) baseAdaptor;
}
/**
@@ -129,12 +116,11 @@ public abstract class BundleResourceHandler extends URLStreamHandler implements
// are allowed access to the resource.
String authorized = SECURITY_UNCHECKED;
long bundleId = getBundleID(host);
- Bundle bundle = adaptor == null ? null : adaptor.getBundle(bundleId);
- if (checkAuthorization(bundle))
+ Module module = getModule(bundleId);
+ if (checkAuthorization(module))
authorized = SECURITY_CHECKED;
// Always force the use of the hash from the adaptor
- if (adaptor != null)
- host = Long.toString(bundleId) + BID_FWKID_SEPARATOR + Integer.toString(adaptor.hashCode());
+ host = Long.toString(bundleId) + BID_FWKID_SEPARATOR + Integer.toString(container.hashCode());
// Setting the authority portion of the URL to SECURITY_ATHORIZED
// ensures that this URL was created by using this parseURL
// method. The openConnection method will only open URLs
@@ -142,6 +128,10 @@ public abstract class BundleResourceHandler extends URLStreamHandler implements
setURL(url, url.getProtocol(), host, resIndex, authorized, null, path, null, url.getRef());
}
+ private Module getModule(long id) {
+ return container.getModule(id);
+ }
+
/**
* Establishes a connection to the resource specified by <code>URL</code>.
* Since different protocols may have unique ways of connecting, it must be
@@ -160,24 +150,23 @@ public abstract class BundleResourceHandler extends URLStreamHandler implements
if (host == null) {
throw new IOException(NLS.bind(AdaptorMsg.URL_NO_BUNDLE_ID, url.toExternalForm()));
}
- AbstractBundle bundle = null;
long bundleID;
try {
bundleID = getBundleID(host);
} catch (NumberFormatException nfe) {
throw (MalformedURLException) new MalformedURLException(NLS.bind(AdaptorMsg.URL_INVALID_BUNDLE_ID, host)).initCause(nfe);
}
- bundle = adaptor == null ? null : (AbstractBundle) adaptor.getBundle(bundleID);
- if (bundle == null)
+ Module module = getModule(bundleID);
+ if (module == null)
throw new IOException(NLS.bind(AdaptorMsg.URL_NO_BUNDLE_FOUND, url.toExternalForm()));
// check to make sure that this URL was created using the
// parseURL method. This ensures the security check was done
// at URL construction.
if (!url.getAuthority().equals(SECURITY_CHECKED)) {
// No admin security check was made better check now.
- checkAuthorization(bundle);
+ checkAuthorization(module);
}
- return (new BundleURLConnection(url, findBundleEntry(url, bundle)));
+ return (new BundleURLConnection(url, findBundleEntry(url, module)));
}
/**
@@ -185,10 +174,11 @@ public abstract class BundleResourceHandler extends URLStreamHandler implements
* differently for Bundle.gerResource() and Bundle.getEntry()
* because getResource uses the bundle classloader and getEntry
* only used the base bundle file.
- * @param url The URL to find the BundleEntry for.
+ * @param url The URL to find the entry for.
+ * @param module the module to find the entry for.
* @return the bundle entry
*/
- abstract protected BundleEntry findBundleEntry(URL url, AbstractBundle bundle) throws IOException;
+ abstract protected BundleEntry findBundleEntry(URL url, Module module) throws IOException;
/**
* Converts a bundle URL to a String.
@@ -239,8 +229,7 @@ public abstract class BundleResourceHandler extends URLStreamHandler implements
if (path != null)
hash += path.hashCode();
- if (adaptor != null)
- hash += adaptor.hashCode();
+ hash += container.hashCode();
return hash;
}
@@ -285,23 +274,17 @@ public abstract class BundleResourceHandler extends URLStreamHandler implements
// URLs depending on how they were constructed.
}
- protected boolean checkAuthorization(Bundle bundle) {
+ protected boolean checkAuthorization(Module module) {
SecurityManager sm = System.getSecurityManager();
if (sm == null)
return true;
+ Bundle bundle = module == null ? null : module.getBundle();
if (bundle == null)
return false;
sm.checkPermission(new AdminPermission(bundle, AdminPermission.RESOURCE));
return true;
}
- protected static BaseClassLoader getBundleClassLoader(AbstractBundle bundle) {
- BundleLoader loader = bundle.getBundleLoader();
- if (loader == null)
- return null;
- return (BaseClassLoader) loader.createClassLoader();
- }
-
private long getBundleID(String host) {
int dotIndex = host.indexOf('.');
return (dotIndex >= 0 && dotIndex < host.length() - 1) ? Long.parseLong(host.substring(0, dotIndex)) : Long.parseLong(host);
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleURLConnection.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleURLConnection.java
index c878ea2a2..003edf978 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleURLConnection.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleURLConnection.java
@@ -11,13 +11,12 @@
package org.eclipse.osgi.storage.url;
-import org.eclipse.osgi.storage.bundlefile.BundleEntry;
-
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import org.eclipse.osgi.internal.baseadaptor.AdaptorMsg;
+import org.eclipse.osgi.storage.bundlefile.BundleEntry;
import org.eclipse.osgi.util.NLS;
/**
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleURLConverter.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleURLConverter.java
index a2f540bda..253095398 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleURLConverter.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/BundleURLConverter.java
@@ -8,15 +8,12 @@
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
-package org.eclipse.core.runtime.internal.adaptor;
-
-import org.eclipse.osgi.storage.url.BundleURLConnection;
-
-import org.eclipse.osgi.internal.location.EclipseAdaptorMsg;
+package org.eclipse.osgi.storage.url;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
+import org.eclipse.osgi.internal.location.EclipseAdaptorMsg;
import org.eclipse.osgi.service.urlconversion.URLConverter;
import org.eclipse.osgi.util.NLS;
@@ -26,7 +23,7 @@ import org.eclipse.osgi.util.NLS;
*
* <p>Internal class.</p>
*/
-public class URLConverterImpl implements URLConverter {
+public class BundleURLConverter implements URLConverter {
/* (non-Javadoc)
* @see org.eclipse.osgi.service.urlconversion.URLConverter#toFileURL(java.net.URL)
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/bundleentry/Handler.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/bundleentry/Handler.java
index 42e4a55ae..e69dec312 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/bundleentry/Handler.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/bundleentry/Handler.java
@@ -9,18 +9,15 @@
* IBM Corporation - initial API and implementation
*******************************************************************************/
-package org.eclipse.osgi.framework.internal.protocol.bundleentry;
-
-import org.eclipse.osgi.storage.url.BundleResourceHandler;
-
-import org.eclipse.osgi.storage.bundlefile.BundleEntry;
+package org.eclipse.osgi.storage.url.bundleentry;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
-import org.eclipse.osgi.baseadaptor.BaseAdaptor;
-import org.eclipse.osgi.baseadaptor.BaseData;
-import org.eclipse.osgi.framework.internal.core.AbstractBundle;
+import org.eclipse.osgi.container.*;
+import org.eclipse.osgi.storage.BundleInfo;
+import org.eclipse.osgi.storage.bundlefile.BundleEntry;
+import org.eclipse.osgi.storage.url.BundleResourceHandler;
/**
* URLStreamHandler the bundleentry protocol.
@@ -28,24 +25,16 @@ import org.eclipse.osgi.framework.internal.core.AbstractBundle;
public class Handler extends BundleResourceHandler {
- /**
- * Constructor for a bundle protocol resource URLStreamHandler.
- */
- public Handler() {
- super();
- }
-
- public Handler(BundleEntry bundleEntry, BaseAdaptor adaptor) {
- super(bundleEntry, adaptor);
+ public Handler(ModuleContainer container, BundleEntry bundleEntry) {
+ super(container, bundleEntry);
}
- protected BundleEntry findBundleEntry(URL url, AbstractBundle bundle) throws IOException {
- BaseData bundleData = (BaseData) bundle.getBundleData();
- BundleEntry entry = bundleData.getBundleFile().getEntry(url.getPath());
+ protected BundleEntry findBundleEntry(URL url, Module module) throws IOException {
+ ModuleRevision revision = module.getCurrentRevision();
+ BundleInfo.Generation revisionInfo = (BundleInfo.Generation) revision.getRevisionInfo();
+ BundleEntry entry = revisionInfo == null ? null : revisionInfo.getBundleFile().getEntry(url.getPath());
if (entry == null)
throw new FileNotFoundException(url.getPath());
return entry;
-
}
-
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/bundleresource/Handler.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/bundleresource/Handler.java
index 6cc25e539..a4dfeefde 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/bundleresource/Handler.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/url/bundleresource/Handler.java
@@ -9,20 +9,15 @@
* IBM Corporation - initial API and implementation
*******************************************************************************/
-package org.eclipse.osgi.framework.internal.protocol.bundleresource;
-
-import org.eclipse.osgi.storage.url.BundleResourceHandler;
-
-import org.eclipse.osgi.internal.loader.classpath.BaseClassLoader;
-import org.eclipse.osgi.internal.loader.classpath.ClasspathManager;
-
-import org.eclipse.osgi.storage.bundlefile.BundleEntry;
+package org.eclipse.osgi.storage.url.bundleresource;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
-import org.eclipse.osgi.baseadaptor.BaseAdaptor;
-import org.eclipse.osgi.framework.internal.core.AbstractBundle;
+import org.eclipse.osgi.container.*;
+import org.eclipse.osgi.internal.loader.ModuleClassLoader;
+import org.eclipse.osgi.storage.bundlefile.BundleEntry;
+import org.eclipse.osgi.storage.url.BundleResourceHandler;
/**
* URLStreamHandler the bundleresource protocol.
@@ -30,28 +25,24 @@ import org.eclipse.osgi.framework.internal.core.AbstractBundle;
public class Handler extends BundleResourceHandler {
- /**
- * Constructor for a bundle protocol resource URLStreamHandler.
- */
- public Handler() {
- super();
- }
-
- public Handler(BundleEntry bundleEntry, BaseAdaptor adaptor) {
- super(bundleEntry, adaptor);
+ public Handler(ModuleContainer container, BundleEntry bundleEntry) {
+ super(container, bundleEntry);
}
- protected BundleEntry findBundleEntry(URL url, AbstractBundle bundle) throws IOException {
- BaseClassLoader classloader = getBundleClassLoader(bundle);
+ protected BundleEntry findBundleEntry(URL url, Module module) throws IOException {
+ ModuleRevision current = module.getCurrentRevision();
+ ModuleWiring wiring = current == null ? null : current.getWiring();
+ ModuleClassLoader classloader = (ModuleClassLoader) (current == null ? null : wiring.getClassLoader());
if (classloader == null)
throw new FileNotFoundException(url.getPath());
- ClasspathManager cpManager = classloader.getClasspathManager();
- BundleEntry entry = cpManager.findLocalEntry(url.getPath(), url.getPort());
- if (entry == null)
+ BundleEntry entry = classloader.getClasspathManager().findLocalEntry(url.getPath(), url.getPort());
+ if (entry == null) {
// this isn't strictly needed but is kept to maintain compatibility
- entry = cpManager.findLocalEntry(url.getPath());
- if (entry == null)
+ entry = classloader.getClasspathManager().findLocalEntry(url.getPath());
+ }
+ if (entry == null) {
throw new FileNotFoundException(url.getPath());
+ }
return entry;
}
diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/Debug.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/Debug.java
index 1bda1eb01..51b605d8d 100644
--- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/Debug.java
+++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/Debug.java
@@ -155,27 +155,27 @@ public class Debug {
*/
public static final String OPTION_DEBUG_MESSAGE_BUNDLES = ECLIPSE_OSGI + "/debug/messageBundles"; //$NON-NLS-1$
- static {
- FrameworkDebugOptions dbgOptions = FrameworkDebugOptions.getDefault();
- if (dbgOptions != null) {
- DEBUG_ENABLED = dbgOptions.isDebugEnabled();
- DEBUG_GENERAL = dbgOptions.getBooleanOption(OPTION_DEBUG_GENERAL, false);
- DEBUG_BUNDLE_TIME = dbgOptions.getBooleanOption(OPTION_DEBUG_BUNDLE_TIME, false) || dbgOptions.getBooleanOption("org.eclipse.core.runtime/timing/startup", false); //$NON-NLS-1$
- DEBUG_LOADER = dbgOptions.getBooleanOption(OPTION_DEBUG_LOADER, false);
- DEBUG_EVENTS = dbgOptions.getBooleanOption(OPTION_DEBUG_EVENTS, false);
- DEBUG_SERVICES = dbgOptions.getBooleanOption(OPTION_DEBUG_SERVICES, false);
- DEBUG_HOOKS = dbgOptions.getBooleanOption(OPTION_DEBUG_HOOKS, false);
- DEBUG_PACKAGES = dbgOptions.getBooleanOption(OPTION_DEBUG_PACKAGES, false);
- DEBUG_MANIFEST = dbgOptions.getBooleanOption(OPTION_DEBUG_MANIFEST, false);
- DEBUG_FILTER = dbgOptions.getBooleanOption(OPTION_DEBUG_FILTER, false);
- DEBUG_SECURITY = dbgOptions.getBooleanOption(OPTION_DEBUG_SECURITY, false);
- DEBUG_STARTLEVEL = dbgOptions.getBooleanOption(OPTION_DEBUG_STARTLEVEL, false);
- DEBUG_PACKAGEADMIN = dbgOptions.getBooleanOption(OPTION_DEBUG_PACKAGEADMIN, false);
- DEBUG_PACKAGEADMIN_TIMING = dbgOptions.getBooleanOption(OPTION_DEBUG_PACKAGEADMIN_TIMING, false) || dbgOptions.getBooleanOption("org.eclipse.core.runtime/debug", false); //$NON-NLS-1$
- DEBUG_MESSAGE_BUNDLES = dbgOptions.getBooleanOption(OPTION_DEBUG_MESSAGE_BUNDLES, false);
- MONITOR_ACTIVATION = dbgOptions.getBooleanOption(OPTION_MONITOR_ACTIVATION, false);
- }
- }
+ // static {
+ // FrameworkDebugOptions dbgOptions = FrameworkDebugOptions.getDefault();
+ // if (dbgOptions != null) {
+ // DEBUG_ENABLED = dbgOptions.isDebugEnabled();
+ // DEBUG_GENERAL = dbgOptions.getBooleanOption(OPTION_DEBUG_GENERAL, false);
+ // DEBUG_BUNDLE_TIME = dbgOptions.getBooleanOption(OPTION_DEBUG_BUNDLE_TIME, false) || dbgOptions.getBooleanOption("org.eclipse.core.runtime/timing/startup", false); //$NON-NLS-1$
+ // DEBUG_LOADER = dbgOptions.getBooleanOption(OPTION_DEBUG_LOADER, false);
+ // DEBUG_EVENTS = dbgOptions.getBooleanOption(OPTION_DEBUG_EVENTS, false);
+ // DEBUG_SERVICES = dbgOptions.getBooleanOption(OPTION_DEBUG_SERVICES, false);
+ // DEBUG_HOOKS = dbgOptions.getBooleanOption(OPTION_DEBUG_HOOKS, false);
+ // DEBUG_PACKAGES = dbgOptions.getBooleanOption(OPTION_DEBUG_PACKAGES, false);
+ // DEBUG_MANIFEST = dbgOptions.getBooleanOption(OPTION_DEBUG_MANIFEST, false);
+ // DEBUG_FILTER = dbgOptions.getBooleanOption(OPTION_DEBUG_FILTER, false);
+ // DEBUG_SECURITY = dbgOptions.getBooleanOption(OPTION_DEBUG_SECURITY, false);
+ // DEBUG_STARTLEVEL = dbgOptions.getBooleanOption(OPTION_DEBUG_STARTLEVEL, false);
+ // DEBUG_PACKAGEADMIN = dbgOptions.getBooleanOption(OPTION_DEBUG_PACKAGEADMIN, false);
+ // DEBUG_PACKAGEADMIN_TIMING = dbgOptions.getBooleanOption(OPTION_DEBUG_PACKAGEADMIN_TIMING, false) || dbgOptions.getBooleanOption("org.eclipse.core.runtime/debug", false); //$NON-NLS-1$
+ // DEBUG_MESSAGE_BUNDLES = dbgOptions.getBooleanOption(OPTION_DEBUG_MESSAGE_BUNDLES, false);
+ // MONITOR_ACTIVATION = dbgOptions.getBooleanOption(OPTION_MONITOR_ACTIVATION, false);
+ // }
+ // }
/**
* The PrintStream to print debug messages to.
diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/EclipseDebugTrace.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/EclipseDebugTrace.java
index a21bbcd01..bf1610eac 100644
--- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/EclipseDebugTrace.java
+++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/EclipseDebugTrace.java
@@ -523,7 +523,7 @@ class EclipseDebugTrace implements DebugTrace {
writeComment(traceWriter, EclipseDebugTrace.TRACE_FILE_VERSION_COMMENT + EclipseDebugTrace.TRACE_FILE_VERSION);
writeComment(traceWriter, EclipseDebugTrace.TRACE_FILE_VERBOSE_COMMENT + debugOptions.isVerbose());
writeComment(traceWriter, "The following option strings are specified for this debug session:"); //$NON-NLS-1$
- final String[] allOptions = FrameworkDebugOptions.getDefault().getAllOptions();
+ final String[] allOptions = debugOptions.getAllOptions();
for (int i = 0; i < allOptions.length; i++) {
writeComment(traceWriter, "\t" + allOptions[i]); //$NON-NLS-1$
}
diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/FrameworkDebugOptions.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/FrameworkDebugOptions.java
index d686ac843..f5142eb98 100644
--- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/FrameworkDebugOptions.java
+++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/debug/FrameworkDebugOptions.java
@@ -14,7 +14,7 @@ import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
-import org.eclipse.osgi.framework.internal.core.FrameworkProperties;
+import org.eclipse.osgi.internal.framework.EquinoxConfiguration;
import org.eclipse.osgi.service.debug.*;
import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;
@@ -32,35 +32,33 @@ public class FrameworkDebugOptions implements DebugOptions, ServiceTrackerCustom
private static final String OSGI_DEBUG = "osgi.debug"; //$NON-NLS-1$
private static final String OSGI_DEBUG_VERBOSE = "osgi.debug.verbose"; //$NON-NLS-1$
public static final String PROP_TRACEFILE = "osgi.tracefile"; //$NON-NLS-1$
+ /** The default name of the .options file if loading when the -debug command-line argument is used */
+ private static final String OPTIONS = ".options"; //$NON-NLS-1$
+
/** monitor used to lock the options maps */
private final Object lock = new Object();
/** A current map of all the options with values set */
private Properties options = null;
/** A map of all the disabled options with values set at the time debug was disabled */
private Properties disabledOptions = null;
- /** The singleton object of this class */
- private static FrameworkDebugOptions singleton = null;
- /** The default name of the .options file if loading when the -debug command-line argument is used */
- private static final String OPTIONS = ".options"; //$NON-NLS-1$
/** A cache of all of the bundles <code>DebugTrace</code> in the format <key,value> --> <bundle name, DebugTrace> */
- protected final static Map<String, DebugTrace> debugTraceCache = new HashMap<String, DebugTrace>();
+ protected final Map<String, DebugTrace> debugTraceCache = new HashMap<String, DebugTrace>();
/** The File object to store messages. This value may be null. */
protected File outFile = null;
/** Is verbose debugging enabled? Changing this value causes a new tracing session to start. */
protected boolean verboseDebug = true;
+ private final EquinoxConfiguration environmentInfo;
private volatile BundleContext context;
private volatile ServiceTracker<DebugOptionsListener, DebugOptionsListener> listenerTracker;
- /**
- * Internal constructor to create a <code>FrameworkDebugOptions</code> singleton object.
- */
- private FrameworkDebugOptions() {
+ public FrameworkDebugOptions(EquinoxConfiguration environmentInfo) {
+ this.environmentInfo = environmentInfo;
// check if verbose debugging was set during initialization. This needs to be set even if debugging is disabled
- this.verboseDebug = Boolean.valueOf(FrameworkProperties.getProperty(OSGI_DEBUG_VERBOSE, Boolean.TRUE.toString())).booleanValue();
+ this.verboseDebug = Boolean.valueOf(environmentInfo.getConfiguration(OSGI_DEBUG_VERBOSE, Boolean.TRUE.toString())).booleanValue();
// if no debug option was specified, don't even bother to try.
// Must ensure that the options slot is null as this is the signal to the
// platform that debugging is not enabled.
- String debugOptionsFilename = FrameworkProperties.getProperty(OSGI_DEBUG);
+ String debugOptionsFilename = environmentInfo.getConfiguration(OSGI_DEBUG);
if (debugOptionsFilename == null)
return;
options = new Properties();
@@ -69,7 +67,7 @@ public class FrameworkDebugOptions implements DebugOptions, ServiceTrackerCustom
// default options location is user.dir (install location may be r/o so
// is not a good candidate for a trace options that need to be updatable by
// by the user)
- String userDir = FrameworkProperties.getProperty("user.dir").replace(File.separatorChar, '/'); //$NON-NLS-1$
+ String userDir = System.getProperty("user.dir").replace(File.separatorChar, '/'); //$NON-NLS-1$
if (!userDir.endsWith("/")) //$NON-NLS-1$
userDir += "/"; //$NON-NLS-1$
debugOptionsFilename = new File(userDir, OPTIONS).toString();
@@ -112,18 +110,6 @@ public class FrameworkDebugOptions implements DebugOptions, ServiceTrackerCustom
this.context = null;
}
- /**
- * Returns the singleton instance of <code>FrameworkDebugOptions</code>.
- * @return the instance of <code>FrameworkDebugOptions</code>
- */
- public static FrameworkDebugOptions getDefault() {
-
- if (FrameworkDebugOptions.singleton == null) {
- FrameworkDebugOptions.singleton = new FrameworkDebugOptions();
- }
- return FrameworkDebugOptions.singleton;
- }
-
@SuppressWarnings("deprecation")
private static URL buildURL(String spec, boolean trailingSlash) {
if (spec == null)
@@ -363,7 +349,7 @@ public class FrameworkDebugOptions implements DebugOptions, ServiceTrackerCustom
EclipseDebugTrace.newSession = true;
// enable platform debugging - there is no .options file
- FrameworkProperties.setProperty(OSGI_DEBUG, ""); //$NON-NLS-1$
+ environmentInfo.setConfiguration(OSGI_DEBUG, ""); //$NON-NLS-1$
if (disabledOptions != null) {
options = disabledOptions;
disabledOptions = null;
@@ -376,7 +362,7 @@ public class FrameworkDebugOptions implements DebugOptions, ServiceTrackerCustom
if (options == null)
return;
// disable platform debugging.
- FrameworkProperties.clearProperty(OSGI_DEBUG);
+ environmentInfo.clearConfiguration(OSGI_DEBUG);
if (options.size() > 0) {
// Save the current options off in case debug is re-enabled
disabledOptions = options;
@@ -408,11 +394,11 @@ public class FrameworkDebugOptions implements DebugOptions, ServiceTrackerCustom
public final DebugTrace newDebugTrace(String bundleSymbolicName, Class<?> traceEntryClass) {
DebugTrace debugTrace = null;
- synchronized (FrameworkDebugOptions.debugTraceCache) {
- debugTrace = FrameworkDebugOptions.debugTraceCache.get(bundleSymbolicName);
+ synchronized (debugTraceCache) {
+ debugTrace = debugTraceCache.get(bundleSymbolicName);
if (debugTrace == null) {
- debugTrace = new EclipseDebugTrace(bundleSymbolicName, FrameworkDebugOptions.singleton, traceEntryClass);
- FrameworkDebugOptions.debugTraceCache.put(bundleSymbolicName, debugTrace);
+ debugTrace = new EclipseDebugTrace(bundleSymbolicName, this, traceEntryClass);
+ debugTraceCache.put(bundleSymbolicName, debugTrace);
}
}
return debugTrace;
@@ -434,7 +420,7 @@ public class FrameworkDebugOptions implements DebugOptions, ServiceTrackerCustom
public synchronized void setFile(final File traceFile) {
this.outFile = traceFile;
- FrameworkProperties.setProperty(PROP_TRACEFILE, this.outFile.getAbsolutePath());
+ environmentInfo.setConfiguration(PROP_TRACEFILE, this.outFile.getAbsolutePath());
// the file changed so start a new session
EclipseDebugTrace.newSession = true;
}
diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/next/internal/debug/Debug.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/next/internal/debug/Debug.java
new file mode 100644
index 000000000..89031bffe
--- /dev/null
+++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/next/internal/debug/Debug.java
@@ -0,0 +1,370 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.next.internal.debug;
+
+import java.io.PrintStream;
+import java.lang.reflect.*;
+import org.eclipse.osgi.internal.framework.EquinoxContainer;
+import org.eclipse.osgi.service.debug.DebugOptions;
+
+/**
+ * This class has debug constants which can be used by the Framework implementation
+ * and Adaptor implementations
+ * @since 3.1
+ */
+public class Debug {
+ /**
+ * Base debug option key (org.eclispe.osgi).
+ */
+ public static final String ECLIPSE_OSGI = EquinoxContainer.NAME;
+ /**
+ * General Debug option key.
+ */
+ public static final String OPTION_DEBUG_GENERAL = ECLIPSE_OSGI + "/debug"; //$NON-NLS-1$
+ /**
+ * Bundle time Debug option key.
+ */
+ // TODO remove this or use it somewhere
+ public static final String OPTION_DEBUG_BUNDLE_TIME = ECLIPSE_OSGI + "/debug/bundleTime"; //$NON-NLS-1$
+ /**
+ * Loader Debug option key.
+ */
+ public static final String OPTION_DEBUG_LOADER = ECLIPSE_OSGI + "/debug/loader"; //$NON-NLS-1$
+ /**
+ * Events Debug option key.
+ */
+ public static final String OPTION_DEBUG_EVENTS = ECLIPSE_OSGI + "/debug/events"; //$NON-NLS-1$
+ /**
+ * Services Debug option key.
+ */
+ public static final String OPTION_DEBUG_SERVICES = ECLIPSE_OSGI + "/debug/services"; //$NON-NLS-1$
+ /**
+ * Services Debug option key.
+ */
+ public static final String OPTION_DEBUG_HOOKS = ECLIPSE_OSGI + "/debug/hooks"; //$NON-NLS-1$
+ /**
+ * Packages Debug option key.
+ */
+ public static final String OPTION_DEBUG_PACKAGES = ECLIPSE_OSGI + "/debug/packages"; //$NON-NLS-1$
+ /**
+ * Manifest Debug option key.
+ */
+ public static final String OPTION_DEBUG_MANIFEST = ECLIPSE_OSGI + "/debug/manifest"; //$NON-NLS-1$
+ /**
+ * Filter Debug option key.
+ */
+ public static final String OPTION_DEBUG_FILTER = ECLIPSE_OSGI + "/debug/filter"; //$NON-NLS-1$
+ /**
+ * Security Debug option key.
+ */
+ public static final String OPTION_DEBUG_SECURITY = ECLIPSE_OSGI + "/debug/security"; //$NON-NLS-1$
+ /**
+ * Start level Debug option key.
+ */
+ public static final String OPTION_DEBUG_STARTLEVEL = ECLIPSE_OSGI + "/debug/startlevel"; //$NON-NLS-1$
+ /**
+ * PackageAdmin Debug option key.
+ */
+ public static final String OPTION_DEBUG_PACKAGEADMIN = ECLIPSE_OSGI + "/debug/packageadmin"; //$NON-NLS-1$
+ /**
+ * PackageAdmin timing Debug option key.
+ */
+ public static final String OPTION_DEBUG_PACKAGEADMIN_TIMING = ECLIPSE_OSGI + "/debug/packageadmin/timing"; //$NON-NLS-1$
+ /**
+ * Monitor activation Debug option key.
+ */
+ public static final String OPTION_MONITOR_ACTIVATION = ECLIPSE_OSGI + "/monitor/activation"; //$NON-NLS-1$
+ /**
+ * Message bundles Debug option key.
+ */
+ public static final String OPTION_DEBUG_MESSAGE_BUNDLES = ECLIPSE_OSGI + "/debug/messageBundles"; //$NON-NLS-1$
+
+ public static final String OPTION_DEBUG_LOCATION = ECLIPSE_OSGI + "/debug/location"; //$NON-NLS-1$
+
+ /**
+ * Indicates if tracing is enabled
+ */
+ public boolean DEBUG_ENABLED = false;
+
+ /**
+ * General debug flag.
+ */
+ public boolean DEBUG_GENERAL = false; // "debug"
+ /**
+ * Bundle time debug flag.
+ */
+ public boolean DEBUG_BUNDLE_TIME = false; //"debug.bundleTime"
+ /**
+ * Loader debug flag.
+ */
+ public boolean DEBUG_LOADER = false; // "debug.loader"
+ /**
+ * Events debug flag.
+ */
+ public boolean DEBUG_EVENTS = false; // "debug.events"
+ /**
+ * Services debug flag.
+ */
+ public boolean DEBUG_SERVICES = false; // "debug.services"
+
+ /**
+ * Hooks debug flag.
+ */
+ public boolean DEBUG_HOOKS = false; // "debug.hooks"
+ /**
+ * Packages debug flag.
+ */
+ // TODO remove this or use it somewhere
+ public boolean DEBUG_PACKAGES = false; // "debug.packages"
+ /**
+ * Manifest debug flag.
+ */
+ public boolean DEBUG_MANIFEST = false; // "debug.manifest"
+ /**
+ * Filter debug flag.
+ */
+ public boolean DEBUG_FILTER = false; // "debug.filter"
+ /**
+ * Security debug flag.
+ */
+ public boolean DEBUG_SECURITY = false; // "debug.security"
+ /**
+ * Start level debug flag.
+ */
+ public boolean DEBUG_STARTLEVEL = false; // "debug.startlevel"
+ /**
+ * PackageAdmin debug flag.
+ */
+ public boolean DEBUG_PACKAGEADMIN = false; // "debug.packageadmin"
+ /**
+ * PackageAdmin timing debug flag.
+ */
+ // TODO remove this or use it somewhere
+ public boolean DEBUG_PACKAGEADMIN_TIMING = false; //"debug.packageadmin/timing"
+ /**
+ * Message debug flag.
+ */
+ public boolean DEBUG_MESSAGE_BUNDLES = false; //"/debug/messageBundles"
+ /**
+ * Monitor activation debug flag.
+ */
+ public boolean MONITOR_ACTIVATION = false; // "monitor/bundles"
+
+ public boolean DEBUG_LOCATION = false; // debug/location
+
+ public Debug(DebugOptions dbgOptions) {
+ if (dbgOptions == null) {
+ return;
+ }
+ DEBUG_ENABLED = dbgOptions.isDebugEnabled();
+ DEBUG_GENERAL = dbgOptions.getBooleanOption(OPTION_DEBUG_GENERAL, false);
+ DEBUG_BUNDLE_TIME = dbgOptions.getBooleanOption(OPTION_DEBUG_BUNDLE_TIME, false) || dbgOptions.getBooleanOption("org.eclipse.core.runtime/timing/startup", false); //$NON-NLS-1$
+ DEBUG_LOADER = dbgOptions.getBooleanOption(OPTION_DEBUG_LOADER, false);
+ DEBUG_EVENTS = dbgOptions.getBooleanOption(OPTION_DEBUG_EVENTS, false);
+ DEBUG_SERVICES = dbgOptions.getBooleanOption(OPTION_DEBUG_SERVICES, false);
+ DEBUG_HOOKS = dbgOptions.getBooleanOption(OPTION_DEBUG_HOOKS, false);
+ DEBUG_PACKAGES = dbgOptions.getBooleanOption(OPTION_DEBUG_PACKAGES, false);
+ DEBUG_MANIFEST = dbgOptions.getBooleanOption(OPTION_DEBUG_MANIFEST, false);
+ DEBUG_FILTER = dbgOptions.getBooleanOption(OPTION_DEBUG_FILTER, false);
+ DEBUG_SECURITY = dbgOptions.getBooleanOption(OPTION_DEBUG_SECURITY, false);
+ DEBUG_STARTLEVEL = dbgOptions.getBooleanOption(OPTION_DEBUG_STARTLEVEL, false);
+ DEBUG_PACKAGEADMIN = dbgOptions.getBooleanOption(OPTION_DEBUG_PACKAGEADMIN, false);
+ DEBUG_PACKAGEADMIN_TIMING = dbgOptions.getBooleanOption(OPTION_DEBUG_PACKAGEADMIN_TIMING, false) || dbgOptions.getBooleanOption("org.eclipse.core.runtime/debug", false); //$NON-NLS-1$
+ DEBUG_MESSAGE_BUNDLES = dbgOptions.getBooleanOption(OPTION_DEBUG_MESSAGE_BUNDLES, false);
+ MONITOR_ACTIVATION = dbgOptions.getBooleanOption(OPTION_MONITOR_ACTIVATION, false);
+ DEBUG_LOCATION = dbgOptions.getBooleanOption(OPTION_DEBUG_LOCATION, false);
+ }
+
+ /**
+ * The PrintStream to print debug messages to.
+ */
+ public static PrintStream out = System.out;
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void print(boolean x) {
+ out.print(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void print(char x) {
+ out.print(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void print(int x) {
+ out.print(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void print(long x) {
+ out.print(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void print(float x) {
+ out.print(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void print(double x) {
+ out.print(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void print(char x[]) {
+ out.print(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void print(String x) {
+ out.print(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void print(Object x) {
+ out.print(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void println(boolean x) {
+ out.println(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void println(char x) {
+ out.println(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void println(int x) {
+ out.println(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void println(long x) {
+ out.println(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void println(float x) {
+ out.println(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void println(double x) {
+ out.println(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void println(char x[]) {
+ out.println(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void println(String x) {
+ out.println(x);
+ }
+
+ /**
+ * Prints x to the PrintStream
+ * @param x
+ */
+ public static void println(Object x) {
+ out.println(x);
+ }
+
+ /**
+ * Prints t to the PrintStream
+ * @param t
+ */
+ public static void printStackTrace(Throwable t) {
+ if (t == null)
+ return;
+ t.printStackTrace(out);
+
+ Method[] methods = t.getClass().getMethods();
+
+ int size = methods.length;
+ Class<?> throwable = Throwable.class;
+
+ for (int i = 0; i < size; i++) {
+ Method method = methods[i];
+
+ if (Modifier.isPublic(method.getModifiers()) && method.getName().startsWith("get") && throwable.isAssignableFrom(method.getReturnType()) && (method.getParameterTypes().length == 0)) { //$NON-NLS-1$
+ try {
+ Throwable nested = (Throwable) method.invoke(t, (Object[]) null);
+
+ if ((nested != null) && (nested != t)) {
+ out.println("Nested Exception:"); //$NON-NLS-1$
+ printStackTrace(nested);
+ }
+ } catch (IllegalAccessException e) {
+ // nothing
+ } catch (InvocationTargetException e) {
+ // nothing
+ }
+ }
+ }
+ }
+
+}

Back to the top