Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/BundleComponent.java7
-rw-r--r--ds/org.eclipse.pde.ds.ui/META-INF/MANIFEST.MF2
-rw-r--r--ds/org.eclipse.pde.ds.ui/pom.xml2
-rw-r--r--features/org.eclipse.pde-feature/feature.xml14
-rw-r--r--pom.xml1
-rw-r--r--releng/org.eclipse.pde.ui.setup/PDE.setup2
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/ClasspathHelper.java357
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/MinimalState.java4
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/TargetWeaver.java149
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/BundleErrorReporter.java5
-rw-r--r--ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/exports/FeatureExportOperation.java4
-rw-r--r--ui/org.eclipse.pde.launching/schema/osgiFrameworks.exsd16
-rw-r--r--ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchListener.java3
-rw-r--r--ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/JUnitLaunchConfigurationDelegate.java9
-rw-r--r--ui/org.eclipse.pde.spy.context/.classpath7
-rw-r--r--ui/org.eclipse.pde.spy.context/.project28
-rw-r--r--ui/org.eclipse.pde.spy.context/.settings/org.eclipse.jdt.core.prefs9
-rw-r--r--ui/org.eclipse.pde.spy.context/META-INF/MANIFEST.MF25
-rw-r--r--ui/org.eclipse.pde.spy.context/README.md13
-rw-r--r--ui/org.eclipse.pde.spy.context/about.html28
-rw-r--r--ui/org.eclipse.pde.spy.context/build.properties9
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/annotation_obj.pngbin0 -> 536 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/annotation_obj@2x.pngbin0 -> 1185 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/collapseall.pngbin0 -> 208 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/collapseall@2x.pngbin0 -> 349 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/contextfunction.pngbin0 -> 338 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/contextfunction@2x.pngbin0 -> 601 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/expandall.pngbin0 -> 239 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/expandall@2x.pngbin0 -> 440 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/field_public_obj.pngbin0 -> 217 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/field_public_obj@2x.pngbin0 -> 398 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/inher_co.pngbin0 -> 265 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/inher_co@2x.pngbin0 -> 505 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/letter-l-icon.pngbin0 -> 498 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/letter-l-icon@2x.pngbin0 -> 943 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/methpub_obj.pngbin0 -> 264 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/methpub_obj@2x.pngbin0 -> 503 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/refresh.pngbin0 -> 586 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/refresh@2x.pngbin0 -> 1249 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/splash.pngbin0 -> 39688 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/valueincontext.pngbin0 -> 247 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/icons/valueincontext@2x.pngbin0 -> 451 bytes
-rw-r--r--ui/org.eclipse.pde.spy.context/plugin.properties18
-rw-r--r--ui/org.eclipse.pde.spy.context/plugin.xml13
-rw-r--r--ui/org.eclipse.pde.spy.context/pom.xml30
-rw-r--r--ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextDataFilter.java165
-rw-r--r--ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextDataPart.java212
-rw-r--r--ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextDataProvider.java366
-rw-r--r--ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextSpyHelper.java65
-rw-r--r--ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextSpyProvider.java115
-rw-r--r--ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/spy/context/ContextSpyPart.java224
-rw-r--r--ui/org.eclipse.pde.spy.core/src/org/eclipse/pde/spy/core/SpyProcessor.java2
-rw-r--r--ui/org.eclipse.pde.ui.tests.smartimport/META-INF/MANIFEST.MF20
-rw-r--r--ui/org.eclipse.pde.ui.tests.smartimport/pom.xml2
-rw-r--r--ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF3
-rw-r--r--ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/core/tests/internal/DependencyManagerTest.java20
-rw-r--r--ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/core/tests/internal/classpath/ClasspathResolutionTest.java26
-rw-r--r--ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathcontributor/ClasspathContributorTest.java80
-rw-r--r--ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathresolver/ClasspathResolverTest.java375
-rw-r--r--ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/AbstractLaunchTest.java90
-rw-r--r--ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/LaunchConfigurationMigrationTest.java5
-rw-r--r--ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/PluginBasedLaunchTest.java10
-rw-r--r--ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/project/DynamicPluginProjectReferencesTest.java13
-rw-r--r--ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/runtime/TestUtils.java104
-rw-r--r--ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/ProjectUtils.java100
-rw-r--r--ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/TargetPlatformUtil.java129
-rw-r--r--ui/org.eclipse.pde.ui.tests/tests/launch/.project11
-rw-r--r--ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/ManifestEditor.java5
68 files changed, 2166 insertions, 731 deletions
diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/BundleComponent.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/BundleComponent.java
index bebb5f0b9d..af4f09ae02 100644
--- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/BundleComponent.java
+++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/BundleComponent.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2018 IBM Corporation and others.
+ * Copyright (c) 2007, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -197,8 +197,9 @@ public class BundleComponent extends Component {
*/
protected synchronized Map<String, String> getManifest() throws CoreException {
if (fManifest == null) {
+ File bundleLocation = new File(fLocation);
try {
- fManifest = ManifestUtils.loadManifest(new File(fLocation));
+ fManifest = ManifestUtils.loadManifest(bundleLocation);
} catch (CoreException e) {
if (e.getStatus().getCode() == ManifestUtils.STATUS_CODE_NOT_A_BUNDLE_MANIFEST) {
// If we load a component with a manifest file that isn't a
@@ -212,7 +213,7 @@ public class BundleComponent extends Component {
// must account for bundles in development mode - look for class
// files in output
// folders rather than jars
- TargetWeaver.weaveManifest(fManifest);
+ TargetWeaver.weaveManifest(fManifest, bundleLocation);
}
}
return fManifest;
diff --git a/ds/org.eclipse.pde.ds.ui/META-INF/MANIFEST.MF b/ds/org.eclipse.pde.ds.ui/META-INF/MANIFEST.MF
index 5011f72d27..5495fe0ca8 100644
--- a/ds/org.eclipse.pde.ds.ui/META-INF/MANIFEST.MF
+++ b/ds/org.eclipse.pde.ds.ui/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.pde.ds.ui;singleton:=true
-Bundle-Version: 1.2.100.qualifier
+Bundle-Version: 1.2.200.qualifier
Bundle-Activator: org.eclipse.pde.internal.ds.ui.Activator
Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.11.0,4.0.0)",
org.eclipse.core.resources;bundle-version="[3.3.0,4.0.0)",
diff --git a/ds/org.eclipse.pde.ds.ui/pom.xml b/ds/org.eclipse.pde.ds.ui/pom.xml
index 9acf6fbfe4..6a00cfbc35 100644
--- a/ds/org.eclipse.pde.ds.ui/pom.xml
+++ b/ds/org.eclipse.pde.ds.ui/pom.xml
@@ -20,6 +20,6 @@
</parent>
<groupId>org.eclipse.pde</groupId>
<artifactId>org.eclipse.pde.ds.ui</artifactId>
- <version>1.2.100-SNAPSHOT</version>
+ <version>1.2.200-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
diff --git a/features/org.eclipse.pde-feature/feature.xml b/features/org.eclipse.pde-feature/feature.xml
index ceaa4f2ed6..73fb861535 100644
--- a/features/org.eclipse.pde-feature/feature.xml
+++ b/features/org.eclipse.pde-feature/feature.xml
@@ -216,4 +216,18 @@
version="0.0.0"
unpack="false"/>
+ <plugin
+ id="org.eclipse.pde.spy.context"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.pde.spy.bundle"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
</feature>
diff --git a/pom.xml b/pom.xml
index 151460df14..328f87113b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,6 +77,7 @@
<module>ui/org.eclipse.pde.spy.bundle</module>
<module>ui/org.eclipse.pde.spy.css</module>
<module>ui/org.eclipse.pde.spy.model</module>
+ <module>ui/org.eclipse.pde.spy.context</module>
<module>ui/org.eclipse.pde.spy.preferences</module>
<module>ui/org.eclipse.tools.layout.spy</module>
<module>ui/org.eclipse.pde.ui.templates.tests</module>
diff --git a/releng/org.eclipse.pde.ui.setup/PDE.setup b/releng/org.eclipse.pde.ui.setup/PDE.setup
index b722342d00..25b01de670 100644
--- a/releng/org.eclipse.pde.ui.setup/PDE.setup
+++ b/releng/org.eclipse.pde.ui.setup/PDE.setup
@@ -100,7 +100,7 @@
<repository
url="http://download.eclipse.org/cbi/updates/license"/>
<repository
- url="http://download.eclipse.org/reddeer/releases/2.9.0"/>
+ url="http://download.eclipse.org/reddeer/releases/3.5.0"/>
<repository
url="https://download.eclipse.org/reddeer/releases/latest"/>
</repositoryList>
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/ClasspathHelper.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/ClasspathHelper.java
index db366e13c6..16655d2594 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/ClasspathHelper.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/ClasspathHelper.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2017 IBM Corporation and others.
+ * Copyright (c) 2003, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,8 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Hannes Wellmann - Bug 577541 - Clean up ClasspathHelper and TargetWeaver
+ * Hannes Wellmann - Bug 577543 - Only weave dev.properties for secondary launches if plug-in is from Running-Platform
*******************************************************************************/
package org.eclipse.pde.internal.core;
@@ -20,17 +22,16 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.Dictionary;
import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Iterator;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
-import java.util.ListIterator;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Properties;
-import java.util.StringTokenizer;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
@@ -38,7 +39,6 @@ import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
@@ -51,7 +51,6 @@ import org.eclipse.pde.core.IBundleClasspathResolver;
import org.eclipse.pde.core.build.IBuild;
import org.eclipse.pde.core.build.IBuildEntry;
import org.eclipse.pde.core.plugin.IFragmentModel;
-import org.eclipse.pde.core.plugin.IPluginBase;
import org.eclipse.pde.core.plugin.IPluginLibrary;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.plugin.PluginRegistry;
@@ -60,56 +59,30 @@ import org.eclipse.pde.internal.core.project.PDEProject;
public class ClasspathHelper {
+ private ClasspathHelper() { // static use only
+ }
+
private static final String DOT = "."; //$NON-NLS-1$
private static final String FRAGMENT_ANNOTATION = "@fragment@"; //$NON-NLS-1$
- public static String getDevEntriesProperties(String fileName, boolean checkExcluded) {
- File file = new File(fileName);
- if (!file.exists()) {
- File directory = file.getParentFile();
- if (directory != null && (!directory.exists() || directory.isFile())) {
- directory.mkdirs();
- }
- }
- Properties properties = new Properties();
- // account for cascading workspaces
- TargetWeaver.weaveDevProperties(properties);
+ public static String getDevEntriesProperties(String fileName, boolean checkExcluded) throws CoreException {
IPluginModelBase[] models = PluginRegistry.getWorkspaceModels();
+ Map<String, IPluginModelBase> bundleModels = new HashMap<>();
for (IPluginModelBase model : models) {
- String id = model.getPluginBase().getId();
- if (id == null) {
- continue;
- }
- String entry = writeEntry(getDevPaths(model, checkExcluded, null));
- if (entry.length() > 0) {
- String currentValue = (String) properties.get(id);
- if (!entry.equals(currentValue)) {
- if (currentValue != null) {
- entry = currentValue.concat(",").concat(entry); //$NON-NLS-1$
- }
- properties.put(id, entry);
- }
- }
+ bundleModels.put(model.getPluginBase().getId(), model);
}
- properties.put("@ignoredot@", "true"); //$NON-NLS-1$ //$NON-NLS-2$
- try (FileOutputStream stream = new FileOutputStream(fileName)) {
- properties.store(stream, ""); //$NON-NLS-1$
- stream.flush();
- return new URL("file:" + fileName).toString(); //$NON-NLS-1$
- } catch (IOException e) {
- PDECore.logException(e);
- }
- return getDevEntries(checkExcluded);
+ Properties properties = getDevEntriesProperties(bundleModels, checkExcluded);
+ return writeDevEntries(fileName, properties);
}
- public static String getDevEntriesProperties(String fileName, Map<?, ?> map) {
- @SuppressWarnings("unchecked")
- Properties properties = getDevEntriesProperties((Map<?, IPluginModelBase>) map);
+ public static String getDevEntriesProperties(String fileName, Map<String, IPluginModelBase> map)
+ throws CoreException {
+ Properties properties = getDevEntriesProperties(map, true);
return writeDevEntries(fileName, properties);
}
- public static String writeDevEntries(String fileName, Properties properties) {
+ public static String writeDevEntries(String fileName, Properties properties) throws CoreException {
File file = new File(fileName);
if (!file.exists()) {
File directory = file.getParentFile();
@@ -119,32 +92,24 @@ public class ClasspathHelper {
}
try (FileOutputStream stream = new FileOutputStream(fileName)) {
properties.store(stream, ""); //$NON-NLS-1$
- stream.flush();
return new URL("file:" + fileName).toString(); //$NON-NLS-1$
} catch (IOException e) {
PDECore.logException(e);
+ throw new CoreException(Status.error("Failed to create dev.properties file", e)); //$NON-NLS-1$
}
- return getDevEntries(true);
}
- public static Properties getDevEntriesProperties(Map<?, IPluginModelBase> bundlesMap) {
+ public static Properties getDevEntriesProperties(Map<String, IPluginModelBase> bundlesMap, boolean checkExcluded) {
Properties properties = new Properties();
// account for cascading workspaces
- TargetWeaver.weaveDevProperties(properties);
- Iterator<?> iter = bundlesMap.values().iterator();
- while (iter.hasNext()) {
- IPluginModelBase model = (IPluginModelBase) iter.next();
+ TargetWeaver.weaveRunningPlatformDevProperties(properties, bundlesMap.values());
+ for (IPluginModelBase model : bundlesMap.values()) {
if (model.getUnderlyingResource() != null) {
- String entry = writeEntry(getDevPaths(model, true, bundlesMap));
- if (entry.length() > 0) {
- String id = model.getPluginBase().getId();
- String currentValue = (String) properties.get(id);
- if (!entry.equals(currentValue)) {
- if (currentValue != null) {
- entry = currentValue.concat(",").concat(entry); //$NON-NLS-1$
- }
- properties.put(id, entry);
- }
+ String entry = formatEntry(getDevPaths(model, checkExcluded, bundlesMap.keySet()));
+ if (!entry.isEmpty()) {
+ // overwrite entry, if plug-in from primary Eclipse is also
+ // imported into workspace of secondary eclipse
+ properties.put(model.getPluginBase().getId(), entry);
}
}
}
@@ -152,60 +117,22 @@ public class ClasspathHelper {
return properties;
}
- private static String getDevEntries(boolean checkExcluded) {
- IPluginModelBase[] models = PluginRegistry.getWorkspaceModels();
- ArrayList<IPath> list = new ArrayList<>();
- for (IPluginModelBase model : models) {
- String id = model.getPluginBase().getId();
- if (id == null || id.trim().length() == 0) {
- continue;
- }
- IPath[] paths = getDevPaths(model, checkExcluded, null);
- Collections.addAll(list, paths);
- }
- String entry = writeEntry(list.toArray(new IPath[list.size()]));
- return entry.length() > 0 ? entry : "bin"; //$NON-NLS-1$
- }
-
- private static String writeEntry(IPath[] paths) {
- StringBuilder buffer = new StringBuilder();
- for (int i = 0; i < paths.length; i++) {
- buffer.append(paths[i].toString());
- if (i < paths.length - 1) {
- buffer.append(","); //$NON-NLS-1$
- }
- }
- return buffer.toString();
- }
-
- // TODO remove - no longer used after bug 217870
- public static Dictionary<String, String> getDevDictionary(IPluginModelBase model) {
- if (model.getUnderlyingResource() == null) {
- return null;
- }
-
- String id = model.getPluginBase().getId();
- if (id == null || id.trim().length() == 0) {
- return null;
- }
- IPath[] paths = getDevPaths(model, false, null);
- String entry = writeEntry(paths);
- Hashtable<String, String> map = new Hashtable<>(2);
- map.put("@ignoredot@", "true"); //$NON-NLS-1$ //$NON-NLS-2$
- map.put(id, entry.length() > 0 ? entry : "bin"); //$NON-NLS-1$
- return map;
+ private static String formatEntry(Collection<IPath> paths) {
+ return paths.stream().map(IPath::toString).collect(Collectors.joining(",")); //$NON-NLS-1$
}
// creates a map whose key is a Path to the source directory/jar and the value is a Path output directory or jar.
- private static Map<IPath, ArrayList<IPath>> getClasspathMap(IProject project, boolean checkExcluded, boolean absolutePaths) throws JavaModelException {
- List<Path> excluded = getFoldersToExclude(project, checkExcluded);
+ private static Map<IPath, List<IPath>> getClasspathMap(IProject project, boolean checkExcluded,
+ boolean absolutePaths) throws JavaModelException {
+ Set<Path> excluded = getFoldersToExclude(project, checkExcluded);
IJavaProject jProject = JavaCore.create(project);
- HashMap<IPath, ArrayList<IPath>> map = new LinkedHashMap<>();
+ Map<IPath, List<IPath>> map = new LinkedHashMap<>();
IClasspathEntry[] entries = jProject.getRawClasspath();
for (IClasspathEntry entry : entries) {
// most of the paths we get will be project relative, so we need to make the paths relative
// we will have problems adding an "absolute" path that is workspace relative
- IPath output = null, source = null;
+ IPath output = null;
+ IPath source = null;
if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
source = entry.getPath();
output = entry.getOutputLocation();
@@ -229,21 +156,14 @@ public class ClasspathHelper {
if (location != null) {
output = location.makeAbsolute();
} else {
- PDECore.log(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(PDECoreMessages.ClasspathHelper_BadFileLocation, file.getFullPath())));
+ PDECore.log(Status.error(NLS.bind(PDECoreMessages.ClasspathHelper_BadFileLocation, file.getFullPath())));
continue;
}
} else {
output = output.makeRelative();
}
- } else {
- continue;
+ map.computeIfAbsent(source, s -> new ArrayList<>()).add(output);
}
- ArrayList<IPath> list = map.get(source);
- if (list == null) {
- list = new ArrayList<>();
- }
- list.add(output);
- map.put(source, list);
}
}
@@ -251,38 +171,26 @@ public class ClasspathHelper {
IBundleClasspathResolver[] resolvers = PDECore.getDefault().getClasspathContainerResolverManager().getBundleClasspathResolvers(project);
for (IBundleClasspathResolver resolver : resolvers) {
Map<IPath, Collection<IPath>> resolved = resolver.getAdditionalClasspathEntries(jProject);
- Iterator<Entry<IPath, Collection<IPath>>> resolvedIter = resolved.entrySet().iterator();
- while (resolvedIter.hasNext()) {
- Map.Entry<IPath, Collection<IPath>> resolvedEntry = resolvedIter.next();
- IPath ceSource = resolvedEntry.getKey();
- ArrayList<IPath> list = map.get(ceSource);
- if (list == null) {
- list = new ArrayList<>();
- map.put(ceSource, list);
- }
- list.addAll(resolvedEntry.getValue());
- }
+ resolved.forEach((ceSource, value) -> { // merge into map
+ List<IPath> mapValue = map.computeIfAbsent(ceSource, s -> new ArrayList<>());
+ mapValue.addAll(value);
+ });
}
return map;
}
// find the corresponding paths for a library name. Searches for source folders first, but includes any libraries on the buildpath with the same name
- private static IPath[] findLibrary(String libName, IProject project, Map<IPath, ArrayList<IPath>> classpathMap, IBuild build) {
- ArrayList<IPath> paths = new ArrayList<>();
+ private static List<IPath> findLibrary(String libName, IProject project, Map<IPath, List<IPath>> classpathMap, IBuild build) {
+ List<IPath> paths = new ArrayList<>();
IBuildEntry entry = (build != null) ? build.getEntry(IBuildEntry.JAR_PREFIX + libName) : null;
if (entry != null) {
String[] resources = entry.getTokens();
for (String resource : resources) {
IResource res = project.findMember(resource);
if (res != null) {
- ArrayList<IPath> list = classpathMap.get(res.getFullPath());
- if (list != null) {
- Iterator<IPath> li = list.iterator();
- while (li.hasNext()) {
- paths.add(li.next());
- }
- }
+ List<IPath> list = classpathMap.getOrDefault(res.getFullPath(), Collections.emptyList());
+ paths.addAll(list);
}
}
}
@@ -300,109 +208,79 @@ public class ClasspathHelper {
}
}
- List<IPath> list = classpathMap.get(path);
- if (list != null) {
- Iterator<IPath> li = list.iterator();
- while (li.hasNext()) {
- paths.add(li.next());
- }
- }
- return paths.toArray(new IPath[paths.size()]);
+ List<IPath> list = classpathMap.getOrDefault(path, Collections.emptyList());
+ paths.addAll(list);
+ return paths;
}
- private static IPath[] getDevPaths(IPluginModelBase model, boolean checkExcluded, Map<?, ?> pluginsMap) {
- ArrayList<IPath> result = new ArrayList<>();
+ private static Set<IPath> getDevPaths(IPluginModelBase model, boolean checkExcluded, Set<String> plugins) {
IProject project = model.getUnderlyingResource().getProject();
- IPluginBase base = model.getPluginBase();
- IPluginLibrary[] libraries = base.getLibraries();
try {
if (project.hasNature(JavaCore.NATURE_ID)) {
- Map<IPath, ArrayList<IPath>> classpathMap = getClasspathMap(project, checkExcluded, false);
- IFile file = PDEProject.getBuildProperties(project);
- IPath filePath = file.getLocation();
- boolean searchBuild = filePath != null && filePath.toFile().exists();
- if (searchBuild) {
- WorkspaceBuildModel bModel = new WorkspaceBuildModel(file);
- IBuild build = bModel.getBuild();
- // if it is a custom build, act like there is no build.properties (add everything)
- IBuildEntry entry = build.getEntry("custom"); //$NON-NLS-1$
- if (entry != null) {
- searchBuild = false;
+ Map<IPath, List<IPath>> classpathMap = getClasspathMap(project, checkExcluded, false);
+ IBuild build = getBuild(project);
+ Set<IPath> result = new LinkedHashSet<>();
+ // if it is a custom build, act like there is no build.properties (add everything)
+ if (build != null && build.getEntry("custom") == null) { //$NON-NLS-1$
+ IPluginLibrary[] libraries = model.getPluginBase().getLibraries();
+ if (libraries.length == 0) {
+ List<IPath> paths = findLibrary(DOT, project, classpathMap, build);
+ if (paths.isEmpty() && !classpathMap.isEmpty()) {
+ // No mapping for default library, if there are source folders just add their corresponding output folders to the build path.
+ // This likely indicates an error in the build.properties, but to be friendly we should add the output folders so running/debugging
+ // works (see bug 237025)
+ paths = new ArrayList<>();
+ classpathMap.values().forEach(paths::addAll);
+ }
+ addPaths(paths, project, result);
} else {
- if (libraries.length == 0) {
- IPath[] paths = findLibrary(DOT, project, classpathMap, build);
- if (paths.length == 0) {
- // No mapping for default library, if there are source folders just add their corresponding output folders to the build path.
- // This likely indicates an error in the build.properties, but to be friendly we should add the output folders so running/debugging
- // works (see bug 237025)
- if (!classpathMap.isEmpty()) {
- Iterator<ArrayList<IPath>> iterator = classpathMap.values().iterator();
- List<IPath> collect = new ArrayList<>();
- while (iterator.hasNext()) {
- collect.addAll(iterator.next());
- }
- paths = collect.toArray(new IPath[collect.size()]);
- }
+ for (int i = 0; i < libraries.length; i++) {
+ List<IPath> paths = findLibrary(libraries[i].getName(), project, classpathMap, build);
+ if (paths.isEmpty() && !libraries[i].getName().equals(DOT)) {
+ paths = findLibraryFromFragments(libraries[i].getName(), model, checkExcluded, plugins);
}
- for (IPath path : paths) {
- addPath(result, project, path);
- }
- } else {
- for (int i = 0; i < libraries.length; i++) {
- IPath[] paths = findLibrary(libraries[i].getName(), project, classpathMap, build);
- if (paths.length == 0 && !libraries[i].getName().equals(DOT)) {
- paths = findLibraryFromFragments(libraries[i].getName(), model, checkExcluded, pluginsMap);
- }
- for (IPath path : paths) {
- addPath(result, project, path);
- }
- }
- }
- }
- }
- if (!searchBuild) {
- // if no build.properties, add all output folders
- Iterator<Entry<IPath, ArrayList<IPath>>> it = classpathMap.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<IPath, ArrayList<IPath>> entry = it.next();
- ArrayList<IPath> list = entry.getValue();
- ListIterator<IPath> li = list.listIterator();
- while (li.hasNext()) {
- addPath(result, project, li.next());
+ addPaths(paths, project, result);
}
}
+ return result;
}
+ // if no build.properties, add all output folders
+ classpathMap.values().forEach(l -> addPaths(l, project, result));
+ return result;
}
} catch (CoreException e) {
}
- return result.toArray(new IPath[result.size()]);
+ return Collections.emptySet();
+ }
+
+ private static void addPaths(List<IPath> paths, IProject project, Set<IPath> result) {
+ for (IPath path : paths) {
+ IPath resultPath = resolvePath(project, path);
+ if (resultPath != null) {
+ result.add(resultPath);
+ }
+ }
}
// looks for fragments for a plug-in. Then searches the fragments for a specific library. Will return paths which are absolute (required by runtime)
- private static IPath[] findLibraryFromFragments(String libName, IPluginModelBase model, boolean checkExcluded, Map<?, ?> plugins) {
+ private static List<IPath> findLibraryFromFragments(String libName, IPluginModelBase model, boolean checkExcluded, Set<String> plugins) {
IFragmentModel[] frags = PDEManager.findFragmentsFor(model);
for (int i = 0; i < frags.length; i++) {
- if (plugins != null && !plugins.containsKey(frags[i].getBundleDescription().getSymbolicName())) {
+ if (!plugins.contains(frags[i].getBundleDescription().getSymbolicName())) {
continue;
}
// look in project first
if (frags[i].getUnderlyingResource() != null) {
try {
IProject project = frags[i].getUnderlyingResource().getProject();
- Map<IPath, ArrayList<IPath>> classpathMap = getClasspathMap(project, checkExcluded, true);
- IFile file = PDEProject.getBuildProperties(project);
- IBuild build = null;
- if (file.exists()) {
- WorkspaceBuildModel bModel = new WorkspaceBuildModel(file);
- build = bModel.getBuild();
- }
- IPath[] paths = findLibrary(libName, project, classpathMap, build);
- if (paths.length > 0) {
+ Map<IPath, List<IPath>> classpathMap = getClasspathMap(project, checkExcluded, true);
+ IBuild build = getBuild(project);
+ List<IPath> paths = findLibrary(libName, project, classpathMap, build);
+ if (!paths.isEmpty()) {
return postfixFragmentAnnotation(paths);
}
} catch (JavaModelException e) {
- continue;
}
// if external plugin, look in child directories for library
} else {
@@ -411,62 +289,61 @@ public class ClasspathHelper {
file = new File(file, libName);
if (file.exists()) {
// Postfix fragment annotation for fragment path (fix bug 294211)
- return new IPath[] {new Path(file.getPath() + FRAGMENT_ANNOTATION)};
+ return List.of(new Path(file.getPath() + FRAGMENT_ANNOTATION));
}
}
}
}
- return new IPath[0];
+ return Collections.emptyList();
+ }
+
+ private static IBuild getBuild(IProject project) {
+ IFile file = PDEProject.getBuildProperties(project);
+ IPath location = file.getLocation();
+ boolean existsOnFileSystem = location != null && location.toFile().exists();
+ return existsOnFileSystem ? new WorkspaceBuildModel(file).getBuild() : null;
}
/*
* Postfixes the fragment annotation for the paths that we know come
* from fragments. This is needed to fix bug 294211.
*/
- private static IPath[] postfixFragmentAnnotation(IPath[] paths) {
- for (int i = 0; i < paths.length; i++) {
- paths[i] = new Path(paths[i].toString() + FRAGMENT_ANNOTATION);
- }
- return paths;
+ private static List<IPath> postfixFragmentAnnotation(List<IPath> paths) {
+ return paths.stream().map(p -> new Path(p + FRAGMENT_ANNOTATION)).collect(Collectors.toList());
}
- private static void addPath(ArrayList<IPath> result, IProject project, IPath path) {
- IPath resultPath = null;
+ private static IPath resolvePath(IProject project, IPath path) {
if (path.isAbsolute()) {
- resultPath = path;
+ return path;
} else if (path.segmentCount() > 0 && path.segment(0).equals(project.getName())) {
IContainer bundleRoot = PDEProject.getBundleRoot(project);
IPath rootPath = bundleRoot.getFullPath();
// make path relative to bundle root
path = path.makeRelativeTo(rootPath);
if (path.segmentCount() == 0) {
- resultPath = new Path(DOT);
- } else {
- IResource resource = bundleRoot.findMember(path);
- if (resource != null) {
- resultPath = path;
- }
+ return new Path(DOT);
+ }
+ if (bundleRoot.findMember(path) != null) {
+ return path;
}
}
-
- if (resultPath != null && !result.contains(resultPath)) {
- result.add(resultPath);
- }
+ return null;
}
- private static List<Path> getFoldersToExclude(IProject project, boolean checkExcluded) {
- ArrayList<Path> list = new ArrayList<>();
+ private static final Pattern BIN_EXCLUDES_SEPARATOR = Pattern.compile(","); //$NON-NLS-1$
+
+ private static Set<Path> getFoldersToExclude(IProject project, boolean checkExcluded) {
if (checkExcluded) {
IEclipsePreferences pref = new ProjectScope(project).getNode(PDECore.PLUGIN_ID);
if (pref != null) {
String binExcludes = pref.get(ICoreConstants.SELFHOSTING_BIN_EXCLUDES, ""); //$NON-NLS-1$
- StringTokenizer tokenizer = new StringTokenizer(binExcludes, ","); //$NON-NLS-1$
- while (tokenizer.hasMoreTokens()) {
- list.add(new Path(tokenizer.nextToken().trim()));
+ if (!binExcludes.isBlank()) {
+ Stream<String> elements = BIN_EXCLUDES_SEPARATOR.splitAsStream(binExcludes);
+ return elements.map(String::trim).map(Path::new).collect(Collectors.toUnmodifiableSet());
}
}
}
- return list;
+ return Collections.emptySet();
}
}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/MinimalState.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/MinimalState.java
index 60b9150940..73fa35adbf 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/MinimalState.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/MinimalState.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2015 IBM Corporation and others.
+ * Copyright (c) 2005, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -199,7 +199,7 @@ public class MinimalState {
private BundleDescription addBundle(File bundleLocation, long bundleId, Map<String, String> manifest)
throws CoreException {
// update for development mode
- TargetWeaver.weaveManifest(manifest);
+ TargetWeaver.weaveManifest(manifest, bundleLocation);
BundleDescription desc = addBundle(manifest, bundleLocation, bundleId);
if (desc != null && manifest != null && "true".equals(manifest.get(ICoreConstants.ECLIPSE_SYSTEM_BUNDLE))) { //$NON-NLS-1$
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/TargetWeaver.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/TargetWeaver.java
index c6b8d86ff6..1d6da8b291 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/TargetWeaver.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/TargetWeaver.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2012 IBM Corporation and others.
+ * Copyright (c) 2008, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -11,23 +11,28 @@
* Contributors:
* IBM Corporation - initial API and implementation
* EclipseSource Corporation - ongoing enhancements
+ * Hannes Wellmann - Bug 577541 - Clean up ClasspathHelper and TargetWeaver
+ * Hannes Wellmann - Bug 577543 - Only weave dev.properties for secondary launches if plug-in is from Running-Platform
*******************************************************************************/
package org.eclipse.pde.internal.core;
-import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
-import java.net.MalformedURLException;
+import java.io.InputStream;
import java.net.URL;
-import java.util.Iterator;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Properties;
-import java.util.Set;
+import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Platform;
+import org.eclipse.pde.core.plugin.IPluginBase;
import org.eclipse.pde.core.plugin.IPluginModelBase;
+import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
/**
* Supports target weaving (combining the target platform with workspace
@@ -36,14 +41,12 @@ import org.osgi.framework.Constants;
* @since 3.4
*/
public class TargetWeaver {
+ private TargetWeaver() { // static use only
+ }
/**
- * Whether the running platform is in development mode.
- */
- private static boolean fgIsDev = false;
-
- /**
- * Location of dev.properties
+ * Location of dev.properties, {@code null} if the Platform is not in
+ * development mode.
*/
private static String fgDevPropertiesURL = null;
@@ -56,8 +59,7 @@ public class TargetWeaver {
* Initializes system properties
*/
static {
- fgIsDev = Platform.inDevelopmentMode();
- if (fgIsDev) {
+ if (Platform.inDevelopmentMode()) {
fgDevPropertiesURL = System.getProperty("osgi.dev"); //$NON-NLS-1$
}
}
@@ -67,27 +69,23 @@ public class TargetWeaver {
*
* @return properties
*/
- protected static Properties getDevProperties() {
- if (fgIsDev) {
+ private static synchronized Properties getDevProperties() {
+ if (fgDevPropertiesURL != null) {
if (fgDevProperties == null) {
fgDevProperties = new Properties();
- if (fgDevPropertiesURL != null) {
- try {
- URL url = new URL(fgDevPropertiesURL);
- String path = url.getFile();
- if (path != null && path.length() > 0) {
- File file = new File(path);
- if (file.exists()) {
- try (BufferedInputStream stream = new BufferedInputStream(new FileInputStream(file));) {
- fgDevProperties.load(stream);
- } catch (IOException e) {
- PDECore.log(e);
- }
+ try {
+ URL url = new URL(fgDevPropertiesURL);
+ String path = url.getFile();
+ if (path != null && path.length() > 0) {
+ File file = new File(path);
+ if (file.exists()) {
+ try (InputStream stream = new FileInputStream(file)) {
+ fgDevProperties.load(stream);
}
}
- } catch (MalformedURLException e) {
- PDECore.log(e);
}
+ } catch (IOException e) {
+ PDECore.log(e);
}
}
return fgDevProperties;
@@ -100,17 +98,19 @@ public class TargetWeaver {
* mode from the launching workspace.
*
* @param manifest manifest to update
+ * @param bundleLocation the location of the Manifest's bundle
*/
- public static void weaveManifest(Map<String, String> manifest) {
- if (manifest != null && fgIsDev) {
+ public static void weaveManifest(Map<String, String> manifest, File bundleLocation) {
+ if (manifest != null && fgDevPropertiesURL != null) {
Properties properties = getDevProperties();
String id = manifest.get(Constants.BUNDLE_SYMBOLICNAME);
- if (id != null) {
+ String version = manifest.get(Constants.BUNDLE_VERSION);
+ if (id != null && version != null) {
int index = id.indexOf(';');
if (index != -1) {
id = id.substring(0, index);
}
- String property = properties.getProperty(id, null);
+ String property = getDevProperty(bundleLocation.toPath(), id, version, properties);
if (property != null) {
manifest.put(Constants.BUNDLE_CLASSPATH, property);
}
@@ -119,20 +119,21 @@ public class TargetWeaver {
}
/**
- * When launching a secondary runtime workbench, all projects already in dev mode
- * must continue in dev mode such that their class files are found.
+ * When launching a secondary runtime workbench, all projects already in dev
+ * mode that participate in that runtime must continue in dev mode such that
+ * their class files are found.
*
- * @param properties dev.properties
+ * @param launchDevProperties dev.properties
+ * @param launchedPlugins the bundles that participate in secondary runtime
*/
- public static void weaveDevProperties(Properties properties) {
- if (fgIsDev) {
- Properties devProperties = getDevProperties();
- if (devProperties != null) {
- Set<?> entries = devProperties.entrySet();
- Iterator<?> iterator = entries.iterator();
- while (iterator.hasNext()) {
- Entry<?, ?> entry = (Entry<?, ?>) iterator.next();
- properties.setProperty((String) entry.getKey(), (String) entry.getValue());
+ static void weaveRunningPlatformDevProperties(Properties launchDevProperties,
+ Iterable<IPluginModelBase> launchedPlugins) {
+ if (fgDevPropertiesURL != null) {
+ Properties platformDevProperties = getDevProperties();
+ for (IPluginModelBase launchedPlugin : launchedPlugins) {
+ String devCP = getDevProperty(launchedPlugin, platformDevProperties);
+ if (devCP != null) {
+ launchDevProperties.setProperty(launchedPlugin.getPluginBase().getId(), devCP);
}
}
}
@@ -147,10 +148,10 @@ public class TargetWeaver {
* @param libraryName the standard library name
* @return empty string or the standard library name
*/
- public static String getWeavedSourceLibraryName(IPluginModelBase model, String libraryName) {
+ static String getWeavedSourceLibraryName(IPluginModelBase model, String libraryName) {
// Note that if the host project has binary-linked libraries, these libraries appear in the dev.properties file with full path names,
// and the library name must be returned as-is.
- if (fgIsDev && !new File(libraryName).isAbsolute()) {
+ if (fgDevPropertiesURL != null && !new File(libraryName).isAbsolute()) {
Properties properties = getDevProperties();
String id = null;
if (model.getBundleDescription() != null) {
@@ -160,23 +161,12 @@ public class TargetWeaver {
* Workaround for bug 332112: Do not hack the source path for
* bundles that are not coming from the host workspace.
*
- * Since we don't actually know what the host workspace is and where
- * its projects are located, we have to guess:
- *
- * - If the bundle is not a folder, then it can't be a bundle from
- * the host workspace.
- *
- * - If the model has an underlying resource, then it's probably
- * from the local workspace.
- *
* The architectural bug is that this weaving takes place at the
* wrong level. It should already be done while the target platform
* resolves bundles from the host workspace.
*/
- if (id != null
- && !new File(model.getInstallLocation()).isFile()
- && model.getUnderlyingResource() == null) {
- String property = properties.getProperty(id, null);
+ if (id != null) {
+ String property = getDevProperty(model, properties);
if (property != null) {
return ""; //$NON-NLS-1$
}
@@ -184,4 +174,41 @@ public class TargetWeaver {
}
return libraryName;
}
+
+ private static String getDevProperty(IPluginModelBase plugin, Properties devProperties) {
+ // If it has an underlying resource, then it's from the local workspace.
+ if (plugin.getUnderlyingResource() == null) {
+ Path pluginLocation = Path.of(plugin.getInstallLocation());
+ IPluginBase pluginBase = plugin.getPluginBase();
+ return getDevProperty(pluginLocation, pluginBase.getId(), pluginBase.getVersion(), devProperties);
+ }
+ return null;
+ }
+
+ private static String getDevProperty(Path bundleLocation, String id, String version, Properties devProperties) {
+ String devCP = (String) devProperties.get(id);
+ return devCP != null && isBundleOfRunningPlatform(bundleLocation, id, version) ? devCP : null;
+ }
+
+ private static boolean isBundleOfRunningPlatform(Path pluginLocation, String id, String version) {
+ Bundle platformBundle = findRunningPlatformBundle(id, version);
+ if (platformBundle != null) {
+ try {
+ File bundleBaseFile = FileLocator.getBundleFile(platformBundle);
+ return Files.isSameFile(pluginLocation, bundleBaseFile.toPath());
+ } catch (IOException e) {
+ PDECore.logException(e);
+ }
+ }
+ return false;
+ }
+
+ private static Bundle findRunningPlatformBundle(String symbolicName, String versionStr) {
+ // Obtain all bundles of the running platform with given symbolicName
+ // and filter for version here. This is likely faster than specifying a
+ // range like: "[" + version + "," + version + "]"
+ Version version = Version.parseVersion(versionStr);
+ Bundle[] platformBundles = Platform.getBundles(symbolicName, null);
+ return Arrays.stream(platformBundles).filter(b -> b.getVersion().equals(version)).findAny().orElse(null);
+ }
}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/BundleErrorReporter.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/BundleErrorReporter.java
index ccb6eb6088..e8c8578e4b 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/BundleErrorReporter.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/BundleErrorReporter.java
@@ -136,8 +136,9 @@ public class BundleErrorReporter extends JarManifestErrorReporter {
// There was a problem creating the OSGi bundle description, possibly a bad header
try {
StateObjectFactory stateObjectFactory = Platform.getPlatformAdmin().getFactory();
- Map<String, String> manifest = ManifestUtils.loadManifest(new File(fModel.getInstallLocation()));
- TargetWeaver.weaveManifest(manifest);
+ File bundleLocation = new File(fModel.getInstallLocation());
+ Map<String, String> manifest = ManifestUtils.loadManifest(bundleLocation);
+ TargetWeaver.weaveManifest(manifest, bundleLocation);
Hashtable<String, String> dictionaryManifest = new Hashtable<>(manifest);
stateObjectFactory.createBundleDescription(null, dictionaryManifest, null, 1);
} catch (BundleException e) {
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/exports/FeatureExportOperation.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/exports/FeatureExportOperation.java
index 242d9b84ca..930fbaae06 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/exports/FeatureExportOperation.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/exports/FeatureExportOperation.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2020 IBM Corporation and others.
+ * Copyright (c) 2006, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -819,7 +819,7 @@ public class FeatureExportOperation extends Job {
fStateCopy.setPlatformProperties(state.getPlatformProperties());
}
- private String getDevProperties() {
+ private String getDevProperties() throws CoreException {
if (fDevProperties == null) {
fDevProperties = ClasspathHelper.getDevEntriesProperties(fBuildTempLocation + "/dev.properties", false); //$NON-NLS-1$
}
diff --git a/ui/org.eclipse.pde.launching/schema/osgiFrameworks.exsd b/ui/org.eclipse.pde.launching/schema/osgiFrameworks.exsd
index 3aaea1682d..b607c8928d 100644
--- a/ui/org.eclipse.pde.launching/schema/osgiFrameworks.exsd
+++ b/ui/org.eclipse.pde.launching/schema/osgiFrameworks.exsd
@@ -73,20 +73,20 @@ This extension point is used to register new OSGi frameworks. Each framework is
<attribute name="launcherDelegate" type="string" use="required">
<annotation>
<documentation>
- a launch configuration delegate to launch the OSGi framework. The value of this attribute is the fully qualified name of the Java class that extends &lt;code&gt;org.eclipse.pde.launcher.AbstractPDELaunchConfiguration&lt;/code&gt;.
+ a launch configuration delegate to launch the OSGi framework. The value of this attribute is the fully qualified name of the Java class that extends &lt;code&gt;org.eclipse.pde.launching.AbstractPDELaunchConfiguration&lt;/code&gt;.
</documentation>
<appInfo>
- <meta.attribute kind="java" basedOn="org.eclipse.pde.launcher.AbstractPDELaunchConfiguration"/>
+ <meta.attribute kind="java" basedOn="org.eclipse.pde.launching.AbstractPDELaunchConfiguration"/>
</appInfo>
</annotation>
</attribute>
<attribute name="initializer" type="string">
<annotation>
<documentation>
- initializes new OSGi Framework launch configurations with suitable defaults. The value of this attribute must be a fully-qualified name of a Java class that extends the default implementation &lt;code&gt;org.eclipse.pde.launcher.OSGiLaunchConfigurationInitializer&lt;/code&gt;. If not specified, the default initializer &lt;code&gt;org.eclipse.pde.launcher.OSGiLaunchConfigurationInitializer&lt;/code&gt; is instantiated.
+ initializes new OSGi Framework launch configurations with suitable defaults. The value of this attribute must be a fully-qualified name of a Java class that extends the default implementation &lt;code&gt;org.eclipse.pde.launching.OSGiLaunchConfigurationInitializer&lt;/code&gt;. If not specified, the default initializer &lt;code&gt;org.eclipse.pde.launching.OSGiLaunchConfigurationInitializer&lt;/code&gt; is instantiated.
</documentation>
<appInfo>
- <meta.attribute kind="java" basedOn="org.eclipse.pde.launcher.OSGiLaunchConfigurationInitializer"/>
+ <meta.attribute kind="java" basedOn="org.eclipse.pde.launching.OSGiLaunchConfigurationInitializer"/>
</appInfo>
</annotation>
</attribute>
@@ -116,10 +116,10 @@ The following is an example of the extension point:
&lt;extension
point=&quot;org.eclipse.pde.launching.osgiFrameworks&quot;&gt;
&lt;framework
- launcherDelegate=&quot;org.eclipse.pde.launcher.EquinoxLaunchConfiguration&quot;
+ launcherDelegate=&quot;org.eclipse.pde.launching.EquinoxLaunchConfiguration&quot;
id=&quot;org.eclipse.pde.ui.EquinoxFramework&quot;
name=&quot;%Equinox.shortcut.label&quot;
- initializer=&quot;org.eclipse.pde.internal.launcher.EquinoxInitializer&quot;/&gt;
+ initializer=&quot;org.eclipse.pde.internal.launching.launcher.EquinoxInitializer&quot;/&gt;
&lt;/extension&gt;
&lt;/pre&gt;
</documentation>
@@ -131,10 +131,10 @@ The following is an example of the extension point:
</appInfo>
<documentation>
&lt;p&gt;
-The value of the attribute &lt;code&gt;launcherDelegate&lt;/code&gt; must be a fully qualified name of a Java class that extends &lt;code&gt;org.eclipse.pde.launcher.AbstractPDELaunchConfiguration&lt;/code&gt;. If the launcher is to provide its own source lookup order, then the method &lt;code&gt;setDefaultSourceLocator&lt;/code&gt; should be overridden.
+The value of the attribute &lt;code&gt;launcherDelegate&lt;/code&gt; must be a fully qualified name of a Java class that extends &lt;code&gt;org.eclipse.pde.launching.AbstractPDELaunchConfiguration&lt;/code&gt;. If the launcher is to provide its own source lookup order, then the method &lt;code&gt;setDefaultSourceLocator&lt;/code&gt; should be overridden.
&lt;/p&gt;
&lt;p&gt;
-The value of the attribute &lt;code&gt;initializer&lt;/code&gt; must be a fully qualified name of a Java class that extends &lt;code&gt;org.eclipse.launcher.OSGiLaunchConfigurationInitializer&lt;/code&gt;.
+The value of the attribute &lt;code&gt;initializer&lt;/code&gt; must be a fully qualified name of a Java class that extends &lt;code&gt;org.eclipse.pde.launching.OSGiLaunchConfigurationInitializer&lt;/code&gt;.
&lt;/p&gt;
</documentation>
</annotation>
diff --git a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchListener.java b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchListener.java
index b403a3965a..af440ee7a9 100644
--- a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchListener.java
+++ b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchListener.java
@@ -160,6 +160,9 @@ public class LaunchListener implements ILaunchListener, IDebugEventSetListener {
* @since 3.4
*/
public static File getMostRecentLogFile(ILaunchConfiguration configuration) throws CoreException {
+ if (configuration == null) {
+ return null;
+ }
File latest = null;
String workspace = LaunchArgumentsHelper.getWorkspaceLocation(configuration);
if (workspace.length() > 0) {
diff --git a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/JUnitLaunchConfigurationDelegate.java b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/JUnitLaunchConfigurationDelegate.java
index 3b554ae094..ccbf7b50e2 100644
--- a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/JUnitLaunchConfigurationDelegate.java
+++ b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/JUnitLaunchConfigurationDelegate.java
@@ -154,7 +154,7 @@ public class JUnitLaunchConfigurationDelegate extends org.eclipse.jdt.junit.laun
programArgs.add("-dev"); //$NON-NLS-1$
IJavaProject javaProject = getJavaProject(configuration);
- Properties devProperties = ClasspathHelper.getDevEntriesProperties(fAllBundles);
+ Properties devProperties = ClasspathHelper.getDevEntriesProperties(fAllBundles, true);
if (javaProject != null) {
// source-folders of type "test" are omitted in the previous search so the need to be added here as they are part of the test but not part of the build.properties
Arrays.stream(javaProject.getRawClasspath())//
@@ -162,12 +162,7 @@ public class JUnitLaunchConfigurationDelegate extends org.eclipse.jdt.junit.laun
.filter(IClasspathEntry::isTest)//
.filter(entry -> entry.getOutputLocation() != null).forEach(entry -> {
IPath relativePath = entry.getOutputLocation().removeFirstSegments(1).makeRelative();
- String currentProperty = devProperties.getProperty(testPluginId);
- if (currentProperty == null) {
- devProperties.setProperty(testPluginId, relativePath.toString());
- } else {
- devProperties.setProperty(testPluginId, currentProperty + "," + relativePath.toString()); //$NON-NLS-1$
- }
+ devProperties.merge(testPluginId, relativePath.toString(), (vOld, vNew) -> vOld + "," + vNew); //$NON-NLS-1$
});
}
programArgs.add(ClasspathHelper.writeDevEntries(getConfigurationDirectory(configuration).toString() + "/dev.properties", devProperties)); //$NON-NLS-1$
diff --git a/ui/org.eclipse.pde.spy.context/.classpath b/ui/org.eclipse.pde.spy.context/.classpath
new file mode 100644
index 0000000000..e801ebfb46
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/ui/org.eclipse.pde.spy.context/.project b/ui/org.eclipse.pde.spy.context/.project
new file mode 100644
index 0000000000..7ee455081b
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.pde.spy.context</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/ui/org.eclipse.pde.spy.context/.settings/org.eclipse.jdt.core.prefs b/ui/org.eclipse.pde.spy.context/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..c9545f06a4
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/ui/org.eclipse.pde.spy.context/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.spy.context/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..f65cb6c88a
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/META-INF/MANIFEST.MF
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %name
+Bundle-SymbolicName: org.eclipse.pde.spy.context;singleton:=true
+Bundle-Version: 1.0.100.qualifier
+Bundle-Vendor: %provider-name
+Automatic-Module-Name: org.eclipse.pde.spy.context
+Bundle-RequiredExecutionEnvironment: JavaSE-11
+Require-Bundle: org.eclipse.jface;bundle-version="3.9.0",
+ org.eclipse.e4.core.contexts;bundle-version="1.9.100",
+ org.eclipse.e4.ui.model.workbench,
+ org.eclipse.core.runtime;bundle-version="3.9.0",
+ org.eclipse.e4.ui.workbench;bundle-version="1.0.0",
+ org.eclipse.e4.ui.di;bundle-version="1.0.0",
+ org.eclipse.e4.ui.services;bundle-version="1.0.0",
+ org.eclipse.e4.core.di;bundle-version="1.3.0",
+ org.eclipse.e4.core.services;bundle-version="1.1.0",
+ org.eclipse.e4.ui.workbench.swt,
+ org.eclipse.pde.spy.core;bundle-version="1.0.0"
+Bundle-ActivationPolicy: lazy
+Import-Package: javax.annotation;version="1.2.0",
+ javax.inject;version="1.0.0"
+Bundle-Localization: plugin
+Export-Package: org.eclipse.pde.spy.context
+
diff --git a/ui/org.eclipse.pde.spy.context/README.md b/ui/org.eclipse.pde.spy.context/README.md
new file mode 100644
index 0000000000..ff41fc8394
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/README.md
@@ -0,0 +1,13 @@
+org.eclipse.pde.spy.context
+===================================
+
+
+For more information, refer to the [Eclipse e4 wiki page] [1].
+
+License
+-------
+
+[Eclipse Public License (EPL) v1.0][2]
+
+[1]: http://www.eclipse.org/e4/
+[2]: http://wiki.eclipse.org/EPL
diff --git a/ui/org.eclipse.pde.spy.context/about.html b/ui/org.eclipse.pde.spy.context/about.html
new file mode 100644
index 0000000000..824948673d
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 3, 2009</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/ui/org.eclipse.pde.spy.context/build.properties b/ui/org.eclipse.pde.spy.context/build.properties
new file mode 100644
index 0000000000..fd1517abb7
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/build.properties
@@ -0,0 +1,9 @@
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ about.html,\
+ icons/,\
+ plugin.properties
+source.. = src/
+src.includes = about.html
diff --git a/ui/org.eclipse.pde.spy.context/icons/annotation_obj.png b/ui/org.eclipse.pde.spy.context/icons/annotation_obj.png
new file mode 100644
index 0000000000..828da7aa31
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/annotation_obj.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/annotation_obj@2x.png b/ui/org.eclipse.pde.spy.context/icons/annotation_obj@2x.png
new file mode 100644
index 0000000000..a53f05ca69
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/annotation_obj@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/collapseall.png b/ui/org.eclipse.pde.spy.context/icons/collapseall.png
new file mode 100644
index 0000000000..92cc57892b
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/collapseall.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/collapseall@2x.png b/ui/org.eclipse.pde.spy.context/icons/collapseall@2x.png
new file mode 100644
index 0000000000..8769e04da0
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/collapseall@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/contextfunction.png b/ui/org.eclipse.pde.spy.context/icons/contextfunction.png
new file mode 100644
index 0000000000..7d9f913b4c
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/contextfunction.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/contextfunction@2x.png b/ui/org.eclipse.pde.spy.context/icons/contextfunction@2x.png
new file mode 100644
index 0000000000..118737c3db
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/contextfunction@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/expandall.png b/ui/org.eclipse.pde.spy.context/icons/expandall.png
new file mode 100644
index 0000000000..08cb513f1c
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/expandall.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/expandall@2x.png b/ui/org.eclipse.pde.spy.context/icons/expandall@2x.png
new file mode 100644
index 0000000000..fcbf24f455
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/expandall@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/field_public_obj.png b/ui/org.eclipse.pde.spy.context/icons/field_public_obj.png
new file mode 100644
index 0000000000..2b3e8e51b3
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/field_public_obj.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/field_public_obj@2x.png b/ui/org.eclipse.pde.spy.context/icons/field_public_obj@2x.png
new file mode 100644
index 0000000000..e2695fae0f
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/field_public_obj@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/inher_co.png b/ui/org.eclipse.pde.spy.context/icons/inher_co.png
new file mode 100644
index 0000000000..a33523364e
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/inher_co.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/inher_co@2x.png b/ui/org.eclipse.pde.spy.context/icons/inher_co@2x.png
new file mode 100644
index 0000000000..fb682c09d4
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/inher_co@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/letter-l-icon.png b/ui/org.eclipse.pde.spy.context/icons/letter-l-icon.png
new file mode 100644
index 0000000000..115dcefc3a
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/letter-l-icon.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/letter-l-icon@2x.png b/ui/org.eclipse.pde.spy.context/icons/letter-l-icon@2x.png
new file mode 100644
index 0000000000..37868fc9c3
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/letter-l-icon@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/methpub_obj.png b/ui/org.eclipse.pde.spy.context/icons/methpub_obj.png
new file mode 100644
index 0000000000..a9be929f67
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/methpub_obj.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/methpub_obj@2x.png b/ui/org.eclipse.pde.spy.context/icons/methpub_obj@2x.png
new file mode 100644
index 0000000000..fefe4e71a5
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/methpub_obj@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/refresh.png b/ui/org.eclipse.pde.spy.context/icons/refresh.png
new file mode 100644
index 0000000000..bee8fe7a32
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/refresh.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/refresh@2x.png b/ui/org.eclipse.pde.spy.context/icons/refresh@2x.png
new file mode 100644
index 0000000000..89d4d48575
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/refresh@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/splash.png b/ui/org.eclipse.pde.spy.context/icons/splash.png
new file mode 100644
index 0000000000..ba755f9e35
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/splash.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/valueincontext.png b/ui/org.eclipse.pde.spy.context/icons/valueincontext.png
new file mode 100644
index 0000000000..533cfcc3fd
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/valueincontext.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/icons/valueincontext@2x.png b/ui/org.eclipse.pde.spy.context/icons/valueincontext@2x.png
new file mode 100644
index 0000000000..de9d23daa5
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/icons/valueincontext@2x.png
Binary files differ
diff --git a/ui/org.eclipse.pde.spy.context/plugin.properties b/ui/org.eclipse.pde.spy.context/plugin.properties
new file mode 100644
index 0000000000..c8536c2a43
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/plugin.properties
@@ -0,0 +1,18 @@
+###############################################################################
+# Copyright (c) 2021 OPCoach.
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+#
+# Contributors:
+# Olivier Prouvost - initial API and implementation
+###############################################################################
+#
+#
+name = Context Spy
+description = Context Spy to understand what is behind the scene of injection
+provider-name = Eclipse.org
diff --git a/ui/org.eclipse.pde.spy.context/plugin.xml b/ui/org.eclipse.pde.spy.context/plugin.xml
new file mode 100644
index 0000000000..3558708fb0
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/plugin.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin>
+ <extension
+ point="org.eclipse.pde.spy.core.spyPart">
+ <spyPart
+ description="%description"
+ icon="$nl$/icons/annotation_obj.png"
+ name="%name"
+ part="org.eclipse.pde.spy.context.ContextSpyPart"
+ shortcut="M2+M3+F10">
+ </spyPart>
+ </extension>
+</plugin>
diff --git a/ui/org.eclipse.pde.spy.context/pom.xml b/ui/org.eclipse.pde.spy.context/pom.xml
new file mode 100644
index 0000000000..d39cd00296
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/pom.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2012, 2019 Eclipse Foundation and others.
+ All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Distribution License v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/org/documents/edl-v10.php
+
+ Contributors:
+ Igor Fedorenko - initial implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>eclipse.pde.ui</artifactId>
+ <groupId>eclipse.pde.ui</groupId>
+ <version>4.23.0-SNAPSHOT</version>
+ <relativePath>../../</relativePath>
+ </parent>
+
+ <properties>
+ <skipAPIAnalysis>true</skipAPIAnalysis>
+ </properties>
+
+
+ <groupId>eclipse.pde.ui</groupId>
+ <artifactId>org.eclipse.pde.spy.context</artifactId>
+ <version>1.0.100-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+</project>
diff --git a/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextDataFilter.java b/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextDataFilter.java
new file mode 100644
index 0000000000..9f922be266
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextDataFilter.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2014 OPCoach.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * OPCoach - initial API and implementation for bug #437478
+ *******************************************************************************/
+package org.eclipse.pde.internal.spy.context;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Creatable;
+import org.eclipse.e4.core.internal.contexts.Computation;
+import org.eclipse.e4.core.internal.contexts.EclipseContext;
+import org.eclipse.e4.core.services.log.Logger;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+
+@SuppressWarnings("restriction")
+@Creatable
+@Singleton
+public class ContextDataFilter extends ViewerFilter {
+
+ @Inject
+ Logger log;
+
+ private String pattern;
+
+ // Implements the filter for the data table content
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if ((element == ContextDataProvider.LOCAL_VALUE_NODE)
+ || (element == ContextDataProvider.INHERITED_INJECTED_VALUE_NODE))
+ return true;
+
+ // Must only select objects matching the pattern or objects under a kept
+ // node (to see where it is injected)
+ TreeViewer tv = (TreeViewer) viewer;
+ ContextDataProvider lpkey = (ContextDataProvider) tv.getLabelProvider(0);
+ ContextDataProvider lpval = (ContextDataProvider) tv.getLabelProvider(1);
+
+ // If the text matches in one of the column, must keep it...
+ String skey = lpkey.getText(element);
+ String sval = lpval.getText(element);
+
+ // Must also keep the listener elements if the parent is selected ->
+ // Must compute parent keys
+ String sparentkey = lpkey.getText(parentElement);
+ String sparentval = lpval.getText(parentElement);
+
+ Set<Computation> listeners = lpkey.getListeners(parentElement);
+ boolean mustKeepParent = (matchText(sparentkey) || matchText(sparentval)) && (listeners != null)
+ && (listeners.size() > 0);
+ boolean mustKeepElement = matchText(skey) || matchText(sval);
+
+ return mustKeepElement || (!mustKeepElement && mustKeepParent);
+
+ }
+
+ /** Set the pattern and use it as lowercase */
+ public void setPattern(String newPattern) {
+ if ((newPattern == null) || (newPattern.length() == 0))
+ pattern = null;
+ else
+ pattern = newPattern.toLowerCase();
+ }
+
+ /**
+ * This method search for an object and check if it contains the text or a
+ * pattern matching this text
+ */
+ public boolean containsText(IEclipseContext ctx) {
+ // It is useless to store the values in a map, because context changes
+ // everytime and it should be tracked.
+ Collection<String> values = computeValues(ctx);
+
+ // Search if string is just in one of the values... manage ignore case
+ // and contain...
+ boolean found = false;
+ for (String s : values) {
+ if (matchText(s)) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+ }
+
+ public boolean matchText(String text) {
+ return ((text == null) || (pattern == null)) ? false : text.toLowerCase().contains(pattern);
+ }
+
+ /**
+ * Extract all string values in context
+ *
+ * @param ctx
+ * @return
+ */
+ private Collection<String> computeValues(IEclipseContext ctx) {
+ Collection<String> result = new ArrayList<String>();
+ if (ctx instanceof EclipseContext) {
+ // Search for all strings in this context (values and context
+ // function)
+
+ EclipseContext currentContext = (EclipseContext) ctx;
+ extractStringsFromMap(currentContext.localData(), result);
+
+ // Search also in context functions
+ extractStringsFromMap(currentContext.localContextFunction(), result);
+
+ // Search for the inherited values injected using this context but
+ // defined in
+ // parent
+ // Keep only the names that are not already displayed in local
+ // values
+ Collection<String> localKeys = currentContext.localData().keySet();
+ Collection<String> localContextFunctionsKeys = currentContext.localContextFunction().keySet();
+
+ if (currentContext.getRawListenerNames() != null) {
+ for (String name : currentContext.getRawListenerNames()) {
+ if (!localKeys.contains(name) && !localContextFunctionsKeys.contains(name))
+ result.add(name);
+ }
+ }
+
+ } else {
+ log.warn("Warning : the received EclipseContext has not the expected type. It is a : "
+ + ctx.getClass().toString());
+ }
+
+ return result;
+ }
+
+ /**
+ *
+ * @param map
+ * the map to extract the strings (keys and values)
+ * @param result
+ * the result to fill with strings
+ */
+ private void extractStringsFromMap(Map<String, Object> map, Collection<String> result) {
+ for (Map.Entry<String, Object> entry : map.entrySet()) {
+ result.add(entry.getKey().toString());
+ Object value = entry.getValue();
+ if (value != null) {
+ result.add(value.toString());
+ }
+ }
+ }
+
+}
diff --git a/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextDataPart.java b/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextDataPart.java
new file mode 100644
index 0000000000..868ca355a5
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextDataPart.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ * Copyright (c) 2013 OPCoach.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * OPCoach - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.internal.spy.context;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.core.internal.contexts.EclipseContext;
+import org.eclipse.e4.ui.di.Focus;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+
+/**
+ * This part listen to selection, and if it is an EclipseContext, it displays
+ * its information It is used in the integrated ContextSpyPart and (in the
+ * future) it could be used outside to display the context of focused part for
+ * instance
+ */
+@SuppressWarnings("restriction")
+public class ContextDataPart {
+ private TreeViewer contextDataViewer;
+
+ private ContextDataProvider dataProvider;
+
+ private ContextEntryComparator comparator;
+
+ /**
+ * Create contents of the view part.
+ */
+ @PostConstruct
+ public void createControls(Composite parent, IEclipseContext ctx) {
+
+ parent.setLayout(new GridLayout(1, false));
+
+ // TreeViewer on the top
+ contextDataViewer = new TreeViewer(parent);
+ dataProvider = ContextInjectionFactory.make(ContextDataProvider.class, ctx);
+ contextDataViewer.setContentProvider(dataProvider);
+ contextDataViewer.setLabelProvider(dataProvider);
+ // contextContentTv.setSorter(new ViewerSorter());
+
+ final Tree cTree = contextDataViewer.getTree();
+ cTree.setHeaderVisible(true);
+ cTree.setLinesVisible(true);
+ cTree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ // tv.setInput(a);
+ contextDataViewer.setInput("Foo"); // getElements starts alone
+
+ // Add columns in the tree
+ // Create the first column for the key
+ TreeViewerColumn keyCol = new TreeViewerColumn(contextDataViewer, SWT.NONE);
+ keyCol.getColumn().setWidth(400);
+ keyCol.getColumn().setText("Key");
+ ContextDataProvider keyLabelProvider = ContextInjectionFactory.make(ContextDataProvider.class, ctx);
+ keyLabelProvider.setDisplayKey(true);
+ keyCol.setLabelProvider(keyLabelProvider);
+ keyCol.getColumn().setToolTipText("Key in context");
+ keyCol.getColumn().addSelectionListener(
+ getHeaderSelectionAdapter(contextDataViewer, keyCol.getColumn(), 0, keyLabelProvider));
+
+ comparator = new ContextEntryComparator(0, keyLabelProvider);
+ contextDataViewer.setComparator(comparator);
+
+ // Create the second column for the value
+ TreeViewerColumn valueCol = new TreeViewerColumn(contextDataViewer, SWT.NONE);
+ valueCol.getColumn().setWidth(600);
+ valueCol.getColumn().setText("Value");
+ ContextDataProvider valueLabelProvider = ContextInjectionFactory.make(ContextDataProvider.class, ctx);
+ valueCol.setLabelProvider(dataProvider);
+ valueCol.getColumn().addSelectionListener(
+ getHeaderSelectionAdapter(contextDataViewer, valueCol.getColumn(), 1, valueLabelProvider));
+
+ // Open all the tree
+ contextDataViewer.expandAll();
+
+ ColumnViewerToolTipSupport.enableFor(contextDataViewer);
+
+ }
+
+ @PreDestroy
+ public void dispose() {
+ }
+
+ @Focus
+ public void setFocus() {
+ contextDataViewer.getControl().setFocus();
+ }
+
+ @Inject
+ @Optional
+ public void listenToContext(@Named(IServiceConstants.ACTIVE_SELECTION) EclipseContext ctx) {
+ // Must check if dataviewer is created or not (when we reopen the window
+ // @postconstruct has not been called yet)
+ if ((ctx == null) || (contextDataViewer == null)) {
+ return;
+ }
+ contextDataViewer.setInput(ctx);
+ contextDataViewer.expandToLevel(2);
+ }
+
+ /**
+ * An entry comparator for the table, dealing with column index, keys and
+ * values
+ */
+ public class ContextEntryComparator extends ViewerComparator {
+ private int columnIndex;
+ private int direction;
+ private ILabelProvider labelProvider;
+
+ public ContextEntryComparator(int columnIndex, ILabelProvider defaultLabelProvider) {
+ this.columnIndex = columnIndex;
+ direction = SWT.UP;
+ labelProvider = defaultLabelProvider;
+ }
+
+ public int getDirection() {
+ return direction;
+ }
+
+ /** Called when click on table header, reverse order */
+ public void setColumn(int column) {
+ if (column == columnIndex) {
+ // Same column as last sort; toggle the direction
+ direction = (direction == SWT.UP) ? SWT.DOWN : SWT.UP;
+ } else {
+ // New column; do a descending sort
+ columnIndex = column;
+ direction = SWT.DOWN;
+ }
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ // For root elements at first level, we keep Local before Inherited
+ if ((e1 == ContextDataProvider.LOCAL_VALUE_NODE) || (e2 == ContextDataProvider.LOCAL_VALUE_NODE))
+ return -1;
+
+ // Now can compare the text from label provider.
+ String lp1 = labelProvider.getText(e1);
+ String lp2 = labelProvider.getText(e2);
+ String s1 = lp1 == null ? "" : lp1.toLowerCase();
+ String s2 = lp2 == null ? "" : lp2.toLowerCase();
+ int rc = s1.compareTo(s2);
+ // If descending order, flip the direction
+ return (direction == SWT.DOWN) ? -rc : rc;
+ }
+
+ public void setLabelProvider(ILabelProvider textProvider) {
+ labelProvider = textProvider;
+ }
+
+ }
+
+ private SelectionAdapter getHeaderSelectionAdapter(final TreeViewer viewer, final TreeColumn column,
+ final int columnIndex, final ILabelProvider textProvider) {
+ SelectionAdapter selectionAdapter = new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ viewer.setComparator(comparator);
+ comparator.setColumn(columnIndex);
+ comparator.setLabelProvider(textProvider);
+ viewer.getTree().setSortDirection(comparator.getDirection());
+ viewer.getTree().setSortColumn(column);
+ viewer.refresh();
+ }
+ };
+ return selectionAdapter;
+ }
+
+ public void refresh(boolean refreshLabel) {
+ contextDataViewer.refresh(refreshLabel);
+ }
+
+ private static final ViewerFilter[] NO_FILTER = new ViewerFilter[0];
+
+ public void setFilter(ViewerFilter filter) {
+
+ contextDataViewer.setFilters((filter == null) ? NO_FILTER : new ViewerFilter[] { filter });
+ }
+
+}
diff --git a/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextDataProvider.java b/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextDataProvider.java
new file mode 100644
index 0000000000..0913d26931
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextDataProvider.java
@@ -0,0 +1,366 @@
+/*******************************************************************************
+ * Copyright (c) 2013 OPCoach.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * OPCoach - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.internal.spy.context;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import org.eclipse.e4.core.internal.contexts.Computation;
+import org.eclipse.e4.core.internal.contexts.EclipseContext;
+import org.eclipse.jface.resource.FontRegistry;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * The column Label and content Provider used to display information in context
+ * data TreeViewer. Two instances for label provider are created : one for key,
+ * one for values
+ *
+ * @see ContextDataPart
+ */
+@SuppressWarnings("restriction")
+public class ContextDataProvider extends ColumnLabelProvider implements ITreeContentProvider {
+
+ private static final String NO_VALUE_COULD_BE_COMPUTED = "No value could be yet computed";
+ private static final Color COLOR_IF_FOUND = Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
+ private static final Color COLOR_IF_NOT_COMPUTED = Display.getCurrent().getSystemColor(SWT.COLOR_MAGENTA);
+ private static final Object[] EMPTY_RESULT = new Object[0];
+ static final String LOCAL_VALUE_NODE = "Local values managed by this context";
+ static final String INHERITED_INJECTED_VALUE_NODE = "Inherited values injected or updated using this context";
+
+ private static final String NO_VALUES_FOUND = "No values found";
+ private static final String UPDATED_IN_CLASS = "Updated in class :";
+ private static final String INJECTED_IN_FIELD = "Injected in field :";
+ private static final String INJECTED_IN_METHOD = "Injected in method :";
+
+ // Image keys constants
+ private static final String PUBLIC_METHOD_IMG_KEY = "icons/methpub_obj.png";
+ private static final String PUBLIC_FIELD_IMG_KEY = "icons/field_public_obj.png";
+ private static final String VALUE_IN_CONTEXT_IMG_KEY = "icons/valueincontext.png";
+ private static final String INHERITED_VARIABLE_IMG_KEY = "icons/inher_co.png";
+ private static final String LOCAL_VARIABLE_IMG_KEY = "icons/letter-l-icon.png";
+ private static final String CONTEXT_FUNCTION_IMG_KEY = "icons/contextfunction.png";
+ private static final String INJECT_IMG_KEY = "icons/annotation_obj.png";
+
+ private ImageRegistry imgReg;
+
+ @Inject
+ private ContextDataFilter contextFilter;
+
+ /** Store the selected context (initialized in inputChanged) */
+ private static EclipseContext selectedContext;
+
+ private Font boldFont;
+
+ private boolean displayKey = false;
+
+ @Inject
+ public ContextDataProvider() {
+ super();
+ initFonts();
+ initializeImageRegistry();
+ }
+
+ @Override
+ public void dispose() {
+ selectedContext = null;
+ imgReg = null;
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ selectedContext = (newInput instanceof EclipseContext) ? (EclipseContext) newInput : null;
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ return new String[] { LOCAL_VALUE_NODE, INHERITED_INJECTED_VALUE_NODE };
+ }
+
+ @Override
+ public Object[] getChildren(Object inputElement) {
+ if (selectedContext == null)
+ return EMPTY_RESULT;
+
+ if (inputElement == LOCAL_VALUE_NODE) {
+ Collection<Object> result = new ArrayList<Object>();
+
+ result.addAll(selectedContext.localData().entrySet());
+
+ // For context function, we have to compute the value (if possible),
+ // and display it as a standard value
+ Map<String, Object> cfValues = new HashMap<String, Object>();
+ for (String key : selectedContext.localContextFunction().keySet())
+ try {
+ cfValues.put(key, selectedContext.get(key));
+ } catch (Exception e) {
+ cfValues.put(key, NO_VALUE_COULD_BE_COMPUTED + " (Exception : " + e.getClass().getName() + ")");
+ }
+ result.addAll(cfValues.entrySet());
+ return result.toArray();
+
+ } else if (inputElement == INHERITED_INJECTED_VALUE_NODE) {
+ // Search for all values injected using this context but defined in
+ // parent
+ Collection<Object> result = new ArrayList<Object>();
+
+ // Keep only the names that are not already displayed in local
+ // values
+ Collection<String> localKeys = selectedContext.localData().keySet();
+ Collection<String> localContextFunctionsKeys = selectedContext.localContextFunction().keySet();
+
+ if (selectedContext.getRawListenerNames() != null) {
+ for (String name : selectedContext.getRawListenerNames()) {
+ if (!localKeys.contains(name) && !localContextFunctionsKeys.contains(name))
+ result.add(name);
+ }
+ }
+ return result.size() == 0 ? new String[] { NO_VALUES_FOUND } : result.toArray();
+
+ } else if (inputElement instanceof Map.Entry) {
+ Set<Computation> listeners = getListeners(inputElement);
+ return (listeners == null) ? null : listeners.toArray();
+ } else if (inputElement instanceof String) {
+ // This is the name of a raw listener in the inherited injected
+ // value part
+ return selectedContext.getListeners((String) inputElement).toArray();
+ }
+
+ return EMPTY_RESULT;
+ }
+
+ public void setDisplayKey(boolean k) {
+ displayKey = k;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public String getText(Object element) {
+ if (selectedContext == null)
+ return null;
+
+ if (element instanceof Map.Entry) {
+ Map.Entry<String, Object> mapEntry = (Map.Entry<String, Object>) element;
+ Object o = displayKey ? mapEntry.getKey() : mapEntry.getValue();
+ return (o == null) ? "null" : o.toString();
+ } else if (element instanceof Computation) {
+ // For a computation : display field or method in key column and the
+ // value in value
+ String txt = super.getText(element);
+ if (displayKey) {
+ if (txt.contains("#"))
+ return INJECTED_IN_METHOD;
+ else if (txt.contains("@"))
+ return UPDATED_IN_CLASS;
+ else
+ return INJECTED_IN_FIELD;
+ } else
+ return txt;
+ }
+
+ return displayKey ? super.getText(element) : null;
+ }
+
+ @Override
+ public Color getForeground(Object element) {
+ // Return magenta color if the value could not be yet computed (for
+ // context functions)
+ String s = getText(element);
+ if ((s != null) && s.startsWith(NO_VALUE_COULD_BE_COMPUTED))
+ return COLOR_IF_NOT_COMPUTED;
+
+ // Return blue color if the string matches the search
+ return (contextFilter.matchText(s)) ? COLOR_IF_FOUND : null;
+ }
+
+ /** Get the bold font for keys that are computed with ContextFunction */
+ @Override
+ public Font getFont(Object element) {
+ return (element == LOCAL_VALUE_NODE || element == INHERITED_INJECTED_VALUE_NODE) ? boldFont : null;
+
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ if (!displayKey) // No image in value column, only in key column
+ return null;
+
+ if (element == LOCAL_VALUE_NODE) {
+ return selectedContext == null ? null : imgReg.get(LOCAL_VARIABLE_IMG_KEY);
+
+ } else if (element == INHERITED_INJECTED_VALUE_NODE) {
+ return selectedContext == null ? null : imgReg.get(INHERITED_VARIABLE_IMG_KEY);
+
+ } else if (element instanceof Computation) {
+ // For a computation : display field, method or class in key column
+ // and
+ // value in value column
+ String txt = super.getText(element);
+
+ if (txt.contains("#"))
+ return imgReg.get(PUBLIC_METHOD_IMG_KEY);
+ else if (txt.contains("@"))
+ return imgReg.get(CONTEXT_FUNCTION_IMG_KEY);
+ else
+ return imgReg.get(PUBLIC_FIELD_IMG_KEY);
+
+ } else if (element instanceof Map.Entry) {
+ if (isAContextKeyFunction(element))
+ return imgReg.get(CONTEXT_FUNCTION_IMG_KEY);
+ else {
+ // It is a value. If it is injected somewhere, display the
+ // inject image
+ return hasChildren(element) ? imgReg.get(INJECT_IMG_KEY) : imgReg.get(VALUE_IN_CONTEXT_IMG_KEY);
+ }
+
+ }
+
+ return imgReg.get(INJECT_IMG_KEY);
+
+ }
+
+ @Override
+ public String getToolTipText(Object element) {
+ if (element == LOCAL_VALUE_NODE) {
+ return "This part contains values set in this context and then injected here or in children\n\n"
+ + "If the value is injected using this context, you can expand the node to see where\n\n"
+ + "If the value is injected using a child context you can find it in the second part for this child ";
+ } else if (element == INHERITED_INJECTED_VALUE_NODE) {
+ return "This part contains the values injected or updated using this context, but initialized in a parent context\n\n"
+ + "Expand nodes to see where values are injected or updated";
+ } else if (isAContextKeyFunction(element)) {
+ String key = (String) ((Map.Entry<?, ?>) element).getKey();
+ String fname = selectedContext.localContextFunction().get(key).getClass().getCanonicalName();
+
+ return "This value is created by the Context Function : " + fname;
+ } else {
+ if (hasChildren(element))
+ return "Expand this node to see where this value is injected or updated";
+ else {
+ if (element instanceof Map.Entry)
+ return "This value is set here but not injected using this context (look in children context)";
+ }
+
+ }
+
+ return super.getToolTipText(element);
+ }
+
+ @Override
+ public Image getToolTipImage(Object object) {
+ return getImage(object);
+ }
+
+ @Override
+ public int getToolTipStyle(Object object) {
+ return SWT.SHADOW_OUT;
+ }
+
+ /**
+ * Compute it the current entry in context is a context function
+ *
+ * @param element
+ * @return true if element is a context function
+ */
+ @SuppressWarnings("unchecked")
+ boolean isAContextKeyFunction(Object element) {
+ if (selectedContext != null && element instanceof Map.Entry) {
+ // Just check if key in element is a key in the map of context
+ // functions.
+ Map.Entry<String, Object> mapEntry = (Map.Entry<String, Object>) element;
+ return (selectedContext.localContextFunction().containsKey(mapEntry.getKey()));
+ }
+ return false;
+
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ if (element == LOCAL_VALUE_NODE || element == INHERITED_INJECTED_VALUE_NODE)
+ return null;
+
+ // Not computed
+ return null;
+
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ if ((element == INHERITED_INJECTED_VALUE_NODE) || (element == LOCAL_VALUE_NODE)) {
+ return true; // Intermediate nodes returns true
+ }
+
+ Set<Computation> listeners = getListeners(element);
+ return (listeners != null) && (listeners.size() > 0);
+ }
+
+ @SuppressWarnings("unchecked")
+ Set<Computation> getListeners(Object element) {
+ if (selectedContext != null) {
+ if (element instanceof Map.Entry) {
+ // Ask the context to know if there are listeners for this value
+ Map.Entry<String, Object> mapEntry = (Map.Entry<String, Object>) element;
+ String key = mapEntry.getKey();
+ return selectedContext.getListeners(key);
+
+ } else if (element instanceof String) {
+ // Ask the context to know if there are listeners for this raw
+ // listener name
+ return selectedContext.getListeners((String) element);
+ }
+ }
+ return null;
+
+ }
+
+ private void initializeImageRegistry() {
+ Bundle b = FrameworkUtil.getBundle(this.getClass());
+ imgReg = new ImageRegistry();
+
+ imgReg.put(CONTEXT_FUNCTION_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(CONTEXT_FUNCTION_IMG_KEY)));
+ imgReg.put(INJECT_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(INJECT_IMG_KEY)));
+ imgReg.put(PUBLIC_METHOD_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(PUBLIC_METHOD_IMG_KEY)));
+ imgReg.put(PUBLIC_FIELD_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(PUBLIC_FIELD_IMG_KEY)));
+ imgReg.put(PUBLIC_FIELD_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(PUBLIC_FIELD_IMG_KEY)));
+ imgReg.put(LOCAL_VARIABLE_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(LOCAL_VARIABLE_IMG_KEY)));
+ imgReg.put(VALUE_IN_CONTEXT_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(VALUE_IN_CONTEXT_IMG_KEY)));
+ imgReg.put(INHERITED_VARIABLE_IMG_KEY, ImageDescriptor.createFromURL(b.getEntry(INHERITED_VARIABLE_IMG_KEY)));
+
+ }
+
+ private void initFonts() {
+ FontData[] fontData = Display.getCurrent().getSystemFont().getFontData();
+ String fontName = fontData[0].getName();
+ FontRegistry registry = JFaceResources.getFontRegistry();
+ boldFont = registry.getBold(fontName);
+ }
+
+}
diff --git a/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextSpyHelper.java b/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextSpyHelper.java
new file mode 100644
index 0000000000..32b4aed72d
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextSpyHelper.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2013 OPCoach.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * OPCoach - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.internal.spy.context;
+
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.osgi.framework.BundleContext;
+
+/**
+ * A helper class to get information inside context management system. This
+ * class uses internal fields or methods defined in EclipseContext Could be
+ * updated in the future.
+ *
+ * @author olivier
+ *
+ */
+public class ContextSpyHelper {
+
+ /**
+ * Get all the contexts created by EclipseContextFactory. It get values from
+ * field introspection. Should be rewritten if internal structure changes
+ *
+ * @return a collection of contexts created by EclipseContextFactory
+ */
+ public static Collection<IEclipseContext> getAllBundleContexts() {
+ Collection<IEclipseContext> result = Collections.emptyList();
+ try {
+ // Must use introspection to get the weak hash map (no getter).
+ Field f = EclipseContextFactory.class.getDeclaredField("serviceContexts");
+ f.setAccessible(true);
+ @SuppressWarnings("unchecked")
+ Map<BundleContext, IEclipseContext> ctxs = (Map<BundleContext, IEclipseContext>) f.get(null);
+ result = ctxs.values();
+
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+
+ return result;
+
+ }
+
+}
diff --git a/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextSpyProvider.java b/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextSpyProvider.java
new file mode 100644
index 0000000000..1f8d183d4e
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/internal/spy/context/ContextSpyProvider.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2013 OPCoach.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * OPCoach - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.internal.spy.context;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.internal.contexts.EclipseContext;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+
+@SuppressWarnings("restriction")
+/**
+ * This label and treecontent provider is used by ContextSpyPart to display
+ * available contexts.
+ *
+ * @author olivier
+ *
+ */
+public class ContextSpyProvider extends LabelProvider implements ITreeContentProvider, IColorProvider {
+
+ @Inject
+ private ContextDataFilter contextFilter;
+
+ @Inject
+ public ContextSpyProvider() {
+
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ if (inputElement instanceof MApplication) {
+ return new Object[] { ((MApplication) inputElement).getContext().getParent() };
+ } else if (inputElement instanceof Collection<?>) {
+ return ((Collection<?>) inputElement).toArray();
+ }
+
+ return new Object[0];
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ List<EclipseContext> children = Collections.emptyList();
+
+ if (parentElement instanceof EclipseContext) {
+ Iterable<EclipseContext> it = ((EclipseContext) parentElement).getChildren();
+ children = new ArrayList<EclipseContext>();
+ it.forEach(children::add);
+ }
+ return children.toArray();
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ if (element instanceof EclipseContext) {
+ return ((EclipseContext) element).getParent();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ return getChildren(element).length > 0;
+ }
+
+ @Override
+ public String getText(Object element) {
+ return super.getText(element);
+ }
+
+ @Override
+ public Color getForeground(Object element) {
+ // Return a color if a text contained in this node contains the text.
+ if (element instanceof IEclipseContext && contextFilter.containsText((IEclipseContext) element)) {
+ return Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
+ }
+ return null;
+ }
+
+ @Override
+ public Color getBackground(Object element) {
+ return null;
+ }
+
+}
diff --git a/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/spy/context/ContextSpyPart.java b/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/spy/context/ContextSpyPart.java
new file mode 100644
index 0000000000..e07666ec1f
--- /dev/null
+++ b/ui/org.eclipse.pde.spy.context/src/org/eclipse/pde/spy/context/ContextSpyPart.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2013 OPCoach.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Olivier Prouvost <olivier.prouvost@opcoach.com> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.spy.context;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.di.Focus;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.pde.internal.spy.context.ContextDataFilter;
+import org.eclipse.pde.internal.spy.context.ContextDataPart;
+import org.eclipse.pde.internal.spy.context.ContextSpyHelper;
+import org.eclipse.pde.internal.spy.context.ContextSpyProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * This class is the main part of the context spy. It creates a treeviewer and
+ * the context data part listening to context selection
+ */
+public class ContextSpyPart {
+
+ private static final String ICON_COLLAPSEALL = "icons/collapseall.png";
+ private static final String ICON_EXPANDALL = "icons/expandall.png";
+ private static final String ICON_REFRESH = "icons/refresh.png";
+
+ // The ID for this part descriptor
+ static final String CONTEXT_SPY_VIEW_DESC = "org.eclipse.e4.tools.context.spy.view";
+
+ private TreeViewer contextTreeViewer;
+
+ @Inject
+ private ESelectionService selService;
+
+ private ContextSpyProvider treeContentProvider;
+
+ private ImageRegistry imgReg;
+
+ @Inject
+ private ContextDataFilter contextFilter;
+
+ private ContextDataPart contextDataPart;
+ private Button showOnlyFilteredElements;
+ private Text filterText;
+
+ /** Store the values to set it when it is reopened */
+ private static String lastFilterText = null;
+ private static boolean lastShowFiltered = false;
+
+ @Inject
+ private void initializeImageRegistry() {
+ Bundle b = FrameworkUtil.getBundle(this.getClass());
+ imgReg = new ImageRegistry();
+ imgReg.put(ICON_COLLAPSEALL, ImageDescriptor.createFromURL(b.getEntry(ICON_COLLAPSEALL)));
+ imgReg.put(ICON_EXPANDALL, ImageDescriptor.createFromURL(b.getEntry(ICON_EXPANDALL)));
+ imgReg.put(ICON_REFRESH, ImageDescriptor.createFromURL(b.getEntry(ICON_REFRESH)));
+ }
+
+ /**
+ * Create contents of the view part.
+ */
+ @PostConstruct
+ public void createControls(Composite parent, MApplication a, IEclipseContext ctx) {
+ parent.setLayout(new GridLayout(1, false));
+
+ final Composite comp = new Composite(parent, SWT.NONE);
+ comp.setLayout(new GridLayout(7, false));
+
+ Button refreshButton = new Button(comp, SWT.FLAT);
+ refreshButton.setImage(imgReg.get(ICON_REFRESH));
+ refreshButton.setToolTipText("Refresh the contexts");
+ refreshButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ contextTreeViewer.refresh(true);
+ contextDataPart.refresh(true);
+ }
+ });
+
+ Button expandAll = new Button(comp, SWT.FLAT);
+ expandAll.setImage(imgReg.get(ICON_EXPANDALL));
+ expandAll.setToolTipText("Expand context nodes");
+ expandAll.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ contextTreeViewer.expandAll();
+ }
+ });
+ Button collapseAll = new Button(comp, SWT.FLAT);
+ collapseAll.setImage(imgReg.get(ICON_COLLAPSEALL));
+ collapseAll.setToolTipText("Collapse context nodes");
+ collapseAll.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ contextTreeViewer.collapseAll();
+ }
+
+ });
+
+ filterText = new Text(comp, SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
+ GridDataFactory.fillDefaults().hint(200, SWT.DEFAULT).applyTo(filterText);
+ filterText.setMessage("Search data");
+ filterText.setToolTipText("Highlight the contexts where the contained objects contains this string pattern.\n"
+ + "Case is ignored.");
+ if (lastFilterText != null)
+ filterText.setText(lastFilterText);
+ contextFilter.setPattern(lastFilterText);
+ filterText.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyReleased(KeyEvent e) {
+ String textToSearch = filterText.getText();
+ lastFilterText = textToSearch;
+ boolean enableButton = textToSearch.length() > 0;
+ // Enable/disable button for filtering
+ showOnlyFilteredElements.setEnabled(enableButton);
+
+ // Then update filters and viewers
+ contextFilter.setPattern(textToSearch);
+ setFilter();
+ contextTreeViewer.refresh(true);
+ contextDataPart.refresh(true);
+ }
+
+ });
+
+ showOnlyFilteredElements = new Button(comp, SWT.CHECK);
+ showOnlyFilteredElements.setText("Show Only Filtered");
+ showOnlyFilteredElements.setToolTipText("Show only the filtered items in the table view");
+ showOnlyFilteredElements.setEnabled((lastFilterText != null) && (lastFilterText.length() > 0));
+ showOnlyFilteredElements.setSelection(lastShowFiltered);
+ showOnlyFilteredElements.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ lastShowFiltered = showOnlyFilteredElements.getSelection();
+ setFilter();
+ }
+ });
+
+ SashForm sashForm = new SashForm(parent, SWT.VERTICAL | SWT.V_SCROLL | SWT.H_SCROLL);
+ sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ // TreeViewer on the top
+ contextTreeViewer = new TreeViewer(sashForm);
+ treeContentProvider = ContextInjectionFactory.make(ContextSpyProvider.class, ctx);
+ contextTreeViewer.setContentProvider(treeContentProvider);
+ contextTreeViewer.setLabelProvider(treeContentProvider);
+ contextTreeViewer.setComparator(new ViewerComparator());
+
+ // tv.setInput(a);
+ contextTreeViewer.setInput(ContextSpyHelper.getAllBundleContexts());
+
+ contextTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection ss = (IStructuredSelection) event.getSelection();
+ selService.setSelection((ss.size() == 1) ? ss.getFirstElement() : ss.toArray());
+ }
+ });
+
+ IEclipseContext subCtx = ctx.createChild("Context for ContextDataPart");
+ subCtx.set(Composite.class, sashForm);
+ contextDataPart = ContextInjectionFactory.make(ContextDataPart.class, subCtx);
+ setFilter();
+
+ // Set the correct weight for SashForm
+ sashForm.setWeights(new int[] { 35, 65 });
+
+ // Open all the tree
+ contextTreeViewer.expandAll();
+
+ }
+
+ /** Set the filter on context data part */
+ public void setFilter() {
+ if (showOnlyFilteredElements.isEnabled() && showOnlyFilteredElements.getSelection())
+ contextDataPart.setFilter(contextFilter);
+ else
+ contextDataPart.setFilter(null);
+ }
+
+ @PreDestroy
+ public void dispose() {
+ }
+
+ @Focus
+ public void setFocus() {
+ contextTreeViewer.getControl().setFocus();
+ }
+
+}
diff --git a/ui/org.eclipse.pde.spy.core/src/org/eclipse/pde/spy/core/SpyProcessor.java b/ui/org.eclipse.pde.spy.core/src/org/eclipse/pde/spy/core/SpyProcessor.java
index 026f38a46d..5449e959ea 100644
--- a/ui/org.eclipse.pde.spy.core/src/org/eclipse/pde/spy/core/SpyProcessor.java
+++ b/ui/org.eclipse.pde.spy.core/src/org/eclipse/pde/spy/core/SpyProcessor.java
@@ -238,6 +238,7 @@ public class SpyProcessor {
mp.setCategory(Messages.SpyProcessor_category);
mp.setDescription(desc);
mp.setLabel(partLabel);
+ mp.getPersistedState().remove(IWorkbench.PERSIST_STATE); // see Bug 577275
String bundleId = FrameworkUtil.getBundle(spyPartClass).getSymbolicName();
mp.setContributionURI("bundleclass://" + bundleId + "/" + spyPartClass.getCanonicalName());
String contributorURI = "platform:/plugin/" + bundleId;
@@ -250,7 +251,6 @@ public class SpyProcessor {
// If descriptor not yet in descriptor list, add it now
MPartDescriptor descriptor = modelService.createModelElement(MPartDescriptor.class);
descriptor.setCategory(Messages.SpyProcessor_category);
- descriptor.getPersistedState().put(IWorkbench.PERSIST_STATE, "false");
descriptor.setElementId(partId);
descriptor.setDescription(desc);
descriptor.getTags().add("View");
diff --git a/ui/org.eclipse.pde.ui.tests.smartimport/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.ui.tests.smartimport/META-INF/MANIFEST.MF
index 45932a56b7..2f6eb43fe2 100644
--- a/ui/org.eclipse.pde.ui.tests.smartimport/META-INF/MANIFEST.MF
+++ b/ui/org.eclipse.pde.ui.tests.smartimport/META-INF/MANIFEST.MF
@@ -2,21 +2,21 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Smart Import test for PDE
Bundle-SymbolicName: org.eclipse.pde.ui.tests.smartimport;singleton:=true
-Bundle-Version: 1.1.0.qualifier
+Bundle-Version: 1.1.100.qualifier
Bundle-Vendor: Eclipse.org
Export-Package: org.eclipse.ui.tests.smartimport
Require-Bundle: org.eclipse.core.resources,
org.eclipse.core.runtime,
org.eclipse.jface,
- org.eclipse.reddeer.core;bundle-version="[3.0.0,4.0.0)",
- org.eclipse.reddeer.common;bundle-version="[3.0.0,4.0.0)",
- org.eclipse.reddeer.eclipse;bundle-version="[3.0.0,4.0.0)",
- org.eclipse.reddeer.jface;bundle-version="[3.0.0,4.0.0)",
- org.eclipse.reddeer.junit;bundle-version="[3.0.0,4.0.0)",
- org.eclipse.reddeer.junit.extension;bundle-version="[3.0.0,4.0.0)",
- org.eclipse.reddeer.swt;bundle-version="[3.0.0,4.0.0)",
- org.eclipse.reddeer.workbench;bundle-version="[3.0.0,4.0.0)",
- org.eclipse.reddeer.workbench.core;bundle-version="[3.0.0,4.0.0)",
+ org.eclipse.reddeer.core;bundle-version="[3.0.0,5.0.0)",
+ org.eclipse.reddeer.common;bundle-version="[3.0.0,5.0.0)",
+ org.eclipse.reddeer.eclipse;bundle-version="[3.0.0,5.0.0)",
+ org.eclipse.reddeer.jface;bundle-version="[3.0.0,5.0.0)",
+ org.eclipse.reddeer.junit;bundle-version="[3.0.0,5.0.0)",
+ org.eclipse.reddeer.junit.extension;bundle-version="[3.0.0,5.0.0)",
+ org.eclipse.reddeer.swt;bundle-version="[3.0.0,5.0.0)",
+ org.eclipse.reddeer.workbench;bundle-version="[3.0.0,5.0.0)",
+ org.eclipse.reddeer.workbench.core;bundle-version="[3.0.0,5.0.0)",
org.eclipse.swt,
org.junit,
org.eclipse.jdt.ui,
diff --git a/ui/org.eclipse.pde.ui.tests.smartimport/pom.xml b/ui/org.eclipse.pde.ui.tests.smartimport/pom.xml
index b544afb9d2..b3dc083c9a 100644
--- a/ui/org.eclipse.pde.ui.tests.smartimport/pom.xml
+++ b/ui/org.eclipse.pde.ui.tests.smartimport/pom.xml
@@ -16,7 +16,7 @@
</parent>
<groupId>org.eclipse.pde</groupId>
<artifactId>org.eclipse.pde.ui.tests.smartimport</artifactId>
- <version>1.1.0-SNAPSHOT</version>
+ <version>1.1.100-SNAPSHOT</version>
<packaging>eclipse-test-plugin</packaging>
diff --git a/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF
index b1df78589f..1d451b3e4b 100644
--- a/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF
+++ b/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF
@@ -41,7 +41,8 @@ Require-Bundle: org.junit,
org.eclipse.debug.core,
org.eclipse.pde.genericeditor.extension,
org.eclipse.equinox.simpleconfigurator.manipulator;bundle-version="2.1.300"
-Import-Package: org.assertj.core.api;version="3.14.0"
+Import-Package: org.assertj.core.api;version="3.14.0",
+ org.junit.jupiter.api.function;version="5.8.1"
Eclipse-LazyStart: true
Bundle-RequiredExecutionEnvironment: JavaSE-11
Eclipse-BundleShape: dir
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/core/tests/internal/DependencyManagerTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/core/tests/internal/DependencyManagerTest.java
index a56ed5e906..a954c90b55 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/core/tests/internal/DependencyManagerTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/core/tests/internal/DependencyManagerTest.java
@@ -21,12 +21,12 @@ import java.net.URI;
import java.util.*;
import java.util.Map.Entry;
import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.service.resolver.State;
import org.eclipse.pde.core.plugin.PluginRegistry;
-import org.eclipse.pde.core.target.*;
+import org.eclipse.pde.core.target.ITargetLocation;
+import org.eclipse.pde.core.target.ITargetPlatformService;
import org.eclipse.pde.internal.core.*;
import org.eclipse.pde.internal.core.target.IUBundleContainer;
import org.eclipse.pde.ui.tests.target.IUBundleContainerTests;
@@ -38,6 +38,11 @@ import org.osgi.framework.Version;
public class DependencyManagerTest {
+ @ClassRule
+ public static final TestRule CLEAR_WORKSPACE = ProjectUtils.DELETE_ALL_WORKSPACE_PROJECTS_BEFORE_AND_AFTER;
+ @Rule
+ public final TestRule deleteCreatedTestProjectsAfter = ProjectUtils.DELETE_CREATED_WORKSPACE_PROJECTS_AFTER;
+
@Rule
public final TestRule restoreTargetDefinition = TargetPlatformUtil.RESTORE_CURRENT_TARGET_DEFINITION_AFTER;
@@ -46,13 +51,6 @@ public class DependencyManagerTest {
PluginModelManager.getInstance().getState();
}
- @After
- public void clearWorkspace() throws Exception {
- for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
- project.delete(false, true, null);
- }
- }
-
@Test
public void testFindRequirementsClosure_RequireBundle() throws IOException, CoreException {
BundleDescription bundleA = importProjectBundle("tests/projects/requirements/bundle.A-1.0.0");
@@ -165,8 +163,6 @@ public class DependencyManagerTest {
IUBundleContainer.INCLUDE_REQUIRED | IUBundleContainer.INCLUDE_CONFIGURE_PHASE);
locations.add(location);
});
- ITargetDefinition target = tps.newTarget();
- TargetPlatformUtil.setTargetProperties(target, locations.toArray(ITargetLocation[]::new));
- TargetPlatformUtil.loadAndSetTargetForWorkspace(target);
+ TargetPlatformUtil.createAndSetTargetForWorkspace(null, locations, null);
}
}
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/core/tests/internal/classpath/ClasspathResolutionTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/core/tests/internal/classpath/ClasspathResolutionTest.java
index 95042a8287..6a7137b654 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/core/tests/internal/classpath/ClasspathResolutionTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/core/tests/internal/classpath/ClasspathResolutionTest.java
@@ -22,7 +22,8 @@ import java.util.Arrays;
import java.util.Set;
import java.util.function.Predicate;
import org.eclipse.core.resources.*;
-import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
@@ -39,20 +40,15 @@ public class ClasspathResolutionTest {
@ClassRule
public static final TestRule RESTORE_TARGET_DEFINITION = TargetPlatformUtil.RESTORE_CURRENT_TARGET_DEFINITION_AFTER;
- private IProject project;
-
- @After
- public void tearDown() throws CoreException {
- if (project != null) {
- project.delete(false, false, null);
- project = null;
- }
- }
+ @ClassRule
+ public static final TestRule CLEAR_WORKSPACE = ProjectUtils.DELETE_ALL_WORKSPACE_PROJECTS_BEFORE_AND_AFTER;
+ @Rule
+ public final TestRule deleteCreatedTestProjectsAfter = ProjectUtils.DELETE_CREATED_WORKSPACE_PROJECTS_AFTER;
@Test
public void testImportSystemPackageDoesntAddExtraBundleJava11() throws Exception {
loadTargetPlatform("org.w3c.dom.events");
- project = ProjectUtils.importTestProject("tests/projects/demoMissedSystemModulePackage");
+ IProject project = ProjectUtils.importTestProject("tests/projects/demoMissedSystemModulePackage");
project.build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
IJavaProject javaProject = (IJavaProject) project.getNature(JavaCore.NATURE_ID);
RequiredPluginsClasspathContainer container = new RequiredPluginsClasspathContainer(
@@ -80,7 +76,7 @@ public class ClasspathResolutionTest {
@Test
public void testImportExternalPreviouslySystemPackageAddsExtraBundle() throws Exception {
loadTargetPlatform("javax.annotation");
- project = ProjectUtils.importTestProject("tests/projects/demoMissedExternalPackage");
+ IProject project = ProjectUtils.importTestProject("tests/projects/demoMissedExternalPackage");
project.build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
// In Java 11, javax.annotation is not present, so the bundle *must* be
// part of classpath
@@ -94,7 +90,7 @@ public class ClasspathResolutionTest {
@Test
public void testImportExternalPreviouslySystemPackageAddsExtraBundle_missingBREE() throws Exception {
loadTargetPlatform("javax.annotation");
- project = ProjectUtils.importTestProject("tests/projects/demoMissedExternalPackageNoBREE");
+ IProject project = ProjectUtils.importTestProject("tests/projects/demoMissedExternalPackageNoBREE");
IExecutionEnvironment java11 = JavaRuntime.getExecutionEnvironmentsManager().getEnvironment("JavaSE-11");
assertThat(JavaRuntime.getVMInstall(JavaCore.create(project))).isIn(Arrays.asList(java11.getCompatibleVMs()));
@@ -112,7 +108,7 @@ public class ClasspathResolutionTest {
@Test
public void testImportSystemPackageDoesntAddExtraBundleJava8() throws Exception {
loadTargetPlatform("javax.annotation");
- project = ProjectUtils.importTestProject("tests/projects/demoMissedSystemPackageJava8");
+ IProject project = ProjectUtils.importTestProject("tests/projects/demoMissedSystemPackageJava8");
project.build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
// In Java 8, javax.annotation is present, so the bundle must *NOT* be
// part of classpath
@@ -126,7 +122,7 @@ public class ClasspathResolutionTest {
@Test
public void testImportSystemPackageDoesntAddExtraBundleJava8_osgiEERequirement() throws Exception {
loadTargetPlatform("javax.annotation");
- project = ProjectUtils.importTestProject("tests/projects/demoMissedSystemPackageJava8OsgiEERequirement");
+ IProject project = ProjectUtils.importTestProject("tests/projects/demoMissedSystemPackageJava8OsgiEERequirement");
project.build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
// bundle is build with java 11, but declares java 8 requirement via
// Require-Capability
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathcontributor/ClasspathContributorTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathcontributor/ClasspathContributorTest.java
index 0621ff52e5..1b9ce632f4 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathcontributor/ClasspathContributorTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathcontributor/ClasspathContributorTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013, 2018 IBM Corporation and others.
+ * Copyright (c) 2013, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,23 +10,22 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Hannes Wellmann - Bug 577629 - Unify project creation/deletion in tests
*******************************************************************************/
package org.eclipse.pde.ui.tests.classpathcontributor;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import java.io.*;
-import java.net.URL;
import java.util.*;
-import org.eclipse.core.resources.*;
-import org.eclipse.core.runtime.*;
+import org.eclipse.core.resources.IProject;
import org.eclipse.jdt.core.*;
import org.eclipse.pde.core.IClasspathContributor;
import org.eclipse.pde.internal.core.PDECore;
-import org.eclipse.pde.ui.tests.PDETestsPlugin;
import org.eclipse.pde.ui.tests.classpathresolver.ClasspathResolverTest;
+import org.eclipse.pde.ui.tests.util.ProjectUtils;
import org.junit.*;
+import org.junit.rules.TestRule;
/**
* Tests {@link IClasspathContributor} API to add additional classpath
@@ -35,22 +34,14 @@ import org.junit.*;
*/
public class ClasspathContributorTest {
- private static final IProgressMonitor monitor = new NullProgressMonitor();
- private IWorkspace workspace = ResourcesPlugin.getWorkspace();
- private IProject project;
-
- @Before
- public void setUp() throws Exception {
- project = importProject(workspace);
- }
-
- @After
- public void tearDown() throws Exception {
- project.delete(true, true, monitor);
- }
+ @ClassRule
+ public static final TestRule CLEAR_WORKSPACE = ProjectUtils.DELETE_ALL_WORKSPACE_PROJECTS_BEFORE_AND_AFTER;
+ @Rule
+ public final TestRule deleteCreatedTestProjectsAfter = ProjectUtils.DELETE_CREATED_WORKSPACE_PROJECTS_AFTER;
@Test
public void testAdditionalClasspathEntries() throws Exception {
+ IProject project = ProjectUtils.importTestProject("tests/projects/" + ClasspathResolverTest.bundleName);
List<IClasspathEntry> expected = new ArrayList<>(TestClasspathContributor.entries);
expected.addAll(TestClasspathContributor.entries2);
IJavaProject jProject = JavaCore.create(project);
@@ -59,59 +50,10 @@ public class ClasspathContributorTest {
IClasspathEntry[] classpath = container.getClasspathEntries();
for (IClasspathEntry element : classpath) {
// Ignore the PDE Core bundle dependency
- if (element.getPath().toPortableString().indexOf("org.eclipse.pde.core") == -1){
+ if (element.getPath().toPortableString().indexOf("org.eclipse.pde.core") == -1) {
assertTrue("Unexpected classpath entry found: " + element, expected.remove(element));
}
}
assertTrue("Expected classpath entry not found: " + Arrays.toString(expected.toArray()), expected.isEmpty());
}
-
- /**
- * Imports a project into the test workspace
- *
- * @param workspace workspace to import into
- * @return the created project
- * @throws IOException
- * @throws CoreException
- */
- IProject importProject(IWorkspace workspace) throws IOException, CoreException {
- File rootFile = workspace.getRoot().getLocation().toFile();
-
- URL srcURL = PDETestsPlugin.getBundleContext().getBundle ().getEntry("tests/projects/" + ClasspathResolverTest.bundleName);
- File srcBasedir = new File(FileLocator.toFileURL(srcURL).getFile());
-
- File dstBasedir = new File(rootFile, ClasspathResolverTest.bundleName);
- copyFile(srcBasedir, dstBasedir, ".project");
- copyFile(srcBasedir, dstBasedir, ".classpath");
- copyFile(srcBasedir, dstBasedir, "build.properties");
- copyFile(srcBasedir, dstBasedir, "META-INF/MANIFEST.MF");
- copyFile(srcBasedir, dstBasedir, "cpe/some.properties");
- IProject project = workspace.getRoot().getProject(ClasspathResolverTest.bundleName);
- IProjectDescription description = workspace.newProjectDescription(ClasspathResolverTest.bundleName);
- project.create(description, monitor);
- project.open(monitor);
- return project;
- }
-
- private void copyFile(File srcBasedir, File dstBasedir, String file) throws IOException {
- copyFile(new File(srcBasedir, file), new File(dstBasedir, file));
- }
-
- // copy&paste from org.eclipse.m2e.tests.common.FileHelpers
- private void copyFile(File src, File dst) throws IOException {
- src.getParentFile().mkdirs();
- dst.getParentFile().mkdirs();
-
- try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
- BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dst))) {
-
- byte[] buf = new byte[10240];
- int len;
- while ((len = in.read(buf)) != -1) {
- out.write(buf, 0, len);
- }
-
- }
- }
-
}
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathresolver/ClasspathResolverTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathresolver/ClasspathResolverTest.java
index 9c704db979..36613d405b 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathresolver/ClasspathResolverTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathresolver/ClasspathResolverTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011, 2017 Sonatype, Inc. and others.
+ * Copyright (c) 2011, 2021 Sonatype, Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -11,53 +11,88 @@
* Contributors:
* Sonatype, Inc. - initial API and implementation
* IBM Corporation - ongoing enhancements
+ * Hannes Wellmann - Bug 577629 - Unify project creation/deletion in tests
+ * Hannes Wellmann - Bug 577541 - Clean up ClasspathHelper and TargetWeaver and create tests
*******************************************************************************/
package org.eclipse.pde.ui.tests.classpathresolver;
+import static org.eclipse.pde.ui.tests.launcher.AbstractLaunchTest.findTargetModel;
+import static org.eclipse.pde.ui.tests.launcher.AbstractLaunchTest.findWorkspaceModel;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import java.io.*;
+import java.lang.reflect.Field;
import java.net.URL;
-import java.util.Properties;
-import org.eclipse.core.resources.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.*;
import org.eclipse.debug.core.sourcelookup.ISourceContainer;
import org.eclipse.debug.core.sourcelookup.containers.DirectorySourceContainer;
-import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.*;
import org.eclipse.jdt.launching.sourcelookup.containers.JavaProjectSourceContainer;
import org.eclipse.pde.core.IBundleClasspathResolver;
+import org.eclipse.pde.core.plugin.IPluginModelBase;
+import org.eclipse.pde.core.target.NameVersionDescriptor;
import org.eclipse.pde.internal.core.ClasspathHelper;
+import org.eclipse.pde.internal.core.TargetWeaver;
import org.eclipse.pde.internal.launching.sourcelookup.PDESourceLookupDirector;
import org.eclipse.pde.internal.launching.sourcelookup.PDESourceLookupQuery;
-import org.eclipse.pde.ui.tests.PDETestsPlugin;
+import org.eclipse.pde.ui.tests.util.ProjectUtils;
+import org.eclipse.pde.ui.tests.util.TargetPlatformUtil;
import org.junit.*;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestRule;
+import org.osgi.framework.Bundle;
/**
- * Tests {@link IBundleClasspathResolver} API to extend how the classpath and source lookup path
- * is created.
+ * Tests {@link IBundleClasspathResolver} API to extend how the classpath and
+ * source lookup path is created.
*
*/
public class ClasspathResolverTest {
- private static final IProgressMonitor monitor = new NullProgressMonitor();
+ @ClassRule
+ public static final TestRule CLEAR_WORKSPACE = ProjectUtils.DELETE_ALL_WORKSPACE_PROJECTS_BEFORE_AND_AFTER;
+ @ClassRule
+ public static final TestRule RESTORE_TARGET_DEFINITION = TargetPlatformUtil.RESTORE_CURRENT_TARGET_DEFINITION_AFTER;
- private IWorkspace workspace = ResourcesPlugin.getWorkspace();
-
- private IProject project;
+ private static IProject project;
/**
* The project name and bundle symbolic name of the test project
*/
public static final String bundleName = "classpathresolver";
+ private static final String HOST_BUNDLE_ID = "org.eclipse.pde.core";
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ project = ProjectUtils.importTestProject("tests/projects/" + bundleName);
+ // create workspace plug-ins with same id like a running-platform bundle
+ Bundle hostBundle = Platform.getBundle(HOST_BUNDLE_ID);
+ createWorkspacePluginProjects(List.of( //
+ bundle(hostBundle.getSymbolicName(), "2.0.0"), //
+ bundle(hostBundle.getSymbolicName(), hostBundle.getVersion().toString())));
+ }
+
+ @Rule
+ public TemporaryFolder tempFolder = new TemporaryFolder();
+
+ private Path mockedPlatformDevPropertiesFile;
+ private String originalPlatformDevPropertiesURL;
@Before
public void setUp() throws Exception {
- project = importProject(workspace);
+ mockedPlatformDevPropertiesFile = tempFolder.newFile("test-platform-dev.properties").toPath();
+ String mockDevPropertiesURL = mockedPlatformDevPropertiesFile.toUri().toURL().toString();
+ originalPlatformDevPropertiesURL = setPlatformDevPropertiesURL(mockDevPropertiesURL);
}
@After
- public void tearDown() throws Exception {
- project.delete(true, true, monitor);
+ public void tearDown() throws ReflectiveOperationException {
+ setPlatformDevPropertiesURL(originalPlatformDevPropertiesURL);
}
private class _PDESourceLookupQuery extends PDESourceLookupQuery {
@@ -66,7 +101,7 @@ public class ClasspathResolverTest {
super(director, object);
}
- @Override
+ @Override // Make super.getSourceContainers() visible
public ISourceContainer[] getSourceContainers(String location, String id) throws CoreException {
return super.getSourceContainers(location, id);
}
@@ -75,29 +110,27 @@ public class ClasspathResolverTest {
/**
* Checks that a created dev properties file will recognise the modified
* classpath
- *
- * @throws Exception
*/
@Test
- public void testDevProperties() throws Exception {
- File devProperties = File.createTempFile("dev", ".properties");
- ClasspathHelper.getDevEntriesProperties(devProperties.getCanonicalPath(), false);
+ public void testGetDevProperties() throws Exception {
+ mockTPWithRunningPlatformAndBundles(List.of()); // running-platform only
- Properties properties = new Properties();
- try (InputStream is = new FileInputStream(devProperties)) {
- properties.load(is);
- }
+ File devProperties = tempFolder.newFile("dev.properties").getCanonicalFile();
+ String devPropertiesURL = ClasspathHelper.getDevEntriesProperties(devProperties.getPath(), false);
+
+ Properties properties = loadProperties(devPropertiesURL);
- assertEquals(project.getFolder("cpe").getLocation().toPortableString(), properties.get(bundleName));
+ String expectedDevCP = project.getFolder("cpe").getLocation().toPortableString();
+ assertEquals(expectedDevCP, properties.get(bundleName));
}
/**
* Checks that the source lookup path of a project is updated from the API
- *
- * @throws Exception
*/
@Test
public void testSourceLookupPath() throws Exception {
+ mockTPWithRunningPlatformAndBundles(List.of()); // running-platform only
+
PDESourceLookupDirector d = new PDESourceLookupDirector();
_PDESourceLookupQuery q = new _PDESourceLookupQuery(d, project);
@@ -105,54 +138,252 @@ public class ClasspathResolverTest {
assertEquals(2, containers.length);
assertEquals(JavaCore.create(project), ((JavaProjectSourceContainer) containers[0]).getJavaProject());
- assertEquals(project.getFolder("cpe").getLocation().toFile(), ((DirectorySourceContainer) containers[1]).getDirectory());
+ assertEquals(project.getFolder("cpe").getLocation().toFile(),
+ ((DirectorySourceContainer) containers[1]).getDirectory());
}
- /**
- * Imports a project into the test workspace
- *
- * @param workspace workspace to import into
- * @return the created project
- * @throws IOException
- * @throws CoreException
- */
- IProject importProject(IWorkspace workspace) throws IOException, CoreException {
- File rootFile = workspace.getRoot().getLocation().toFile();
-
- URL srcURL = PDETestsPlugin.getBundleContext().getBundle().getEntry("tests/projects/" + bundleName);
- File srcBasedir = new File(FileLocator.toFileURL(srcURL).getFile());
-
- File dstBasedir = new File(rootFile, bundleName);
- copyFile(srcBasedir, dstBasedir, ".project");
- copyFile(srcBasedir, dstBasedir, ".classpath");
- copyFile(srcBasedir, dstBasedir, "build.properties");
- copyFile(srcBasedir, dstBasedir, "META-INF/MANIFEST.MF");
- copyFile(srcBasedir, dstBasedir, "cpe/some.properties");
- IProject project = workspace.getRoot().getProject(bundleName);
- IProjectDescription description = workspace.newProjectDescription(bundleName);
- project.create(description, monitor);
- project.open(monitor);
- return project;
- }
-
- private void copyFile(File srcBasedir, File dstBasedir, String file) throws IOException {
- copyFile(new File(srcBasedir, file), new File(dstBasedir, file));
- }
-
- // copy&paste from org.eclipse.m2e.tests.common.FileHelpers
- private void copyFile(File src, File dst) throws IOException {
- src.getParentFile().mkdirs();
- dst.getParentFile().mkdirs();
-
- try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
- BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dst))) {
-
- byte[] buf = new byte[10240];
- int len;
- while ((len = in.read(buf)) != -1) {
- out.write(buf, 0, len);
- }
+ @Test
+ public void testGetDevProperties_workspacePlugin_devEntryWithAndWithoutVersion() throws Exception {
+
+ getHostBundleAndMockDevProperties();
+
+ mockTPWithBundles(List.of()); // empty TP
+
+ IPluginModelBase wsModel = findWorkspaceModel(HOST_BUNDLE_ID, "2.0.0");
+
+ Properties devProperties = createDevEntryProperties(List.of(wsModel));
+
+ assertEquals("true", devProperties.getProperty("@ignoredot@"));
+ assertEquals("bin", devProperties.getProperty(HOST_BUNDLE_ID));
+ assertEquals(2, devProperties.size()); // assert no more entries
+ }
+
+ @Test
+ public void testGetDevProperties_workspacePluginWithSameVersionLikeHostBundle_devEntryWithAndWithoutVersion()
+ throws Exception {
+
+ Bundle hostBundle = getHostBundleAndMockDevProperties();
+ String hostBundleVersion = hostBundle.getVersion().toString();
+
+ mockTPWithBundles(List.of()); // empty TP
+
+ IPluginModelBase wsModel = findWorkspaceModel(HOST_BUNDLE_ID, hostBundleVersion);
+
+ Properties devProperties = createDevEntryProperties(List.of(wsModel));
+
+ assertEquals("true", devProperties.getProperty("@ignoredot@"));
+ assertEquals("bin", devProperties.getProperty(HOST_BUNDLE_ID));
+ assertEquals(2, devProperties.size()); // assert no more entries
+ }
+
+ @Test
+ public void testGetDevProperties_bundleFromRunningPlatform_wovenDevEntryWithAndWithoutVersion() throws Exception {
+
+ Bundle hostBundle = getHostBundleAndMockDevProperties();
+ String hostBundleVersion = hostBundle.getVersion().toString();
+
+ mockTPWithRunningPlatformAndBundles(List.of()); // running-platform only
+
+ IPluginModelBase hostModel = findTargetModel(HOST_BUNDLE_ID, hostBundleVersion);
+
+ Properties devProperties = createDevEntryProperties(List.of(hostModel));
+
+ assertEquals("true", devProperties.getProperty("@ignoredot@"));
+ assertEquals("devPath1", devProperties.getProperty(HOST_BUNDLE_ID));
+ assertEquals(2, devProperties.size()); // assert no more entries
+ }
+
+ @Test
+ public void testGetDevProperties_jarTPBundle_noDevEntries() throws Exception {
+
+ getHostBundleAndMockDevProperties();
+
+ // pretend there is only a jar-bundle in the TP that has the same
+ // name and version like a woven plug-in from the host
+ mockTPWithBundles(List.of( //
+ bundle(HOST_BUNDLE_ID, "1.0.0")));
+
+ IPluginModelBase tpModel = findTargetModel(HOST_BUNDLE_ID, "1.0.0");
+
+ Properties devProperties = createDevEntryProperties(List.of(tpModel));
+
+ assertEquals("true", devProperties.getProperty("@ignoredot@"));
+ assertNull(devProperties.getProperty(HOST_BUNDLE_ID));
+ assertEquals(1, devProperties.size()); // assert no more entries
+ }
+
+ @Test
+ public void testGetDevProperties_jarTPBundleWithSameVersionLikeHostBundle_noDevEntries() throws Exception {
+
+ Bundle hostBundle = getHostBundleAndMockDevProperties();
+ String hostBundleVersion = hostBundle.getVersion().toString();
+
+ // pretend there is only a jar-bundle in the TP that has the same
+ // name and version like a woven plug-in from the host
+ mockTPWithBundles(List.of( //
+ bundle(HOST_BUNDLE_ID, hostBundleVersion)));
+
+ IPluginModelBase hostModel = findTargetModel(HOST_BUNDLE_ID, hostBundleVersion);
+
+ Properties devProperties = createDevEntryProperties(List.of(hostModel));
+
+ assertEquals("true", devProperties.getProperty("@ignoredot@"));
+ assertNull(devProperties.getProperty(HOST_BUNDLE_ID));
+ assertEquals(1, devProperties.size()); // assert no more entries
+ }
+
+ @Test
+ public void testGetDevProperties_workspaceAndJarTPBundle_oneEmptyDevEntryAndOneWithAndWithoutVersion()
+ throws Exception {
+
+ getHostBundleAndMockDevProperties();
+
+ mockTPWithBundles(List.of( //
+ bundle(HOST_BUNDLE_ID, "1.0.0")));
+
+ IPluginModelBase hostModel = findTargetModel(HOST_BUNDLE_ID, "1.0.0");
+ IPluginModelBase wsModel = findWorkspaceModel(HOST_BUNDLE_ID, "2.0.0");
+
+ Properties devProperties = createDevEntryProperties(List.of(hostModel, wsModel));
+
+ assertEquals("true", devProperties.getProperty("@ignoredot@"));
+ assertEquals("bin", devProperties.getProperty(HOST_BUNDLE_ID));
+ assertEquals(2, devProperties.size()); // assert no more entries
+ }
+
+ @Test
+ public void testGetDevProperties_HostAndJarBundle_oneEmptyDevEntryAndOneWithAndWithoutVersion() throws Exception {
+
+ Bundle hostBundle = getHostBundleAndMockDevProperties();
+ String hostBundleVersion = hostBundle.getVersion().toString();
+
+ mockTPWithRunningPlatformAndBundles(List.of( //
+ bundle(HOST_BUNDLE_ID, "1.0.0")));
+
+ IPluginModelBase hostModel = findTargetModel(HOST_BUNDLE_ID, hostBundleVersion);
+ IPluginModelBase tpModel = findTargetModel(HOST_BUNDLE_ID, "1.0.0");
+
+ Properties devProperties = createDevEntryProperties(List.of(tpModel, hostModel));
+
+ assertEquals("true", devProperties.getProperty("@ignoredot@"));
+ assertEquals("devPath1", devProperties.getProperty(HOST_BUNDLE_ID));
+ assertEquals(2, devProperties.size()); // assert no more entries
+ }
+
+ @Test
+ public void testGetDevProperties_workspaceAndHostBundle_twoDevEntriesWithAndWithoutVersion() throws Exception {
+
+ Bundle hostBundle = getHostBundleAndMockDevProperties();
+ String hostBundleVersion = hostBundle.getVersion().toString();
+
+ mockTPWithRunningPlatformAndBundles(List.of()); // running-platform only
+
+ IPluginModelBase hostModel = findTargetModel(HOST_BUNDLE_ID, hostBundleVersion);
+ IPluginModelBase wsModel = findWorkspaceModel(HOST_BUNDLE_ID, "2.0.0");
+
+ Properties devProperties = createDevEntryProperties(List.of(hostModel, wsModel));
+
+ assertEquals("true", devProperties.getProperty("@ignoredot@"));
+ assertEquals("bin", devProperties.getProperty(HOST_BUNDLE_ID));
+ assertEquals(2, devProperties.size()); // assert no more entries
+ }
+
+ @Test
+ public void testGetDevProperties_mixedWorkspaceAndHostAndJarTPBundle_onlyUsedPlatformBundles() throws Exception {
+
+ Bundle hostBundle = getHostBundleAndMockDevProperties();
+ String hostBundleVersion = hostBundle.getVersion().toString();
+
+ mockTPWithRunningPlatformAndBundles(List.of( //
+ bundle(HOST_BUNDLE_ID, "1.0.0")));
+
+ IPluginModelBase hostModel = findTargetModel(HOST_BUNDLE_ID, hostBundleVersion);
+ IPluginModelBase tpModel = findTargetModel(HOST_BUNDLE_ID, "1.0.0");
+ IPluginModelBase wsModel = findWorkspaceModel(HOST_BUNDLE_ID, "2.0.0");
+
+ Properties devProperties = createDevEntryProperties(List.of(hostModel, tpModel, wsModel));
+
+ assertEquals("true", devProperties.getProperty("@ignoredot@"));
+ assertEquals("bin", devProperties.getProperty(HOST_BUNDLE_ID));
+ assertEquals(2, devProperties.size()); // assert no more entries
+ }
+
+ // --- utility methods ---
+
+ private static String setPlatformDevPropertiesURL(String string) throws ReflectiveOperationException {
+ // trigger properties reload on next use
+ setStaticField(TargetWeaver.class, "fgDevProperties", null);
+ return setStaticField(TargetWeaver.class, "fgDevPropertiesURL", string);
+ }
+
+ private static <V> V setStaticField(Class<?> cl, String fieldName, V newValue) throws ReflectiveOperationException {
+ Field field = cl.getDeclaredField(fieldName);
+ field.trySetAccessible();
+ @SuppressWarnings("unchecked")
+ V oldValue = (V) field.get(null);
+ field.set(null, newValue);
+ return oldValue;
+ }
+
+ private static void createWorkspacePluginProjects(List<NameVersionDescriptor> workspacePlugins)
+ throws CoreException {
+ List<IProject> pluginProjects = ProjectUtils.createWorkspacePluginProjects(workspacePlugins);
+ while (pluginProjects.stream().anyMatch(ClasspathResolverTest::isUpdatePending)) {
+ Thread.yield(); // await async classpath update of projects
+ }
+ }
+
+ private static boolean isUpdatePending(IProject project) {
+ IJavaProject jProject = JavaCore.create(project);
+ try {
+ IPath outputLocation = jProject.getOutputLocation();
+ return outputLocation == null || project.findMember(outputLocation.removeFirstSegments(1)) == null;
+ } catch (JavaModelException e) {
+ return false;
}
}
+ private Bundle getHostBundleAndMockDevProperties() throws IOException {
+ Bundle hostBundle = Platform.getBundle(HOST_BUNDLE_ID);
+ Files.write(mockedPlatformDevPropertiesFile, List.of( //
+ HOST_BUNDLE_ID + "=devPath1", //
+ HOST_BUNDLE_ID + ";" + hostBundle.getVersion() + "=devPath2", //
+ "some.other.plugin=devPath3", //
+ "some.other.plugin;2.0.0=devPath4"));
+ return hostBundle;
+ }
+
+ private void mockTPWithBundles(List<NameVersionDescriptor> targetBundles) throws IOException, InterruptedException {
+ Path jarsDirectory = tempFolder.newFolder("TPJarsDirectory").toPath();
+ TargetPlatformUtil.setDummyBundlesAsTarget(targetBundles, jarsDirectory);
+ }
+
+ private void mockTPWithRunningPlatformAndBundles(List<NameVersionDescriptor> targetBundles)
+ throws IOException, InterruptedException {
+ Path jarsDirectory = tempFolder.newFolder("TPJarsDirectory").toPath();
+ TargetPlatformUtil.setRunningPlatformWithDummyBundlesAsTarget(targetBundles, jarsDirectory,
+ b -> b.getSymbolicName().equals(HOST_BUNDLE_ID));
+ }
+
+ private static NameVersionDescriptor bundle(String id, String version) {
+ return new NameVersionDescriptor(id, version);
+ }
+
+ private Properties createDevEntryProperties(List<IPluginModelBase> launchedBundles)
+ throws IOException, CoreException {
+ File devPropertiesFile = tempFolder.newFile("dev.properties").getCanonicalFile();
+ Map<String, IPluginModelBase> bundlesMap = Map.of(HOST_BUNDLE_ID,
+ launchedBundles.get(launchedBundles.size() - 1));
+ String devPropertiesURL = ClasspathHelper.getDevEntriesProperties(devPropertiesFile.getPath(), bundlesMap);
+ return loadProperties(devPropertiesURL);
+ }
+
+ private static Properties loadProperties(String devPropertiesURL) throws IOException {
+ File propertiesFile = new File(new URL(devPropertiesURL).getPath());
+ Properties devProperties = new Properties();
+ try (InputStream stream = new FileInputStream(propertiesFile)) {
+ devProperties.load(stream);
+ }
+ return devProperties;
+ }
}
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/AbstractLaunchTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/AbstractLaunchTest.java
index 064fd2701a..9203ea4576 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/AbstractLaunchTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/AbstractLaunchTest.java
@@ -11,117 +11,55 @@
* Contributors:
* Julian Honnen <julian.honnen@vector.com> - initial API and implementation
* Andras Peteri <apeteri@b2international.com> - extracted common superclass
- * Hannes Wellmann - Bug 577116: Improve test utility method reusability
+ * Hannes Wellmann - Bug 577116 - Improve test utility method reusability
+ * Hannes Wellmann - Bug 577629 - Unify project creation/deletion in tests
*******************************************************************************/
package org.eclipse.pde.ui.tests.launcher;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import java.io.InputStream;
-import java.net.URL;
-import java.nio.file.Path;
-import java.util.*;
+import java.util.Arrays;
+import java.util.NoSuchElementException;
import java.util.function.Function;
import java.util.stream.Stream;
-import org.eclipse.core.resources.*;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.resources.IProject;
import org.eclipse.debug.core.*;
import org.eclipse.pde.core.plugin.*;
-import org.eclipse.pde.core.project.IBundleProjectDescription;
-import org.eclipse.pde.ui.tests.project.ProjectCreationTests;
+import org.eclipse.pde.ui.tests.util.ProjectUtils;
import org.eclipse.pde.ui.tests.util.TargetPlatformUtil;
import org.junit.*;
import org.junit.rules.TestRule;
-import org.osgi.framework.*;
+import org.osgi.framework.Version;
public abstract class AbstractLaunchTest {
@ClassRule
public static final TestRule RESTORE_TARGET_DEFINITION = TargetPlatformUtil.RESTORE_CURRENT_TARGET_DEFINITION_AFTER;
+ @ClassRule
+ public static final TestRule CLEAR_WORKSPACE = ProjectUtils.DELETE_ALL_WORKSPACE_PROJECTS_BEFORE_AND_AFTER;
private static IProject launchConfigsProject;
@BeforeClass
public static void setupTargetPlatform() throws Exception {
- deleteProjects(Set.of()); // Clean-up garbage of other test-classes
TargetPlatformUtil.setRunningPlatformAsTarget();
- setupLaunchConfigurations();
- }
-
- private static void setupLaunchConfigurations() throws Exception {
- launchConfigsProject = getProject(AbstractLaunchTest.class.getSimpleName());
- launchConfigsProject.create(null);
- launchConfigsProject.open(null);
- Bundle bundle = FrameworkUtil.getBundle(AbstractLaunchTest.class);
- List<URL> resources = Collections.list(bundle.findEntries("tests/launch", "*", false));
- for (URL url : resources) {
- Path path = Path.of(FileLocator.toFileURL(url).toURI());
- IFile file = launchConfigsProject.getFile(path.getFileName().toString());
- try (InputStream in = url.openStream()) {
- file.create(in, true, null);
- }
- }
- }
-
- @AfterClass
- public static void restoreInitialWorkspaceState() throws Exception {
- deleteProjects(Set.of());
- }
-
- private Set<IProject> projectsBefore;
-
- @Before
- public void storeExistingProjects() {
- projectsBefore = Set.of(ResourcesPlugin.getWorkspace().getRoot().getProjects());
- }
-
- @After
- public void deleteCreatedProjects() throws CoreException {
- deleteProjects(projectsBefore);
+ launchConfigsProject = ProjectUtils.importTestProject("tests/launch");
}
- private static void deleteProjects(Set<IProject> retainedProjects) throws CoreException {
- IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
- for (IProject project : projects) {
- if (retainedProjects.stream().noneMatch(s -> s.contains(project))) {
- project.delete(true, true, null);
- }
- }
- }
+ @Rule
+ public final TestRule deleteCreatedTestProjectsAfter = ProjectUtils.DELETE_CREATED_WORKSPACE_PROJECTS_AFTER;
protected ILaunchConfiguration getLaunchConfiguration(String name) {
ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
return launchManager.getLaunchConfiguration(launchConfigsProject.getFile(name));
}
- protected static IProject createPluginProject(String projectName, String bundleSymbolicName, String version)
- throws CoreException {
- IProject project = getProject(projectName);
-
- IBundleProjectDescription description = ProjectCreationTests.getBundleProjectService().getDescription(project);
- description.setSymbolicName(bundleSymbolicName);
- if (version != null) {
- description.setBundleVersion(Version.parseVersion(version));
- }
- description.apply(null);
- return project;
- }
-
- private static IProject getProject(String projectName) throws CoreException {
- IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
- if (project.exists()) {
- project.delete(true, null);
- }
- return project;
- }
-
- protected static IPluginModelBase findWorkspaceModel(String id, String version) {
+ public static IPluginModelBase findWorkspaceModel(String id, String version) {
return getModel(id, version, ModelEntry::getWorkspaceModels, "workspace");
}
- protected static IPluginModelBase findTargetModel(String id, String version) {
+ public static IPluginModelBase findTargetModel(String id, String version) {
return getModel(id, version, ModelEntry::getExternalModels, "target");
}
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/LaunchConfigurationMigrationTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/LaunchConfigurationMigrationTest.java
index 54216b4dd4..8b57ff6466 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/LaunchConfigurationMigrationTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/LaunchConfigurationMigrationTest.java
@@ -25,6 +25,7 @@ import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper;
import org.eclipse.pde.launching.IPDELauncherConstants;
+import org.eclipse.pde.ui.tests.util.ProjectUtils;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -32,8 +33,8 @@ public class LaunchConfigurationMigrationTest extends AbstractLaunchTest {
@BeforeClass
public static void setupPluginProjects() throws Exception {
- createPluginProject("org.eclipse.pde.plugin1", "org.eclipse.pde.plugin1", null);
- createPluginProject("org.eclipse.pde.plugin2", "org.eclipse.pde.plugin2", null);
+ ProjectUtils.createPluginProject("org.eclipse.pde.plugin1", "org.eclipse.pde.plugin1", null);
+ ProjectUtils.createPluginProject("org.eclipse.pde.plugin2", "org.eclipse.pde.plugin2", null);
}
@Test
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/PluginBasedLaunchTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/PluginBasedLaunchTest.java
index ef649784df..58e69c350d 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/PluginBasedLaunchTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/PluginBasedLaunchTest.java
@@ -26,6 +26,7 @@ import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.target.NameVersionDescriptor;
import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper;
import org.eclipse.pde.launching.IPDELauncherConstants;
+import org.eclipse.pde.ui.tests.util.ProjectUtils;
import org.eclipse.pde.ui.tests.util.TargetPlatformUtil;
import org.junit.*;
import org.junit.rules.TemporaryFolder;
@@ -243,7 +244,7 @@ public class PluginBasedLaunchTest extends AbstractLaunchTest {
@Test
public void testGetMergedBundleMap_multipleWorkspacePluginVersions_sameVersion() throws Exception {
- createPluginProject("another.project", "plugin.a", "1.0.0");
+ ProjectUtils.createPluginProject("another.project", "plugin.a", "1.0.0");
List<NameVersionDescriptor> workspacePlugins = List.of( //
bundle("plugin.a", "1.0.0"));
List<NameVersionDescriptor> targetPlatformBundles = List.of( //
@@ -839,12 +840,7 @@ public class PluginBasedLaunchTest extends AbstractLaunchTest {
private void setUpWorkspace(List<NameVersionDescriptor> workspacePlugins, List<NameVersionDescriptor> targetPlugins)
throws CoreException, IOException, InterruptedException {
- for (NameVersionDescriptor pluginDescription : workspacePlugins) {
- String bundleSymbolicName = pluginDescription.getId();
- String bundleVersion = pluginDescription.getVersion();
- String projectName = bundleSymbolicName + bundleVersion.replace('.', '_');
- createPluginProject(projectName, bundleSymbolicName, bundleVersion);
- }
+ ProjectUtils.createWorkspacePluginProjects(workspacePlugins);
TargetPlatformUtil.setDummyBundlesAsTarget(targetPlugins, tpJarDirectory);
}
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/project/DynamicPluginProjectReferencesTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/project/DynamicPluginProjectReferencesTest.java
index 436a966da3..da20f3a3ef 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/project/DynamicPluginProjectReferencesTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/project/DynamicPluginProjectReferencesTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2019 Julian Honnen
+ * Copyright (c) 2019, 2021 Julian Honnen
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -25,15 +25,14 @@ import org.eclipse.pde.core.plugin.PluginRegistry;
import org.eclipse.pde.internal.ui.wizards.imports.PluginImportOperation;
import org.eclipse.pde.ui.tests.util.ProjectUtils;
import org.junit.*;
+import org.junit.rules.TestRule;
public class DynamicPluginProjectReferencesTest {
- @After
- public void clearWorkspace() throws Exception {
- for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
- project.delete(false, true, null);
- }
- }
+ @ClassRule
+ public static final TestRule CLEAR_WORKSPACE = ProjectUtils.DELETE_ALL_WORKSPACE_PROJECTS_BEFORE_AND_AFTER;
+ @Rule
+ public final TestRule deleteCreatedTestProjectsAfter = ProjectUtils.DELETE_CREATED_WORKSPACE_PROJECTS_AFTER;
@Test
public void testFragmentHost_required() throws Exception {
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/runtime/TestUtils.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/runtime/TestUtils.java
index 04538c00cb..ad0a5167b0 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/runtime/TestUtils.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/runtime/TestUtils.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2017 IBM Corporation and others.
+ * Copyright (c) 2008, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -12,35 +12,29 @@
* IBM Corporation - initial API and implementation
* Stefan Xenos (Google) - Initial implementation
* Andrey Loskutov (loskutov@gmx.de) - many different extensions
+ * Hannes Wellmann - Bug 577629 - Unify project creation/deletion in tests
*******************************************************************************/
package org.eclipse.pde.ui.tests.runtime;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.util.*;
-import java.util.function.Function;
-import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.pde.ui.tests.PDETestsPlugin;
import org.eclipse.swt.widgets.Display;
import org.junit.Assert;
+import org.junit.jupiter.api.function.ThrowingConsumer;
+import org.junit.jupiter.api.function.ThrowingSupplier;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.MultipleFailureException;
+import org.junit.runners.model.Statement;
/**
* Utility methods for JUnit tests.
*/
public class TestUtils {
- public static IExtensionPoint getExtensionPoint(String extensionPointId) {
- return Platform.getExtensionRegistry().getExtensionPoint(extensionPointId);
- }
-
- public static IExtension getExtension(String extensionId) {
- return Platform.getExtensionRegistry().getExtension(extensionId);
- }
-
- public static String findPath(String path) {
- return FileLocator.find(PDETestsPlugin.getBundleContext().getBundle(), new Path(path), Collections.emptyMap())
- .toString();
- }
/**
* Call this in the tearDown method of every test to clean up state that can
@@ -110,47 +104,6 @@ public class TestUtils {
}
/**
- * Waits while given condition is {@code true} for a given amount of
- * milliseconds. If the actual wait time exceeds given timeout and condition
- * will be still {@code true}, throws {@link AssertionError} with given
- * message.
- * <p>
- * Will process UI events while waiting in UI thread, if called from
- * background thread, just waits.
- *
- * @param <T>
- * type of the context
- * @param context
- * test context
- * @param condition
- * function which will be evaluated while waiting
- * @param timeout
- * max wait time in milliseconds to wait on given condition
- * @param errorMessage
- * message which will be used to construct the failure exception
- * in case the condition will still return {@code true} after
- * given timeout
- */
- public static <T> void waitWhile(Function<T, Boolean> condition, T context, long timeout,
- Function<T, String> errorMessage) throws Exception {
- long start = System.currentTimeMillis();
- Display display = Display.getCurrent();
- while (System.currentTimeMillis() - start < timeout && condition.apply(context)) {
- if (display != null && !display.isDisposed()) {
- if (!display.readAndDispatch()) {
- Thread.sleep(0);
- }
- } else {
- Thread.sleep(5);
- }
- }
- Boolean stillTrue = condition.apply(context);
- if (stillTrue) {
- Assert.fail(errorMessage.apply(context));
- }
- }
-
- /**
* Utility for waiting until the execution of jobs of any family has
* finished or timeout is reached. If no jobs are running, the method waits
* given minimum wait time. While this method is waiting for jobs, UI events
@@ -290,4 +243,43 @@ public class TestUtils {
}
return false;
}
+
+ /**
+ * Returns a TestRule similar to {@link org.junit.rules.ExternalResource}
+ * but allows throwing unchecked exception in its
+ * {@link org.junit.rules.ExternalResource#after()} method. Furthermore
+ * {@code before} and {@code after} are expressed by the specified actions
+ * that may throw exceptions and can share a state.
+ *
+ * @param before
+ * the action performed before the evaluation
+ * @param after
+ * the action performed after the evaluation (only called if the
+ * {@code before} action did not throw)
+ * @return a rule performing the given before respectively after action
+ * before/after the evaluation of the base
+ * @param <S>
+ * the type of state shared between before and after action
+ */
+ public static <S> TestRule getThrowingTestRule(ThrowingSupplier<S> before, ThrowingConsumer<S> after) {
+ return (base, description) -> new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ S state = before.get();
+ List<Throwable> errors = new ArrayList<>();
+ try {
+ base.evaluate();
+ } catch (Throwable t) {
+ errors.add(t);
+ } finally {
+ try {
+ after.accept(state);
+ } catch (Throwable t) {
+ errors.add(t);
+ }
+ }
+ MultipleFailureException.assertEmpty(errors);
+ }
+ };
+ }
}
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/ProjectUtils.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/ProjectUtils.java
index 0a1b088baa..7ededbe5de 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/ProjectUtils.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/ProjectUtils.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2015 IBM Corporation and others.
+ * Copyright (c) 2008, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,24 +10,32 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Hannes Wellmann - Bug 577629 - Unify project creation/deletion in tests
*******************************************************************************/
package org.eclipse.pde.ui.tests.util;
import java.io.IOException;
import java.net.URL;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
+import org.eclipse.pde.core.project.IBundleProjectDescription;
+import org.eclipse.pde.core.target.NameVersionDescriptor;
import org.eclipse.pde.internal.ui.wizards.IProjectProvider;
import org.eclipse.pde.internal.ui.wizards.plugin.NewProjectCreationOperation;
import org.eclipse.pde.internal.ui.wizards.plugin.PluginFieldData;
import org.eclipse.pde.ui.IBundleContentWizard;
import org.eclipse.pde.ui.templates.AbstractNewPluginTemplateWizard;
import org.eclipse.pde.ui.templates.ITemplateSection;
+import org.eclipse.pde.ui.tests.project.ProjectCreationTests;
import org.eclipse.pde.ui.tests.runtime.TestUtils;
+import org.junit.rules.TestRule;
import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.Version;
/**
* Utility class for project related operations
@@ -130,21 +138,99 @@ public class ProjectUtils {
return javaProject;
}
+ private static final Set<IProject> IMPORTED_PROJECTS = ConcurrentHashMap.newKeySet();
+
public static IProject importTestProject(String path) throws IOException, CoreException {
URL entry = FileLocator.toFileURL(FrameworkUtil.getBundle(ProjectUtils.class).getEntry(path));
if (entry == null) {
throw new IllegalArgumentException(path + " does not exist");
}
- Path src = new Path(entry.getPath());
-
- IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
- IProjectDescription projectDescription = ResourcesPlugin.getWorkspace()
- .loadProjectDescription(src.append(IProjectDescription.DESCRIPTION_FILE_NAME));
- IProject project = root.getProject(projectDescription.getName());
+ IPath projectFile = Path.fromPortableString(entry.getPath()).append(IProjectDescription.DESCRIPTION_FILE_NAME);
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ IProjectDescription projectDescription = workspace.loadProjectDescription(projectFile);
+ IProject project = workspace.getRoot().getProject(projectDescription.getName());
project.create(projectDescription, null);
project.open(null);
+ IMPORTED_PROJECTS.add(project);
+ return project;
+ }
+ public static List<IProject> createWorkspacePluginProjects(List<NameVersionDescriptor> workspacePlugins)
+ throws CoreException {
+ List<IProject> projects = new ArrayList<>();
+ for (NameVersionDescriptor pluginDescription : workspacePlugins) {
+ String bundleSymbolicName = pluginDescription.getId();
+ String bundleVersion = pluginDescription.getVersion();
+ String projectName = bundleSymbolicName + bundleVersion.replace('.', '_');
+ projects.add(createPluginProject(projectName, bundleSymbolicName, bundleVersion));
+ }
+ return projects;
+ }
+
+ public static IProject createPluginProject(String projectName, String bundleSymbolicName, String version)
+ throws CoreException {
+ IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+ IBundleProjectDescription description = ProjectCreationTests.getBundleProjectService().getDescription(project);
+ description.setSymbolicName(bundleSymbolicName);
+ if (version != null) {
+ description.setBundleVersion(Version.parseVersion(version));
+ }
+ description.apply(null);
return project;
}
+ /**
+ * An (intended) {@link org.junit.ClassRule} that deletes all projects from
+ * the test-workspace before and after all tests are executed.
+ * <p>
+ * The intention is to ensure that the workspace is empty before the first
+ * method (static or not) of a test-class is called as well it is cleared
+ * after the last method has returned.
+ * </p>
+ * <p>
+ * For projects that are imported via {@link #importTestProject(String)} the
+ * content is not deleted, for other projects the content is deleted. This
+ * assumes that imported projects are resources in this Test-plugin while
+ * other projects are virtual and can safely be deleted.
+ * </p>
+ */
+ public static final TestRule DELETE_ALL_WORKSPACE_PROJECTS_BEFORE_AND_AFTER = TestUtils.getThrowingTestRule( //
+ () -> { // Clean-up garbage of other test-classes
+ ProjectUtils.deleteWorkspaceProjects(Set.of());
+ return null;
+ }, o -> deleteWorkspaceProjects(Set.of()));
+
+ /**
+ * An (intended) {@link org.junit.Rule} that deletes the projects from the
+ * test-workspace , that where created during the test-case execution, after
+ * each test-case.
+ * <p>
+ * The intention is to delete those projects from the workspace that were
+ * created during the execution of a test-case, but to retain those that
+ * existed before (e.g. were created in a static initializer).
+ * </p>
+ * <p>
+ * For projects that are imported via {@link #importTestProject(String)} the
+ * content is not deleted, for other projects the content is deleted. This
+ * assumes that imported projects are resources in this Test-plugin while
+ * other projects are virtual and can safely be deleted.
+ * </p>
+ */
+ public static final TestRule DELETE_CREATED_WORKSPACE_PROJECTS_AFTER = TestUtils.getThrowingTestRule( //
+ () -> Set.of(ResourcesPlugin.getWorkspace().getRoot().getProjects()), //
+ projectsBefore -> deleteWorkspaceProjects(projectsBefore));
+
+ private static void deleteWorkspaceProjects(Set<IProject> retainedProjects) throws CoreException {
+ IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
+ for (IProject project : projects) {
+ if (!retainedProjects.contains(project)) {
+ boolean isImportedProject = IMPORTED_PROJECTS.remove(project);
+ // Don't delete content of imported projects because they are
+ // resources of this test plug-in and must not be deleted
+ project.delete(!isImportedProject, true, null);
+ }
+ }
+ // back-up, should not change anything if everything is properly used
+ IMPORTED_PROJECTS.retainAll(retainedProjects);
+ }
}
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/TargetPlatformUtil.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/TargetPlatformUtil.java
index 12c2869075..759d37efb1 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/TargetPlatformUtil.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/util/TargetPlatformUtil.java
@@ -22,59 +22,58 @@ import java.nio.file.Path;
import java.util.*;
import java.util.function.Predicate;
import java.util.jar.*;
+import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.pde.core.target.*;
import org.eclipse.pde.internal.core.PDECore;
+import org.eclipse.pde.ui.tests.runtime.TestUtils;
import org.junit.rules.TestRule;
-import org.junit.runners.model.MultipleFailureException;
-import org.junit.runners.model.Statement;
import org.osgi.framework.*;
public class TargetPlatformUtil {
- public static final TestRule RESTORE_CURRENT_TARGET_DEFINITION_AFTER = (base, description) -> new Statement() {
- @Override
- public void evaluate() throws Throwable {
- ITargetPlatformService tps = PDECore.getDefault().acquireService(ITargetPlatformService.class);
- ITargetDefinition beforeTarget = null;
- List<Throwable> errors = new ArrayList<>();
- try {
- beforeTarget = tps.getWorkspaceTargetDefinition();
-
- base.evaluate();
- } catch (Throwable t) {
- errors.add(t);
- } finally {
- try {
- if (beforeTarget != null && beforeTarget != tps.getWorkspaceTargetDefinition()) {
- TargetPlatformUtil.loadAndSetTargetForWorkspace(beforeTarget);
- }
- } catch (Throwable t) {
- errors.add(t);
+ public static final ITargetPlatformService TPS = PDECore.getDefault().acquireService(ITargetPlatformService.class);
+ public static final TestRule RESTORE_CURRENT_TARGET_DEFINITION_AFTER = TestUtils.getThrowingTestRule(
+ TPS::getWorkspaceTargetDefinition, //
+ beforeTarget -> {
+ if (beforeTarget != TPS.getWorkspaceTargetDefinition()) {
+ TargetPlatformUtil.loadAndSetTargetForWorkspace(beforeTarget);
}
- }
- MultipleFailureException.assertEmpty(errors);
- }
- };
+ });
- private static final String TARGET_NAME = TargetPlatformUtil.class + "_target";
+ private static final String RUNNING_PLATFORM_TARGET_NAME = TargetPlatformUtil.class + "_RunningPlatformTarget";
public static void setRunningPlatformAsTarget() throws IOException, CoreException, InterruptedException {
- setRunningPlatformSubSetAsTarget(TARGET_NAME, null);
+ setRunningPlatformSubSetAsTarget(RUNNING_PLATFORM_TARGET_NAME, null);
}
public static void setRunningPlatformSubSetAsTarget(String name, Predicate<Bundle> bundleFilter)
throws IOException, CoreException, InterruptedException {
- ITargetPlatformService tps = PDECore.getDefault().acquireService(ITargetPlatformService.class);
- ITargetDefinition currentTarget = tps.getWorkspaceTargetDefinition();
+ ITargetDefinition currentTarget = TPS.getWorkspaceTargetDefinition();
if (name.equals(currentTarget.getName())) {
return;
}
- ITargetDefinition target = createRunningPlatformSubSetTarget(tps, name, bundleFilter);
- loadAndSetTargetForWorkspace(target);
+ List<ITargetLocation> bundleContainers = new ArrayList<>();
+ List<NameVersionDescriptor> included = new ArrayList<>();
+ addRunningPlatformBundles(bundleContainers, included, bundleFilter);
+ createAndSetTargetForWorkspace(name, bundleContainers, included);
+ }
+
+ public static void setRunningPlatformWithDummyBundlesAsTarget(List<NameVersionDescriptor> targetPlugins,
+ Path jarDirectory, Predicate<Bundle> bundleFilter) throws IOException, InterruptedException {
+ Set<ITargetLocation> locations = new LinkedHashSet<>();
+ Set<NameVersionDescriptor> included = new LinkedHashSet<>();
+
+ addRunningPlatformBundles(locations, included, bundleFilter);
+
+ ITargetLocation location = createDummyBundlesLocation(targetPlugins, jarDirectory);
+ locations.add(location);
+ included.addAll(targetPlugins);
+
+ createAndSetTargetForWorkspace(null, locations, included);
}
public static void loadAndSetTargetForWorkspace(ITargetDefinition target) throws InterruptedException {
@@ -88,48 +87,54 @@ public class TargetPlatformUtil {
}
}
- private static ITargetDefinition createRunningPlatformSubSetTarget(ITargetPlatformService tps, String name,
- Predicate<Bundle> bundleFilter) throws IOException, CoreException {
- ITargetDefinition targetDefinition = tps.newTarget();
- targetDefinition.setName(TARGET_NAME);
-
+ private static void addRunningPlatformBundles(Collection<ITargetLocation> bundleContainers,
+ Collection<NameVersionDescriptor> included, Predicate<Bundle> bundleFilter) throws IOException {
Bundle[] installedBundles = FrameworkUtil.getBundle(TargetPlatformUtil.class).getBundleContext().getBundles();
- Bundle[] targetBundles = bundleFilter != null
- ? Arrays.stream(installedBundles).filter(bundleFilter).toArray(Bundle[]::new)
- : installedBundles;
+ List<Bundle> targetBundles = Arrays.asList(installedBundles);
+ if (bundleFilter != null) {
+ targetBundles = targetBundles.stream().filter(bundleFilter).collect(Collectors.toList());
+ }
Set<File> bundleContainerDirectories = new HashSet<>();
for (Bundle bundle : targetBundles) {
File bundleContainer = FileLocator.getBundleFile(bundle).getParentFile();
bundleContainerDirectories.add(bundleContainer);
}
- ITargetLocation[] bundleContainers = bundleContainerDirectories.stream()
- .map(dir -> tps.newDirectoryLocation(dir.getAbsolutePath())).toArray(ITargetLocation[]::new);
-
- // always only include targetBundles bundles to speed up resolution in
- // cases where large bundle-pools with many other bundles are used,
- // e.g. when one uses a Eclipse provisioned by Oomph
- NameVersionDescriptor[] included = Arrays.stream(targetBundles)
- .map(b -> new NameVersionDescriptor(b.getSymbolicName(), b.getVersion().toString()))
- .toArray(NameVersionDescriptor[]::new);
- targetDefinition.setIncluded(included);
-
- setTargetProperties(targetDefinition, bundleContainers);
+ bundleContainerDirectories.stream().map(dir -> TPS.newDirectoryLocation(dir.getAbsolutePath()))
+ .forEach(bundleContainers::add);
- tps.saveTargetDefinition(targetDefinition);
- return targetDefinition;
+ for (Bundle bundle : targetBundles) {
+ included.add(new NameVersionDescriptor(bundle.getSymbolicName(), bundle.getVersion().toString()));
+ }
}
- public static void setTargetProperties(ITargetDefinition targetDefinition, ITargetLocation[] bundleContainers) {
- targetDefinition.setTargetLocations(bundleContainers);
+ public static void createAndSetTargetForWorkspace(String name, Collection<ITargetLocation> locations,
+ Collection<NameVersionDescriptor> includedBundles) throws InterruptedException {
+ ITargetDefinition targetDefinition = TPS.newTarget();
+ targetDefinition.setName(name);
targetDefinition.setArch(Platform.getOSArch());
targetDefinition.setOS(Platform.getOS());
targetDefinition.setWS(Platform.getWS());
targetDefinition.setNL(Platform.getNL());
+ targetDefinition.setTargetLocations(locations.toArray(ITargetLocation[]::new));
+
+ // only include intended target bundles to speed up resolution in cases
+ // where direction-location points into large bundle-pools with many
+ // other bundles, e.g. when one uses a Eclipse provisioned by Oomph
+ if (includedBundles != null) {
+ targetDefinition.setIncluded(includedBundles.toArray(NameVersionDescriptor[]::new));
+ }
+ loadAndSetTargetForWorkspace(targetDefinition);
}
public static void setDummyBundlesAsTarget(List<NameVersionDescriptor> targetPlugins, Path jarDirectory)
- throws IOException, CoreException, InterruptedException {
+ throws IOException, InterruptedException {
+ ITargetLocation location = createDummyBundlesLocation(targetPlugins, jarDirectory);
+ createAndSetTargetForWorkspace(null, List.of(location), targetPlugins);
+ }
+
+ private static ITargetLocation createDummyBundlesLocation(List<NameVersionDescriptor> targetPlugins,
+ Path jarDirectory) throws IOException {
for (NameVersionDescriptor bundleNameVersion : targetPlugins) {
Manifest manifest = createDummyBundleManifest(bundleNameVersion.getId(), bundleNameVersion.getVersion());
@@ -142,20 +147,12 @@ public class TargetPlatformUtil {
try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(jarPath));) {
out.putNextEntry(new ZipEntry(JarFile.MANIFEST_NAME));
manifest.write(out);
-
}
}
- ITargetPlatformService tps = PDECore.getDefault().acquireService(ITargetPlatformService.class);
- ITargetDefinition target = tps.newTarget();
-
- ITargetLocation location1 = tps.newDirectoryLocation(jarDirectory.toString());
-
- setTargetProperties(target, new ITargetLocation[] { location1 });
- tps.saveTargetDefinition(target);
- loadAndSetTargetForWorkspace(target);
+ return TPS.newDirectoryLocation(jarDirectory.toString());
}
- public static Manifest createDummyBundleManifest(String bundleSymbolicName, String bundleVersion) {
+ private static Manifest createDummyBundleManifest(String bundleSymbolicName, String bundleVersion) {
Manifest manifest = new Manifest();
Attributes mainAttributes = manifest.getMainAttributes();
mainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
diff --git a/ui/org.eclipse.pde.ui.tests/tests/launch/.project b/ui/org.eclipse.pde.ui.tests/tests/launch/.project
new file mode 100644
index 0000000000..38254732ee
--- /dev/null
+++ b/ui/org.eclipse.pde.ui.tests/tests/launch/.project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>AbstractLaunchTest-launches</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ </natures>
+</projectDescription>
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/ManifestEditor.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/ManifestEditor.java
index 46ef04c753..4f46c14969 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/ManifestEditor.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/ManifestEditor.java
@@ -10,6 +10,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Christoph Läubrich - Bug 577637 - ManifestEditor must use Project-BundleRoot to open Manifest
*******************************************************************************/
package org.eclipse.pde.internal.ui.editor.plugin;
@@ -21,6 +22,7 @@ import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.MessageDialog;
@@ -109,7 +111,8 @@ public class ManifestEditor extends PDELauncherFormEditor implements IShowEditor
IResource resource = model.getUnderlyingResource();
if (resource == null)
return openExternalPlugin(new File(model.getInstallLocation()), filename);
- return openWorkspacePlugin(resource.getProject().getFile(filename));
+ IProject project = resource.getProject();
+ return openWorkspacePlugin(PDEProject.getBundleRelativeFile(project, new Path(filename)));
}
}
if (object instanceof BaseDescription) {

Back to the top