| /******************************************************************************* |
| * Copyright (c) 2010, 2018 IBM Corporation and others. |
| * |
| * 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: |
| * IBM Corporation - initial API and implementation |
| * Karsten Thoms (itemis) - Bug 530406 |
| *******************************************************************************/ |
| package org.eclipse.pde.internal.launching.launcher; |
| |
| import java.util.*; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ConcurrentMap; |
| import java.util.stream.Stream; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.debug.core.*; |
| import org.eclipse.pde.core.plugin.*; |
| import org.eclipse.pde.internal.core.PDECore; |
| import org.eclipse.pde.internal.core.PDEExtensionRegistry; |
| import org.eclipse.pde.launching.IPDELauncherConstants; |
| |
| /** |
| * Centralizes code for validating the contents of a launch and finding missing requirements. |
| * |
| * @since 3.6 |
| * @see EclipsePluginValidationOperation |
| */ |
| public class RequirementHelper { |
| |
| private RequirementHelper() { |
| } // static use only |
| |
| @FunctionalInterface // like java.util.function.Function but can throw CoreException |
| public static interface ILaunchRequirementsFunction { |
| List<String> getRequiredBundleIds(ILaunchConfiguration lc) throws CoreException; |
| } |
| |
| private static final ConcurrentMap<String, ILaunchRequirementsFunction> APPLICATION_REQUIREMENTS = new ConcurrentHashMap<>(); |
| |
| public static void registerLaunchTypeRequirements(String launchTypeId, ILaunchRequirementsFunction requirementsFunction) { |
| APPLICATION_REQUIREMENTS.put(launchTypeId, Objects.requireNonNull(requirementsFunction)); |
| } |
| |
| public static void registerSameRequirementsAsFor(String launchTypeId, String sourceLaunchTypeId) { |
| // enforce initialization of source class to register required plug-ins |
| ILaunchConfigurationType type = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationType(sourceLaunchTypeId); |
| for (Set<String> modes : type.getSupportedModeCombinations()) { |
| try { |
| for (ILaunchDelegate delegate : type.getDelegates(modes)) { |
| delegate.getDelegate(); |
| } |
| } catch (CoreException e) { |
| } |
| } |
| APPLICATION_REQUIREMENTS.put(launchTypeId, APPLICATION_REQUIREMENTS.get(sourceLaunchTypeId)); |
| } |
| |
| /** |
| * Returns a list of string plug-in ids that are required to launch the product, application |
| * or application to test that the given launch configuration specifies. Which attributes are |
| * checked will depend on whether a product, an application or a junit application is being launched. |
| * |
| * @param config launch configuration to get attributes from |
| * @param plugins list of plugin models to look for product extensions in |
| * @return list of string plug-in IDs that are required by the config's application/product settings |
| * @throws CoreException if there is a problem reading the launch config |
| */ |
| public static List<String> getApplicationLaunchRequirements(ILaunchConfiguration config) throws CoreException { |
| ILaunchRequirementsFunction requirementsFunction = APPLICATION_REQUIREMENTS.get(config.getType().getIdentifier()); |
| return requirementsFunction != null ? Objects.requireNonNull(requirementsFunction.getRequiredBundleIds(config)) : Collections.emptyList(); |
| } |
| |
| public static boolean addApplicationLaunchRequirements(Map<IPluginModelBase, String> bundle2startLevel, ILaunchConfiguration configuration) throws CoreException { |
| boolean isFeatureBasedLaunch = configuration.getAttribute(IPDELauncherConstants.USE_CUSTOM_FEATURES, false); |
| String pluginResolution = isFeatureBasedLaunch ? configuration.getAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION, IPDELauncherConstants.LOCATION_WORKSPACE) : IPDELauncherConstants.LOCATION_WORKSPACE; |
| |
| List<String> appRequirements = getApplicationLaunchRequirements(configuration); |
| boolean missingRequirements = false; |
| for (String requiredBundleId : appRequirements) { |
| ModelEntry entry = PluginRegistry.findEntry(requiredBundleId); |
| if (entry != null) { |
| // add required plug-in if not yet already included |
| var allPluginsWithId = Stream.of(entry.getWorkspaceModels(), entry.getExternalModels()).flatMap(Arrays::stream); |
| if (allPluginsWithId.noneMatch(bundle2startLevel::containsKey)) { |
| IPluginModelBase plugin = BundleLauncherHelper.getLatestPlugin(requiredBundleId, pluginResolution); |
| BundleLauncherHelper.addDefaultStartingBundle(bundle2startLevel, plugin); |
| } |
| } else { |
| missingRequirements = true; |
| } |
| } |
| return missingRequirements; |
| } |
| |
| public static List<String> getProductRequirements(ILaunchConfiguration config) throws CoreException { |
| String product = config.getAttribute(IPDELauncherConstants.PRODUCT, (String) null); |
| if (product == null) { |
| return Collections.emptyList(); |
| } |
| PDEExtensionRegistry registry = PDECore.getDefault().getExtensionsRegistry(); |
| IExtension[] extensions = registry.findExtensions("org.eclipse.core.runtime.products", true); //$NON-NLS-1$ |
| for (IExtension extension : extensions) { |
| |
| if (product.equals(extension.getUniqueIdentifier()) || product.equals(extension.getSimpleIdentifier())) { |
| Set<String> requiredIds = new LinkedHashSet<>(); |
| requiredIds.add(extension.getContributor().getName()); |
| |
| IConfigurationElement[] elements = extension.getConfigurationElements(); |
| for (IConfigurationElement element : elements) { |
| String application = element.getAttribute(IPDELauncherConstants.APPLICATION); |
| if (application != null && !application.isEmpty()) { |
| requiredIds.addAll(getApplicationRequirements(application)); |
| } |
| } |
| // Only one extension should match the product so break out of the loop |
| return List.copyOf(requiredIds); |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| public static List<String> getApplicationRequirements(String application) { |
| PDEExtensionRegistry registry = PDECore.getDefault().getExtensionsRegistry(); |
| IExtension[] extensions = registry.findExtensions("org.eclipse.core.runtime.applications", true); //$NON-NLS-1$ |
| for (IExtension extension : extensions) { |
| if (application.equals(extension.getUniqueIdentifier()) || application.equals(extension.getSimpleIdentifier())) { |
| return List.of(extension.getContributor().getName()); |
| // Only one extension should match the application so break out of the loop |
| } |
| } |
| return Collections.emptyList(); |
| } |
| } |