/******************************************************************************* * Copyright (c) 2012, 2014 Wind River Systems, Inc. and others. All rights reserved. * This program and the accompanying materials are made available under the terms * of the Eclipse Public License v1.0 which accompanies this distribution, and is * available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.tcf.te.launch.core.lm; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.PlatformObject; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.osgi.util.NLS; import org.eclipse.tcf.te.launch.core.activator.CoreBundleActivator; import org.eclipse.tcf.te.launch.core.bindings.LaunchConfigTypeBindingsManager; import org.eclipse.tcf.te.launch.core.exceptions.LaunchServiceException; import org.eclipse.tcf.te.launch.core.lm.interfaces.ILaunchAttribute; import org.eclipse.tcf.te.launch.core.lm.interfaces.ILaunchManagerDelegate; import org.eclipse.tcf.te.launch.core.lm.interfaces.ILaunchSpecification; import org.eclipse.tcf.te.launch.core.nls.Messages; /** * The Launch Manager is the management interface for the launch configuration storage layer. * Through the launch manager, launch configuration of the several types can be accessed, searched * and initialized. For every possible launch configuration type, a corresponding launch manager * delegate must be registered which is responsible for handling the corresponding attributes of the * specific launch configuration type. In the case the no launch manager delegate is registered for * a launch configuration type, the launch configuration will not be initialized and therefore will * not have any default attribute. If more than one launch manager delegates are contributed for the * same launch configuration type, the first registered launch manager delegates will be used and the * registration of any other delegate for this type will fail! */ public class LaunchManager extends PlatformObject { /* * Thread save singleton instance creation. */ private static class LazyInstanceHolder { public static LaunchManager instance = new LaunchManager(); } /** * Returns the singleton instance for the manager. */ public static LaunchManager getInstance() { return LazyInstanceHolder.instance; } /** * Constructor. */ LaunchManager() { super(); } /** * Returns the corresponding launch manager delegate instance responsible for the specified * launch configuration type. The method may return a default launch manager delegate if no * specific launch manager delegate is registered for the specified launch configuration type. * * @param launchConfigType The launch configuration type to get the launch manager delegate for. * Must not be <code>null</code>! * @param launchMode The launch mode to get the launch manager delegate for. Must not be * <code>null</code>. * @return The corresponding launch manager delegate instance. */ public ILaunchManagerDelegate getLaunchManagerDelegate(ILaunchConfigurationType launchConfigType, String launchMode) { Assert.isNotNull(launchConfigType); Assert.isNotNull(launchMode); return LaunchConfigTypeBindingsManager.getInstance().getLaunchManagerDelegate(launchConfigType.getIdentifier(), launchMode); } /** * Returns the corresponding launch configuration type for the given launch configuration type * id and the given launch mode. * * @param launchConfigTypeId The unique id of the launch configuration type requested. * @param launchMode The launch mode the launch configuration type must support. See * <code>org.eclipse.debug.core.ILaunchManager</code> for details. * @return The corresponding launch configuration type instance or <code>null</code> if not * found or the specified mode is not supported. */ public ILaunchConfigurationType getLaunchConfigType(String launchConfigTypeId, String launchMode) { ILaunchConfigurationType launchConfigType = DebugPlugin.getDefault().getLaunchManager() .getLaunchConfigurationType(launchConfigTypeId); if (launchConfigType != null && !launchConfigType.supportsMode(launchMode)) { launchConfigType = null; } return launchConfigType; } /** * Returns an fully initialized launch configuration. The launch configuration type and the * launch mode required to create or look up the launch configuration, are specified through the * given launch specification. Any launch configuration attribute of the certain type which is * not explicitly overwritten by an attribute specified through the given launch specification * will be initialized with default values. * <p> * If <code>forceNewConfig</code> is <code>false</code>, the method tries to find a matching * existing launch configuration. If no existing launch configuration can be found, a new * launch configuration will created instead. * * @param launchSpec A set of non default launch configuration attributes. Must not be * <code>null</code>, but the list of attributes may empty to get an launch * configuration with all attributes initialized to default values. * @param createNew If <code>true</code>, a new launch configuration will be created if no * available is found. * @return The launch configuration instance matching the given parameters. * @throws <code>LaunchServiceException</code> in case the launch configuration instance * cannot be created, found and/or modified. The exception message describes the failure * details. */ public ILaunchConfiguration getLaunchConfiguration(ILaunchSpecification launchSpec, boolean createNew) throws LaunchServiceException { Assert.isNotNull(launchSpec); ILaunchConfiguration launchConfig = null; try { // get all launch configurations for launch configuration type id and launch mode String launchConfigTypeId = launchSpec.getLaunchConfigurationTypeId(); String launchMode = launchSpec.getLaunchMode(); ILaunchConfigurationType launchConfigType = getLaunchConfigType(launchConfigTypeId, launchMode); ILaunchConfiguration[] configs = DebugPlugin.getDefault().getLaunchManager() .getLaunchConfigurations(launchConfigType); // get list of fully and closest matching launch configurations ILaunchConfiguration[] matchingConfigs = getLaunchManagerDelegate(launchConfigType, launchMode) .getMatchingLaunchConfigurations(launchSpec, configs); // return best matching launch configuration if (matchingConfigs.length > 0) { launchConfig = matchingConfigs[0]; } } catch (LaunchServiceException e) { if (e.getType() == LaunchServiceException.TYPE_MISSING_LAUNCH_SPEC_ATTR) { throw e; } } catch (CoreException e) { throw new LaunchServiceException(e.getMessage()); } // return new launch configuration if no matching or best matching configuration is found if (createNew && launchConfig == null) { launchConfig = createOrUpdateLaunchConfiguration(null, launchSpec); } return launchConfig; } /** * Create a new or updates an existing launch configuration of the requested type and initialize * the configuration with the given launch specification. Attributes not listed by the given * launch specification will be initialized with default values. * * @param launchConfig A launch configuration to update or <code>null</code> if a new launch * configuration should be created. * @param launchSpec A set of non default launch configuration attributes. * @return The newly create launch configuration instance. * * @throws <code>LaunchServiceException</code> in case the launch configuration instance * cannot be created or mandatory attributes are missing in the launch specification. * The exception message describes the failure details. */ public ILaunchConfiguration createOrUpdateLaunchConfiguration(ILaunchConfiguration launchConfig, ILaunchSpecification launchSpec) throws LaunchServiceException { return this.createOrUpdateLaunchConfiguration(launchConfig, launchSpec, true); } /** * Create a new or updates an existing launch configuration of the requested type and initialize * the configuration with the given launch specification. Attributes not listed by the given * launch specification will be initialized with default values. * * @param launchConfig A launch configuration to update or <code>null</code> if a new launch * configuration should be created. * @param launchSpec A set of non default launch configuration attributes. * @param validateSpec Validate the launch specification in the <code>launchSpec</code> * parameter. If <code>false</code>, it will attempt to create the launch * configuration even if some of the mandatory parameters are missing. * @return The newly create launch configuration instance. * * @throws <code>LaunchServiceException</code> in case the launch configuration instance * cannot be created or mandatory attributes are missing in the launch specification. * The exception message describes the failure details. * * @since 3.2 */ public ILaunchConfiguration createOrUpdateLaunchConfiguration(ILaunchConfiguration launchConfig, ILaunchSpecification launchSpec, boolean validateSpec) throws LaunchServiceException { Assert.isNotNull(launchSpec); String launchConfigTypeId = launchSpec.getLaunchConfigurationTypeId(); String launchMode = launchSpec.getLaunchMode(); ILaunchConfigurationType launchConfigType = getLaunchConfigType(launchConfigTypeId, launchMode); try { if (launchConfigType != null) { // get the launch manager delegate instance for the requested launch configuration // type ILaunchManagerDelegate delegate = getLaunchManagerDelegate(launchConfigType, launchMode); if (validateSpec) { delegate.validate(launchSpec); } ILaunchConfigurationWorkingCopy wc = null; if (launchConfig == null || !launchConfig.getType().getIdentifier() .equals(launchConfigTypeId)) { try { // create the launch configuration working copy instance wc = launchConfigType.newInstance(null, LaunchConfigHelper.getUniqueLaunchConfigName(launchSpec.getLaunchConfigName())); // initialize the launch configuration working copy delegate.initLaunchConfigAttributes(wc, launchSpec); // and save the launch configuration return wc.doSave(); } catch (CoreException e) { throw new LaunchServiceException(Messages.LaunchManager_error_failedToCreateConfig); } } try { // get a launch configration working copy if (launchConfig instanceof ILaunchConfigurationWorkingCopy) { wc = (ILaunchConfigurationWorkingCopy) launchConfig; } else { wc = launchConfig.getWorkingCopy(); } // update the launch configuration working copy delegate.updateLaunchConfigAttributes(wc, launchSpec); // and save the launch configuration return (wc.isDirty()) ? wc.doSave() : launchConfig; } catch (CoreException e) { throw new LaunchServiceException(NLS.bind(Messages.LaunchManager_error_failedToUpdateConfig, launchConfig.getName())); } } } catch (CoreException e) { // do nothing, because exception is thrown afterwards if this point is reached. } throw new LaunchServiceException(NLS.bind(Messages.LaunchManager_error_noLaunchConfigType, launchMode)); } /** * Delete the specified launch configuration. * <p> * In case any error occurs during the delete, the exception is logged to the Eclipse error log. * * @param launchConfig The launch configuration to delete. */ public void deleteLaunchConfiguration(ILaunchConfiguration launchConfig) { if (launchConfig != null) { try { launchConfig.delete(); } catch (CoreException e) { IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), Messages.LaunchManager_error_deleteLaunchConfig, e); Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); } } } /** * Creates an exact copy of the given launch specification. * <p> * <b>Note:</b> The method returns always an launch specification which has not locked out * modifications. The corresponding read-only flag from the original is not duplicated to the * copy! * * @param launchSpec The launch specification to duplication. * @return A new <code>ILaunchSpecification</code> instance containing the same data as the * original, or <code>null</code>. */ public ILaunchSpecification duplicate(ILaunchSpecification launchSpec) { if (launchSpec != null) { ILaunchSpecification newLaunchSpec = new LaunchSpecification(launchSpec.getLaunchConfigurationTypeId(), launchSpec.getLaunchMode()); if (!launchSpec.isEmpty()) { ILaunchAttribute[] attributes = launchSpec.getAllAttributes(); for (ILaunchAttribute attribute : attributes) { newLaunchSpec.addAttribute(attribute.getKey(), attribute.getValue()); } } return newLaunchSpec; } return null; } /** * Validates a launch configuration. * * @param launchConfig The launch configuration to validate. * @param launchMode The launch mode. Can be <code>null</code>, in this case the launch configuration * is valid when valid for all supported modes. * @return <code>true</code>, if the launch configuration is valid and can be executed (launched). */ public boolean validate(ILaunchConfiguration launchConfig, String launchMode) { try { if (launchMode == null) { boolean valid = false; for (String mode : LaunchConfigHelper.getLaunchConfigTypeModes(launchConfig.getType(), false)) { if (launchConfig.supportsMode(mode) && validate(launchConfig, mode)) { valid = true; } } return valid; } ILaunchManagerDelegate delegate = getLaunchManagerDelegate(launchConfig.getType(), launchMode); try { delegate.validate(launchMode, launchConfig); } catch (LaunchServiceException e) { return false; } } catch (CoreException e) { } return true; } /** * Transform the specified launch configuration into a corresponding launch specification * object. If <code>withDefaultAttributes</code> is not set, the corresponding launch manager * delegate is called to determine if an attribute has a default value or not. If the attribute * has an default value, this attribute is not copied to the launch specification. If * <code>withDefaultAttributes</code> is set, all attributes are copied to the launch * specification object. * * @param launchConfig The launch configuration. Must not be <code>null</code>. * @param launchMode The launch mode the launch specification should be for. See * <code>ILaunchManager</code> for details. * @param withDefaultAttributes Set to <code>true</code> to copy attributes with default value * as well, <code>false</code> otherwise. * * @return The corresponding launch specification object or <code>null</code>. * * @throws <code>LaunchServiceException</code> in case the launch configuration could not be * transformed to a launch specification. The exception message describes the failure * details. */ public ILaunchSpecification createSpecFromConfig(ILaunchConfiguration launchConfig, String launchMode, boolean withDefaultAttributes) throws LaunchServiceException { Assert.isNotNull(launchConfig); ILaunchSpecification spec = null; try { // extract the launch configuration type ILaunchConfigurationType type = launchConfig.getType(); spec = new LaunchSpecification(type.getIdentifier(), launchMode); // get the launch manager delegate for the specific type ILaunchManagerDelegate delegate = getLaunchManagerDelegate(type, launchMode); // get all the launch configuration attributes Map<String, Object> attributes = launchConfig.getAttributes(); // loop over all listed attributes and copy them to the specification Iterator<Entry<String, Object>> iterator = attributes.entrySet().iterator(); while (iterator.hasNext()) { Entry<String, Object> entry = iterator.next(); if (withDefaultAttributes) { // include the default attributes. So, just copy the stuff over. spec.addAttribute(entry.getKey(), entry.getValue()); } else { // exclude the default attributes. We have to find out if the attribute is // set with default value. Object attributeValue = entry.getValue(); if (!delegate.isDefaultAttribute(entry.getKey(), attributeValue, attributeValue, spec, launchConfig, launchMode)) { spec.addAttribute(entry.getKey(), attributeValue); } } } } catch (CoreException e) { spec = null; throw new LaunchServiceException(e); } return spec; } /** * Launch the specified launch configuration using the corresponding delegate for the specified * launch mode. If <code>buildBeforeLaunch</code> is set to <code>true</code>, the workspace * will be build before the launch. * * @param launchConfig The launch configuration to launch. Must not be <code>null</code>! * @param launchMode The launch mode (@see <code>org.eclipse.debug.core.ILaunchManager</code>. * Must not be <code>null</code>! * @param buildBeforeLaunch Specify <code>true</code> to build the workspace before launch, * <code>false</code> otherwise. * * @return The corresponding <code>ILaunch</code> object associated with this launch. * * @throws <code>LaunchServiceException</code> in case of any problem occurs during the launch sequence. */ public ILaunch launch(ILaunchConfiguration launchConfig, String launchMode, boolean buildBeforeLaunch, IProgressMonitor monitor) throws LaunchServiceException { Assert.isNotNull(launchConfig); Assert.isNotNull(launchMode); try { ILaunchManagerDelegate delegate = getLaunchManagerDelegate(launchConfig.getType(), launchMode); delegate.validate(launchMode, launchConfig); return launchConfig.launch(launchMode, monitor, buildBeforeLaunch); } catch (CoreException e) { // re-pack into a launch service exception throw new LaunchServiceException(e); } } }