Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<feature
id="org.eclipse.pde.unittest.junit"
label="%featureName"
version="1.0.1100.qualifier"
version="1.0.1200.qualifier"
provider-name="%providerName"
license-feature="org.eclipse.license"
license-feature-version="0.0.0">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@

import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

Expand All @@ -37,6 +40,7 @@
import org.eclipse.osgi.service.debug.DebugOptions;
import org.eclipse.osgi.service.debug.DebugOptionsListener;
import org.eclipse.osgi.service.debug.DebugTrace;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.pde.core.IBundleClasspathResolver;
import org.eclipse.pde.core.IClasspathContributor;
import org.eclipse.pde.core.plugin.IPluginModelBase;
Expand All @@ -56,6 +60,7 @@
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.Version;
import org.osgi.util.tracker.ServiceTracker;

import aQute.bnd.build.Workspace;
Expand All @@ -80,6 +85,9 @@ public class PDECore extends Plugin implements DebugOptionsListener {

public static final QualifiedName SCHEMA_PREVIEW_FILE = new QualifiedName(PLUGIN_ID, "SCHEMA_PREVIEW_FILE"); //$NON-NLS-1$

public static final Comparator<IPluginModelBase> COMPARE_BY_VERSION = Comparator
.comparing(model -> PDECore.getOSGiVersion(model));

public static boolean DEBUG_CLASSPATH = false;
public static boolean DEBUG_MODEL = false;
public static boolean DEBUG_TARGET_PROFILE = false;
Expand All @@ -97,6 +105,7 @@ public class PDECore extends Plugin implements DebugOptionsListener {
private static final String VALIDATION_DEBUG = PLUGIN_ID + KEY_DEBUG_VALIDATION;
private static final String STATE_DEBUG = PLUGIN_ID + KEY_DEBUG_STATE;


// Shared instance
private static PDECore inst;

Expand All @@ -109,7 +118,7 @@ public class PDECore extends Plugin implements DebugOptionsListener {
*/
private static PDEPreferencesManager fPreferenceManager;

private Map<String, IPluginModelBase> fHostPlugins;
private Map<String, List<IPluginModelBase>> fHostPlugins;

public static PDECore getDefault() {
return inst;
Expand Down Expand Up @@ -221,15 +230,20 @@ public PDECore() {
inst = this;
}

public synchronized IPluginModelBase findPluginInHost(String id) {
public IPluginModelBase findPluginInHost(String id) {
return findPluginsInHost(id).max(Comparator.comparing(plugin -> {
return getOSGiVersion(plugin);
})).orElse(null);
}

public synchronized Stream<IPluginModelBase> findPluginsInHost(String id) {
if (fHostPlugins == null) {
fHostPlugins = new HashMap<>();

ITargetDefinition defaultTarget = TargetPlatformService.getDefault().newDefaultTarget();
IStatus status = defaultTarget.resolve(new NullProgressMonitor());
if (!status.isOK()) {
log(status);
return null;
return Stream.empty();
}

URI[] pluginPaths = Arrays.stream(defaultTarget.getBundles()) //
Expand All @@ -240,11 +254,22 @@ public synchronized IPluginModelBase findPluginInHost(String id) {
state.resolveState(false);

for (IPluginModelBase plugin : state.getTargetModels()) {
fHostPlugins.put(plugin.getPluginBase().getId(), plugin);
fHostPlugins.computeIfAbsent(plugin.getPluginBase().getId(), nil -> new ArrayList<>(1)).add(plugin);
}
}
List<IPluginModelBase> list = fHostPlugins.get(id);
if (list == null) {
return Stream.empty();
}
return list.stream();
}

return fHostPlugins.get(id);
public static Version getOSGiVersion(IPluginModelBase plugin) {
BundleDescription description = plugin.getBundleDescription();
if (description == null) {
return Version.emptyVersion;
}
return description.getVersion();
}

public PluginModelManager getModelManager() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
Expand Down Expand Up @@ -78,7 +80,11 @@
import org.eclipse.pde.internal.launching.PDELaunchingPlugin;
import org.eclipse.pde.internal.launching.PDEMessages;
import org.eclipse.pde.launching.IPDELauncherConstants;
import org.eclipse.pde.launching.JUnitLaunchConfigurationDelegate;
import org.osgi.framework.Version;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRequirement;
import org.osgi.resource.Resource;

public class BundleLauncherHelper {

Expand Down Expand Up @@ -831,6 +837,117 @@ public static Map<IPluginModelBase, AdditionalPluginData> getAdditionalPlugins(I
return resolvedAdditionalPlugins;
}

public static void addRequiredJunitRuntimePlugins(ILaunchConfiguration configuration, Map<String, List<IPluginModelBase>> collectedModels, Map<IPluginModelBase, String> startLevelMap) throws CoreException {
// First we collect all required plugins we need to launch the junit
// framework...
Collection<String> requiredJunitRuntimePlugins = JUnitLaunchConfigurationDelegate.getRequiredJunitRuntimePlugins(configuration);
List<IPluginModelBase> collected = new ArrayList<>(requiredJunitRuntimePlugins.size());
for (String id : requiredJunitRuntimePlugins) {
// we need to add them all to make sure the collection is complete for adding
// compatible ones...
addIfAbsent(id, collectedModels, startLevelMap).or(() -> collectedModels.getOrDefault(id, List.of()).stream().filter(m -> m.getBundleDescription().isResolved()).findFirst()).ifPresent(collected::add);
}
// Now collect the dependencies of the collected...
Set<BundleDescription> closure = DependencyManager.findRequirementsClosure(collected.stream().map(IPluginModelBase::getBundleDescription).toList());
for (BundleDescription description : closure) {
collected.add(addIfAbsent(description, collectedModels, startLevelMap));
}
// Now add any indirectly required items
if (collectedModels.containsKey("junit-platform-runner")) { //$NON-NLS-1$
Set<BundleDescription> additional = new HashSet<>();
addCompatible("junit-platform-launcher", collected, "org.junit.platform.launcher", collectedModels, startLevelMap).ifPresent(m -> additional.add(m.getBundleDescription())); //$NON-NLS-1$ //$NON-NLS-2$
addCompatible("junit-jupiter-engine", collected, "org.junit.platform.engine", collectedModels, startLevelMap).ifPresent(m -> additional.add(m.getBundleDescription())); //$NON-NLS-1$ //$NON-NLS-2$
if (!additional.isEmpty()) {
//final collection...
Iterator<BundleDescription> iterator = DependencyManager.findRequirementsClosure(additional).iterator();
while (iterator.hasNext()) {
addIfAbsent(iterator.next(), collectedModels, startLevelMap);
}
}
}
}

private static IPluginModelBase addIfAbsent(BundleDescription description, Map<String, List<IPluginModelBase>> fAllBundles, Map<IPluginModelBase, String> fModels) throws CoreException {
IPluginModelBase model = PluginRegistry.findModel((Resource) description);
if (model == null) {
Version version = description.getVersion();
model = PDECore.getDefault().findPluginsInHost(description.getSymbolicName()).filter(m -> version.equals(PDECore.getOSGiVersion(m))).findFirst().orElseThrow(() -> new CoreException(Status.error("Resolved bundle description " + description + " not found in target or host!"))); //$NON-NLS-1$//$NON-NLS-2$
}
List<IPluginModelBase> models = fAllBundles.computeIfAbsent(description.getSymbolicName(), k -> new ArrayList<>());
if (!models.contains(model)) {
models.add(model);
BundleLauncherHelper.addDefaultStartingBundle(fModels, model);
}
return model;
}

private static Optional<IPluginModelBase> addIfAbsent(String id, Map<String, List<IPluginModelBase>> fAllBundles, Map<IPluginModelBase, String> fModels) throws CoreException {
List<IPluginModelBase> models = fAllBundles.computeIfAbsent(id, k -> new ArrayList<>());
if (models.stream().noneMatch(m -> m.getBundleDescription().isResolved())) {
IPluginModelBase model = findRequiredPluginInTargetOrHost(id);
models.add(model);
BundleLauncherHelper.addDefaultStartingBundle(fModels, model);
return Optional.of(model);
}
return Optional.empty();
}

private static IPluginModelBase findRequiredPluginInTargetOrHost(String id) throws CoreException {
IPluginModelBase model = PluginRegistry.findModel(id);
if (model == null || !model.getBundleDescription().isResolved()) {
// prefer bundle from host over unresolved bundle from target
model = PDECore.getDefault().findPluginInHost(id);
}
if (model == null) {
throw new CoreException(Status.error(NLS.bind(PDEMessages.JUnitLaunchConfiguration_error_missingPlugin, id)));
}
return model;
}

private static Optional<IPluginModelBase> addCompatible(String id, List<IPluginModelBase> collected, String namespace, Map<String, List<IPluginModelBase>> fAllBundles, Map<IPluginModelBase, String> fModels) {
//First collect all requirements from namespace
Set<BundleRequirement> requirements = new HashSet<>();
for (IPluginModelBase model : collected) {
BundleDescription description = model.getBundleDescription();
if (description == null) {
continue;
}
requirements.addAll(description.getDeclaredRequirements(namespace));
}
//now compute all candidates and sort them by version
List<IPluginModelBase> candidates = Stream.concat(PluginRegistry.findModels(id, null), PDECore.getDefault().findPluginsInHost(id)).filter(model -> {
BundleDescription description = model.getBundleDescription();
if (description == null) {
return false;
}
List<BundleCapability> capabilities = description.getDeclaredCapabilities(namespace);
for (BundleCapability capability : capabilities) {
for (BundleRequirement requirement : requirements) {
if (requirement.matches(capability)) {
return true;
}
}
}
return false;

}).sorted(PDECore.COMPARE_BY_VERSION.reversed()).toList();
if (candidates.isEmpty()) {
return Optional.empty();
}
//now check if not already one is used!
for (IPluginModelBase model : candidates) {
List<IPluginModelBase> list = fAllBundles.get(model.getBundleDescription().getSymbolicName());
if (list != null && list.contains(model)) {
//already selected...
return Optional.empty();
}
}
IPluginModelBase model = candidates.get(0);
fAllBundles.get(model.getBundleDescription().getSymbolicName()).add(model);
BundleLauncherHelper.addDefaultStartingBundle(fModels, model);
return Optional.of(model);
}

public static String formatAdditionalPluginEntry(IPluginModelBase pluginModel, String pluginResolution, boolean isChecked, String fStartLevel, String fAutoStart) {
IPluginBase plugin = pluginModel.getPluginBase();
return String.join(FEATURES_ADDITIONAL_PLUGINS_DATA_SEPARATOR, plugin.getId(), plugin.getVersion(), pluginResolution, String.valueOf(isChecked), fStartLevel, fAutoStart);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,10 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.stream.Collectors;
Expand All @@ -58,7 +55,6 @@
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.IVMRunner;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.core.plugin.IFragment;
Expand All @@ -69,9 +65,7 @@
import org.eclipse.pde.core.plugin.TargetPlatform;
import org.eclipse.pde.internal.build.IPDEBuildConstants;
import org.eclipse.pde.internal.core.ClasspathHelper;
import org.eclipse.pde.internal.core.DependencyManager;
import org.eclipse.pde.internal.core.ICoreConstants;
import org.eclipse.pde.internal.core.PDECore;
import org.eclipse.pde.internal.core.TargetPlatformHelper;
import org.eclipse.pde.internal.core.bnd.PdeProjectAnalyzer;
import org.eclipse.pde.internal.core.util.CoreUtility;
Expand Down Expand Up @@ -393,18 +387,6 @@ protected String getApplication(ILaunchConfiguration configuration) {
return application;
}

private IPluginModelBase findRequiredPluginInTargetOrHost(String id) throws CoreException {
IPluginModelBase model = PluginRegistry.findModel(id);
if (model == null || !model.getBundleDescription().isResolved()) {
// prefer bundle from host over unresolved bundle from target
model = PDECore.getDefault().findPluginInHost(id);
}
if (model == null) {
abort(NLS.bind(PDEMessages.JUnitLaunchConfiguration_error_missingPlugin, id), null, IStatus.OK);
}
return model;
}

@Override
public String getProgramArguments(ILaunchConfiguration configuration) throws CoreException {
return LaunchArgumentsHelper.getUserProgramArguments(configuration);
Expand Down Expand Up @@ -537,7 +519,7 @@ protected void preLaunchCheck(ILaunchConfiguration configuration, ILaunch launch
launchMode = launch.getLaunchMode();

// implicitly add the plug-ins required for JUnit testing if necessary
addRequiredJunitRuntimePlugins(configuration);
BundleLauncherHelper.addRequiredJunitRuntimePlugins(configuration, fAllBundles, fModels);

String attribute = launch.getAttribute(PDE_JUNIT_SHOW_COMMAND);
boolean isShowCommand = false;
Expand All @@ -558,36 +540,6 @@ protected void preLaunchCheck(ILaunchConfiguration configuration, ILaunch launch
synchronizeManifests(configuration, subMonitor.split(1));
}

private void addRequiredJunitRuntimePlugins(ILaunchConfiguration configuration) throws CoreException {
Set<String> requiredPlugins = new LinkedHashSet<>(getRequiredJunitRuntimePlugins(configuration));

if (fAllBundles.containsKey("junit-platform-runner") || fAllBundles.containsKey("org.junit.platform.runner")) { //$NON-NLS-1$ //$NON-NLS-2$
// add launcher and jupiter.engine to support @RunWith(JUnitPlatform.class)
requiredPlugins.add("junit-platform-launcher"); //$NON-NLS-1$
requiredPlugins.add("junit-jupiter-engine"); //$NON-NLS-1$
}
Set<BundleDescription> addedRequirements = new HashSet<>();
addAbsentRequirements(requiredPlugins, addedRequirements);

Set<BundleDescription> requirementsOfRequirements = DependencyManager.findRequirementsClosure(addedRequirements);
Set<String> rorIds = requirementsOfRequirements.stream().map(BundleDescription::getSymbolicName).collect(Collectors.toSet());
addAbsentRequirements(rorIds, null);
}

private void addAbsentRequirements(Collection<String> requirements, Set<BundleDescription> addedRequirements) throws CoreException {
for (String id : requirements) {
List<IPluginModelBase> models = fAllBundles.computeIfAbsent(id, k -> new ArrayList<>());
if (models.stream().noneMatch(m -> m.getBundleDescription().isResolved())) {
IPluginModelBase model = findRequiredPluginInTargetOrHost(id);
models.add(model);
BundleLauncherHelper.addDefaultStartingBundle(fModels, model);
if (addedRequirements != null) {
addedRequirements.add(model.getBundleDescription());
}
}
}
}

/**
* @noreference This method is not intended to be referenced by clients.
* @param configuration non null config
Expand Down
2 changes: 1 addition & 1 deletion ui/org.eclipse.pde.unittest.junit/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Automatic-Module-Name: org.eclipse.pde.unittest.junit
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.pde.unittest.junit;singleton:=true
Bundle-Version: 1.2.100.qualifier
Bundle-Version: 1.2.200.qualifier
Bundle-Activator: org.eclipse.pde.unittest.junit.JUnitPluginTestPlugin
Bundle-ActivationPolicy: lazy
Bundle-Vendor: %providerName
Expand Down
Loading
Loading