aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Ross2013-09-23 16:26:38 (EDT)
committerJohn Ross2013-09-23 16:26:38 (EDT)
commitaa6a7a8049cfe5089b7307c3a815e16b15d5f0b2 (patch)
tree49ba68dc715c98ac835112fd6601197922acc6ce
parent6afd5367b39f14e27e87a12a785b9044f6dd6588 (diff)
downloadrt.equinox.framework-aa6a7a8049cfe5089b7307c3a815e16b15d5f0b2.zip
rt.equinox.framework-aa6a7a8049cfe5089b7307c3a815e16b15d5f0b2.tar.gz
rt.equinox.framework-aa6a7a8049cfe5089b7307c3a815e16b15d5f0b2.tar.bz2
Bug 411877 - BundleWiring.listResources does not work properly in dev mode
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/HookRegistry.java8
-rwxr-xr-xbundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevBundleFileWrapper.java212
-rwxr-xr-xbundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevBundleFileWrapperFactoryHook.java39
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevClassLoadingHook.java26
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/classpath/ClasspathManager.java10
-rwxr-xr-xbundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapper.java5
6 files changed, 286 insertions, 14 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/HookRegistry.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/HookRegistry.java
index 19354f7..4b0bb17 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/HookRegistry.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/HookRegistry.java
@@ -18,8 +18,7 @@ import java.util.*;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.internal.framework.EquinoxConfiguration;
import org.eclipse.osgi.internal.framework.EquinoxContainer;
-import org.eclipse.osgi.internal.hooks.DevClassLoadingHook;
-import org.eclipse.osgi.internal.hooks.EclipseLazyStarter;
+import org.eclipse.osgi.internal.hooks.*;
import org.eclipse.osgi.internal.signedcontent.SignedBundleHook;
import org.eclipse.osgi.internal.weaving.WeavingHookConfigurator;
import org.eclipse.osgi.util.ManifestElement;
@@ -99,11 +98,14 @@ public final class HookRegistry {
mergeFileHookConfigurators(configurators, errors);
mergePropertyHookConfigurators(configurators);
synchronized (this) {
- addClassLoaderHook(new DevClassLoadingHook(container.getConfiguration()));
+ EquinoxConfiguration configuration = container.getConfiguration();
+ addClassLoaderHook(new DevClassLoadingHook(configuration));
addClassLoaderHook(new EclipseLazyStarter(container));
addClassLoaderHook(new WeavingHookConfigurator(container));
configurators.add(SignedBundleHook.class.getName());
loadConfigurators(configurators, errors);
+ if (configuration.inDevelopmentMode())
+ addBundleFileWrapperFactoryHook(new DevBundleFileWrapperFactoryHook(configuration));
// set to read-only
initialized = true;
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevBundleFileWrapper.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevBundleFileWrapper.java
new file mode 100755
index 0000000..2bb763d
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevBundleFileWrapper.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ * Copyright (c) 2013 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.internal.hooks;
+
+import java.io.File;
+import java.util.*;
+import org.eclipse.osgi.internal.framework.EquinoxConfiguration;
+import org.eclipse.osgi.internal.loader.classpath.ClasspathManager;
+import org.eclipse.osgi.storage.BundleInfo.Generation;
+import org.eclipse.osgi.storage.bundlefile.*;
+import org.osgi.framework.wiring.BundleRevision;
+
+/*
+ * BundleFileWrapper.getFile(String, boolean) is not overridden because only
+ * the base bundle file should be called for this method, which the superclass
+ * already does.
+ */
+public class DevBundleFileWrapper extends BundleFileWrapper {
+ private final EquinoxConfiguration configuration;
+ private final Generation generation;
+
+ private volatile Collection<String> devClasspath;
+ private volatile Collection<NestedDirBundleFile> nested;
+
+ public DevBundleFileWrapper(BundleFile bundleFile, Generation generation, EquinoxConfiguration configuration) {
+ super(bundleFile);
+ if (generation == null || configuration == null)
+ throw new NullPointerException();
+ this.generation = generation;
+ this.configuration = configuration;
+
+ }
+
+ @Override
+ public boolean containsDir(String dir) {
+ if (!isRootOnBundleClasspath())
+ return getBundleFile().containsDir(dir);
+ if (getBundleFile().containsDir(dir))
+ return true;
+ for (NestedDirBundleFile bundleFile : getNestedDirBundleFiles())
+ if (bundleFile.containsDir(dir))
+ return true;
+ return false;
+ }
+
+ @Override
+ public BundleEntry getEntry(String path) {
+ if (!isRootOnBundleClasspath()) {
+ if (isPathOnDevelopmentClasspath(path))
+ return null;
+ return getBundleFile().getEntry(path);
+ }
+ if (isPathOnDevelopmentClasspath(path))
+ return getEntryFromNestedDirBundleFiles(path);
+ return getEntryFromBundleFile(path);
+ }
+
+ @Override
+ public Enumeration<String> getEntryPaths(String path, boolean recurse) {
+ Collection<String> result = new LinkedHashSet<String>();
+ if (!isRootOnBundleClasspath()) {
+ if (!isPathOnDevelopmentClasspath(path))
+ addEntryPathsFromBundleFile(path, recurse, result);
+ } else if (isPathOnDevelopmentClasspath(path)) {
+ addEntryPathsFromNestedDirBundleFiles(path, recurse, result);
+ } else {
+ addEntryPathsFromBundleFile(path, recurse, result);
+ addEntryPathsFromNestedDirBundleFiles(path, recurse, result);
+ }
+ return result.isEmpty() ? null : Collections.enumeration(result);
+ }
+
+ @Override
+ public File getFile(String path, boolean nativeCode) {
+ return getBundleFile().getFile(path, nativeCode);
+ }
+
+ private Collection<NestedDirBundleFile> getNestedDirBundleFiles() {
+ Collection<NestedDirBundleFile> result = nested;
+ if (result == null) {
+ synchronized (this) {
+ if (result == null) {
+ Collection<String> ss = getDevClasspath();
+ if (ss == null)
+ return Collections.emptyList();
+ result = nested = new HashSet<NestedDirBundleFile>(ss.size());
+ for (String s : ss)
+ // Don't pass 'this' to NestedDirBundleFile or an
+ // infinite loop results.
+ result.add(new NestedDirBundleFile(getBundleFile(), s));
+ }
+ }
+ }
+ return result;
+ }
+
+ private Collection<String> getDevClasspath() {
+ Collection<String> result = devClasspath;
+ if (result == null) {
+ synchronized (this) {
+ if (result == null) {
+ BundleRevision revision = generation.getRevision();
+ if (revision == null)
+ return null;
+ String[] ss = configuration.getDevClassPath(revision.getSymbolicName());
+ if (ss == null || ss.length == 0)
+ result = devClasspath = Collections.emptyList();
+ else {
+ result = devClasspath = new LinkedHashSet<String>(ss.length);
+ for (String s : ss)
+ if (!s.contains("..")) //$NON-NLS-1$
+ result.add(s);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ private BundleEntry getEntryFromBundleFile(String path) {
+ return getBundleFile().getEntry(path);
+ }
+
+ private BundleEntry getEntryFromNestedDirBundleFiles(String path) {
+ for (NestedDirBundleFile f : getNestedDirBundleFiles()) {
+ BundleEntry entry = f.getEntry(path);
+ if (entry != null)
+ return entry;
+ }
+ return null;
+ }
+
+ private void addEntryPathsFromBundleFile(String path, boolean recurse, Collection<String> entryPaths) {
+ Enumeration<String> e = getBundleFile().getEntryPaths(path, recurse);
+ if (e == null)
+ return;
+ while (e.hasMoreElements()) {
+ String s = strip(e.nextElement());
+ if (s.length() > 0)
+ entryPaths.add(s);
+ }
+ }
+
+ private void addEntryPathsFromNestedDirBundleFiles(String path, boolean recurse, Collection<String> entryPaths) {
+ for (NestedDirBundleFile f : getNestedDirBundleFiles()) {
+ Enumeration<String> e = f.getEntryPaths(path, recurse);
+ if (e != null)
+ entryPaths.addAll(Collections.list(e));
+ }
+ }
+
+ private String strip(String path) {
+ for (String s : getDevClasspath())
+ if (path.startsWith(s))
+ return path.substring(s.length() + 1);
+ return path;
+ }
+
+ private boolean isRootOnBundleClasspath() {
+ BundleRevision revision = generation.getRevision();
+ if (revision == null)
+ return true;
+ return Arrays.asList(ClasspathManager.getClassPath(revision)).contains("."); //$NON-NLS-1$
+ }
+
+ private String findMatchingPathOnDevelopmentClasspath(String pathToMatch) {
+ return findMatchingPathOnDevelopmentClasspath(pathToMatch, getDevClasspath(), getBundleFile());
+ }
+
+ private boolean isPathOnDevelopmentClasspath(String path) {
+ return findMatchingPathOnDevelopmentClasspath(path) != null;
+ }
+
+ static boolean isRoot(String path) {
+ return "/".equals(path) || ".".equals(path); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ private static String findMatchingPathOnDevelopmentClasspath(String pathToMatch, Collection<String> devClasspath, BundleFile bundleFile) {
+ return findMatchingPathOnDevelopmentClasspath(pathToMatch, devClasspath == null ? new String[0] : devClasspath.toArray(new String[devClasspath.size()]), bundleFile);
+ }
+
+ static String findMatchingPathOnDevelopmentClasspath(String pathToMatch, String[] devClasspath, BundleFile bundleFile) {
+ if (isRoot(pathToMatch))
+ return null;
+ // For each element on the development classpath...
+ for (String path : devClasspath) {
+ // ...see if the bundle file has a matching entry...
+ BundleEntry entry = bundleFile.getEntry(path);
+ if (entry == null)
+ // ...if not, then the element is of no interest.
+ continue;
+ // ...if so, then see if the entry contains the given path...
+ String name = entry.getName();
+ if (pathToMatch.startsWith(name) || name.startsWith(pathToMatch))
+ // ...if it does, we have our match.
+ return name;
+ // ...if prepending the path to match with the entry name find an
+ // entry, then we have our match.
+ if (bundleFile.getEntry(name + pathToMatch) != null)
+ return name;
+ }
+ return null;
+ }
+}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevBundleFileWrapperFactoryHook.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevBundleFileWrapperFactoryHook.java
new file mode 100755
index 0000000..3b83561
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevBundleFileWrapperFactoryHook.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2013 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.internal.hooks;
+
+import org.eclipse.osgi.internal.framework.EquinoxConfiguration;
+import org.eclipse.osgi.internal.hookregistry.BundleFileWrapperFactoryHook;
+import org.eclipse.osgi.storage.BundleInfo.Generation;
+import org.eclipse.osgi.storage.bundlefile.BundleFile;
+import org.eclipse.osgi.storage.bundlefile.BundleFileWrapper;
+
+/*
+ * Returns DevBundleFileWrapper objects for base bundle files that are
+ * directories when in development mode. Ideally, this hook should not be
+ * registered if not in development mode.
+ */
+public class DevBundleFileWrapperFactoryHook implements BundleFileWrapperFactoryHook {
+ private EquinoxConfiguration configuration;
+
+ public DevBundleFileWrapperFactoryHook(EquinoxConfiguration configuration) {
+ if (configuration == null)
+ throw new NullPointerException();
+ this.configuration = configuration;
+ }
+
+ @Override
+ public BundleFileWrapper wrapBundleFile(BundleFile bundleFile, Generation generation, boolean base) {
+ if (base && configuration.inDevelopmentMode() && bundleFile.getBaseFile().isDirectory())
+ return new DevBundleFileWrapper(bundleFile, generation, configuration);
+ return null;
+ }
+}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevClassLoadingHook.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevClassLoadingHook.java
index d936f4e..514278d 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevClassLoadingHook.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hooks/DevClassLoadingHook.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2012 IBM Corporation and others.
+ * Copyright (c) 2006, 2013 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
@@ -19,6 +19,7 @@ import org.eclipse.osgi.internal.hookregistry.ClassLoaderHook;
import org.eclipse.osgi.internal.loader.classpath.*;
import org.eclipse.osgi.storage.BundleInfo.Generation;
import org.eclipse.osgi.storage.bundlefile.BundleFile;
+import org.osgi.framework.wiring.BundleRevision;
public class DevClassLoadingHook extends ClassLoaderHook implements KeyedElement {
public static final String KEY = DevClassLoadingHook.class.getName();
@@ -42,6 +43,12 @@ public class DevClassLoadingHook extends ClassLoaderHook implements KeyedElement
return false; // this source has already had its dev classpath entries added.
boolean result = false;
for (int i = 0; i < devClassPath.length; i++) {
+ BundleFile bundleFile = sourceGeneration.getBundleFile();
+ // If the bundle file is a directory and contains the classpath as an
+ // entry, don't add a classpath entry. The bundle file will do the work
+ // itself. See bug 411877.
+ if (!isClasspathEntryRequired(cp, sourceGeneration, devClassPath[i]))
+ continue;
if (hostmanager.addClassPathEntry(cpEntries, devClassPath[i], hostmanager, sourceGeneration))
result = true;
else {
@@ -49,7 +56,7 @@ public class DevClassLoadingHook extends ClassLoaderHook implements KeyedElement
boolean fromFragment = devCP.endsWith(FRAGMENT);
if (!fromFragment && devCP.indexOf("..") >= 0) { //$NON-NLS-1$
// if in dev mode, try using cp as a relative path from the base bundle file
- File base = sourceGeneration.getBundleFile().getBaseFile();
+ File base = bundleFile.getBaseFile();
if (base.isDirectory()) {
// this is only supported for directory bundles
ClasspathEntry entry = hostmanager.getExternalClassPath(new File(base, devCP).getAbsolutePath(), sourceGeneration);
@@ -109,4 +116,19 @@ public class DevClassLoadingHook extends ClassLoaderHook implements KeyedElement
public int getKeyHashCode() {
return HASHCODE;
}
+
+ private boolean isClasspathEntryRequired(String classpath, Generation generation, String devClasspath) {
+ if (!generation.getBundleFile().getBaseFile().isDirectory())
+ return true;
+ if (devClasspath.contains("..")) //$NON-NLS-1$
+ return true;
+ if (!isPathOnDevelopmentClasspath(classpath, generation) && !DevBundleFileWrapper.isRoot(classpath))
+ return true;
+ return false;
+ }
+
+ private boolean isPathOnDevelopmentClasspath(String path, Generation generation) {
+ BundleRevision revision = generation.getRevision();
+ return DevBundleFileWrapper.findMatchingPathOnDevelopmentClasspath(path, configuration.getDevClassPath(revision.getSymbolicName()), generation.getBundleFile()) != null;
+ }
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/classpath/ClasspathManager.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/classpath/ClasspathManager.java
index bb4ea80..aaa91bf 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/classpath/ClasspathManager.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/classpath/ClasspathManager.java
@@ -16,8 +16,8 @@ import java.net.URL;
import java.util.*;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
-import org.eclipse.osgi.container.*;
import org.eclipse.osgi.container.ModuleContainerAdaptor.ContainerEvent;
+import org.eclipse.osgi.container.*;
import org.eclipse.osgi.container.namespaces.EquinoxModuleDataNamespace;
import org.eclipse.osgi.framework.util.ArrayMap;
import org.eclipse.osgi.internal.debug.Debug;
@@ -33,6 +33,8 @@ import org.eclipse.osgi.storage.bundlefile.BundleFile;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.BundleException;
import org.osgi.framework.namespace.HostNamespace;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Resource;
/**
* A helper class for <code>BaseClassLoader</code> implementations. This class will keep track of
@@ -84,10 +86,10 @@ public class ClasspathManager {
this.entries = buildClasspath(cp, this, this.generation);
}
- private static String[] getClassPath(ModuleRevision revision) {
- List<ModuleCapability> moduleDatas = revision.getModuleCapabilities(EquinoxModuleDataNamespace.MODULE_DATA_NAMESPACE);
+ public static String[] getClassPath(Resource resource) {
+ List<Capability> capabilities = resource.getCapabilities(EquinoxModuleDataNamespace.MODULE_DATA_NAMESPACE);
@SuppressWarnings("unchecked")
- List<String> cp = moduleDatas.isEmpty() ? null : (List<String>) moduleDatas.get(0).getAttributes().get(EquinoxModuleDataNamespace.CAPABILITY_CLASSPATH);
+ List<String> cp = capabilities.isEmpty() ? null : (List<String>) capabilities.get(0).getAttributes().get(EquinoxModuleDataNamespace.CAPABILITY_CLASSPATH);
return cp == null ? DEFAULT_CLASSPATH : cp.toArray(new String[cp.size()]);
}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapper.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapper.java
index 33f5938..50ec437 100755
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapper.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapper.java
@@ -51,11 +51,6 @@ public class BundleFileWrapper extends BundleFile {
}
@Override
- public Enumeration<String> getEntryPaths(String path) {
- return bundleFile.getEntryPaths(path);
- }
-
- @Override
public Enumeration<String> getEntryPaths(String path, boolean recurse) {
return bundleFile.getEntryPaths(path, recurse);
}