diff options
6 files changed, 124 insertions, 7 deletions
diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseData.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseData.java index 5cf202cc8..1bcd4bc72 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseData.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseData.java @@ -24,6 +24,7 @@ import org.eclipse.osgi.framework.adaptor.*; import org.eclipse.osgi.framework.debug.Debug; import org.eclipse.osgi.framework.internal.core.Constants; import org.eclipse.osgi.framework.internal.protocol.bundleentry.Handler; +import org.eclipse.osgi.framework.log.FrameworkLogEntry; import org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader; import org.eclipse.osgi.util.ManifestElement; import org.osgi.framework.*; @@ -50,6 +51,8 @@ public class BaseData implements BundleData { protected Dictionary manifest; // This field is only used by PDE source lookup, and is set by a hook (bug 126517). It serves no purpose at runtime. protected String fileName; + // This is only used to keep track of when the same native library is loaded more than once + protected Collection loadedNativeCode; ///////////////////// Begin values from Manifest ///////////////////// private String symbolicName; @@ -118,11 +121,34 @@ public class BaseData implements BundleData { for (int i = 0; i < hooks.length; i++) { result = hooks[i].findLibrary(this, libname); if (result != null) - return result; + break; } + // check to see if this library has been loaded by another class loader + if (result != null) + synchronized (this) { + if (loadedNativeCode == null) + loadedNativeCode = new ArrayList(1); + if (loadedNativeCode.contains(result)) { + // we must copy the library to a temp space to allow another class loader to load the library + String temp = copyToTempLibrary(result); + if (temp != null) + result = temp; + } else { + loadedNativeCode.add(result); + } + } return result; } + private String copyToTempLibrary(String result) { + try { + return adaptor.getStorage().copyToTempLibrary(this, result); + } catch (IOException e) { + adaptor.getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, e.getMessage(), 0, e, null)); + } + return null; + } + public void installNativeCode(String[] nativepaths) throws BundleException { adaptor.getStorage().installNativeCode(this, nativepaths); } diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleFile.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleFile.java index 0dee64150..e5cf0d8e7 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleFile.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleFile.java @@ -157,7 +157,11 @@ abstract public class BundleFile { return mruIndex; } - protected static void setPermissions(File nested) { + /** + * Attempts to set the permissions of the file in a system dependant 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) return; @@ -166,14 +170,14 @@ abstract public class BundleFile { boolean foundFullPath = false; for (int i = 0; i < temp.length; i++) { if ("[fullpath]".equals(temp[i])) { //$NON-NLS-1$ - command.add(nested.getAbsolutePath()); + command.add(file.getAbsolutePath()); foundFullPath = true; } else command.add(temp[i]); } if (!foundFullPath) - command.add(nested.getAbsolutePath()); + command.add(file.getAbsolutePath()); try { Runtime.getRuntime().exec((String[]) command.toArray(new String[command.size()])).waitFor(); } catch (Exception e) { diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java index 2a511eef3..c9227ede3 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java @@ -46,6 +46,8 @@ public class ClasspathManager { private ClasspathEntry[] entries; private BaseClassLoader classloader; private FragmentClasspath[] fragments = emptyFragments; + // a colloction of String[2], each element is {"libname", "libpath"} + private Collection loadedLibraries = null; /** * Constructs a classpath manager for the given host base data, classpath and base class loader @@ -530,4 +532,26 @@ public class ClasspathManager { return classloader; } + public String findLibrary(String libname) { + synchronized (this) { + if (loadedLibraries == null) + loadedLibraries = new ArrayList(1); + } + synchronized (loadedLibraries) { + // we assume that each classloader will load a small number of of libraries + // instead of wasting space with a map we iterate over our collection of found libraries + // each element is a String[2], each array is {"libname", "libpath"} + for (Iterator libs = loadedLibraries.iterator(); libs.hasNext();) { + String[] libNameResult = (String[]) libs.next(); + if (libNameResult[0].equals(libname)) + return libNameResult[1]; + } + + String result = classloader.getDelegate().findLibrary(libname); + if (result != null) + loadedLibraries.add(new String[] {libname, result}); + return result; + } + } + } diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorage.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorage.java index c7aaa60c1..16aeb9b31 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorage.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorage.java @@ -47,6 +47,7 @@ public class BaseStorage { private static final String PROP_BUNDLE_STORE = "osgi.bundlestore"; //$NON-NLS-1$ // The name of the bundle data directory static final String DATA_DIR_NAME = "data"; //$NON-NLS-1$ + static final String LIB_TEMP = "libtemp"; //$NON-NLS-1$ // System property used to determine whether State saver needs to be enabled private static final String PROP_ENABLE_STATE_SAVER = "eclipse.enableStateSaver"; //$NON-NLS-1$ static final String BUNDLEFILE_NAME = "bundlefile"; //$NON-NLS-1$ @@ -71,6 +72,13 @@ public class BaseStorage { * flag to indicate a framework extension is being updated */ public static final byte EXTENSION_UPDATED = 0x08; + + /** + * the file name for the delete flag. If this file exists in one a directory + * under the bundle store area then it will be removed during the + * compact operation. + */ + public static final String DELETE_FLAG = ".delete"; //$NON-NLS-1$ private static final String PERM_DATA_FILE = ".permdata"; //$NON-NLS-1$ private static final byte PERMDATA_VERSION = 1; @@ -186,7 +194,7 @@ public class BaseStorage { // if the file is a directory if (!target.isDirectory()) continue; - File delete = new File(target, ".delete"); //$NON-NLS-1$ + File delete = new File(target, BaseStorage.DELETE_FLAG); // and the directory is marked for delete if (delete.exists()) { // if rm fails to delete the directory and .delete was removed @@ -1127,4 +1135,58 @@ public class BaseStorage { return nextId++; } + public String copyToTempLibrary(BaseData data, String absolutePath) throws IOException { + File storageRoot = getBundleStoreRoot(); + File libTempDir = new File(storageRoot, 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(data.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, BaseStorage.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 + InputStream in = new FileInputStream(realLib); + AdaptorUtil.readFile(in, libTempFile); + // set permissions if needed + BundleFile.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(); + } + } diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorageHook.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorageHook.java index d3537ae1b..500afc19a 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorageHook.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorageHook.java @@ -238,7 +238,7 @@ public class BaseStorageHook implements StorageHook, AdaptorHook{ } if (delete != null && delete.exists() && (postpone || !AdaptorUtil.rm(delete))) { /* create .delete */ - FileOutputStream out = new FileOutputStream(new File(delete, ".delete")); //$NON-NLS-1$ + FileOutputStream out = new FileOutputStream(new File(delete, BaseStorage.DELETE_FLAG)); out.close(); } } diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader.java index 8cce9985a..61770b076 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader.java @@ -145,7 +145,8 @@ public class DefaultClassLoader extends ClassLoader implements BaseClassLoader { * @return The URL of the resource or null if it does not exist. */ protected String findLibrary(String libname) { - return delegate.findLibrary(libname); + // let the manager find the library for us + return manager.findLibrary(libname); } public ProtectionDomain getDomain() { |