Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 7ffb5d7de0be77ca0526fa83dfe6464cd6ecbdaf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
/*******************************************************************************
 * Copyright (c) 2012 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, DebugPlugin
										.getDefault()
										.getLaunchManager()
										.generateLaunchConfigurationName(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, 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);
		}
	}

	/**
	 * Remove all illegal characters in the launch configuration name candidate.
	 *
	 * @param candidate The launch configuration name candidate.
	 * @return The unified launch configuration name.
	 */
	public static String getUnifiedLaunchConfigName(String candidate) {
		if (candidate != null) {
			candidate = candidate.replaceAll("[/\\\"&?:@*]", "_"); //$NON-NLS-1$ //$NON-NLS-2$
		}
		return candidate;
	}

}

Back to the top