001: /*******************************************************************************
002: * Copyright (c) 2005, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.ui.launcher;
011:
012: import java.io.File;
013: import java.util.ArrayList;
014: import java.util.Map;
015:
016: import org.eclipse.core.resources.IProject;
017: import org.eclipse.core.runtime.CoreException;
018: import org.eclipse.core.runtime.IPath;
019: import org.eclipse.core.runtime.IProgressMonitor;
020: import org.eclipse.core.runtime.IStatus;
021: import org.eclipse.core.runtime.SubProgressMonitor;
022: import org.eclipse.debug.core.DebugPlugin;
023: import org.eclipse.debug.core.ILaunch;
024: import org.eclipse.debug.core.ILaunchConfiguration;
025: import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
026: import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
027: import org.eclipse.jdt.launching.ExecutionArguments;
028: import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
029: import org.eclipse.jdt.launching.IVMInstall;
030: import org.eclipse.jdt.launching.IVMRunner;
031: import org.eclipse.jdt.launching.VMRunnerConfiguration;
032: import org.eclipse.jface.dialogs.MessageDialog;
033: import org.eclipse.pde.core.plugin.TargetPlatform;
034: import org.eclipse.pde.internal.core.TargetPlatformHelper;
035: import org.eclipse.pde.internal.ui.IPDEUIConstants;
036: import org.eclipse.pde.internal.ui.PDEPlugin;
037: import org.eclipse.pde.internal.ui.PDEUIMessages;
038: import org.eclipse.pde.internal.ui.launcher.EclipsePluginValidationOperation;
039: import org.eclipse.pde.internal.ui.launcher.LaunchArgumentsHelper;
040: import org.eclipse.pde.internal.ui.launcher.LaunchConfigurationHelper;
041: import org.eclipse.pde.internal.ui.launcher.LaunchPluginValidator;
042: import org.eclipse.pde.internal.ui.launcher.LauncherUtils;
043: import org.eclipse.pde.internal.ui.launcher.VMHelper;
044:
045: /**
046: * An abstract launch delegate for PDE-based launch configurations
047: * <p>
048: * Clients may subclass this class.
049: * </p>
050: * @since 3.2
051: */
052: public abstract class AbstractPDELaunchConfiguration extends
053: LaunchConfigurationDelegate {
054:
055: protected File fConfigDir = null;
056:
057: /*
058: * (non-Javadoc)
059: * @see org.eclipse.debug.core.model.ILaunchConfigurationDelegate#launch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor)
060: */
061: public void launch(ILaunchConfiguration configuration, String mode,
062: ILaunch launch, IProgressMonitor monitor)
063: throws CoreException {
064: try {
065: fConfigDir = null;
066: monitor.beginTask("", 4); //$NON-NLS-1$
067: try {
068: preLaunchCheck(configuration, launch,
069: new SubProgressMonitor(monitor, 2));
070: } catch (CoreException e) {
071: if (e.getStatus().getSeverity() == IStatus.CANCEL) {
072: monitor.setCanceled(true);
073: return;
074: }
075: throw e;
076: }
077: // if restarting, remove the restart flag from the launch config
078: if (configuration.getAttribute(IPDEUIConstants.RESTART,
079: false)
080: && configuration instanceof ILaunchConfigurationWorkingCopy) {
081: ((ILaunchConfigurationWorkingCopy) configuration)
082: .setAttribute(IPDEUIConstants.RESTART, false);
083: ((ILaunchConfigurationWorkingCopy) configuration)
084: .doSave();
085: }
086: VMRunnerConfiguration runnerConfig = new VMRunnerConfiguration(
087: getMainClass(), getClasspath(configuration));
088: runnerConfig.setVMArguments(getVMArguments(configuration));
089: runnerConfig
090: .setProgramArguments(getProgramArguments(configuration));
091: runnerConfig.setWorkingDirectory(getWorkingDirectory(
092: configuration).getAbsolutePath());
093: runnerConfig.setEnvironment(getEnvironment(configuration));
094: runnerConfig
095: .setVMSpecificAttributesMap(getVMSpecificAttributesMap(configuration));
096:
097: monitor.worked(1);
098:
099: setDefaultSourceLocator(configuration);
100: manageLaunch(launch);
101: IVMRunner runner = getVMRunner(configuration, mode);
102: if (runner != null)
103: runner.run(runnerConfig, launch, monitor);
104: else
105: monitor.setCanceled(true);
106: monitor.done();
107: } catch (final CoreException e) {
108: monitor.setCanceled(true);
109: LauncherUtils.getDisplay().syncExec(new Runnable() {
110: public void run() {
111: MessageDialog.openError(LauncherUtils
112: .getActiveShell(),
113: PDEUIMessages.Launcher_error_title, e
114: .getMessage());
115: }
116: });
117: }
118: }
119:
120: /**
121: * Returns the VM runner for the given launch mode to use when launching the
122: * given configuration.
123: *
124: * @param configuration launch configuration
125: * @param mode launch node
126: * @return VM runner to use when launching the given configuration in the given mode
127: * @throws CoreException if a VM runner cannot be determined
128: */
129: public IVMRunner getVMRunner(ILaunchConfiguration configuration,
130: String mode) throws CoreException {
131: IVMInstall launcher = VMHelper.createLauncher(configuration);
132: return launcher.getVMRunner(mode);
133: }
134:
135: /**
136: * Assigns a default source locator to the given launch if a source locator
137: * has not yet been assigned to it, and the associated launch configuration
138: * does not specify a source locator.
139: *
140: * @param configuration
141: * configuration being launched
142: * @exception CoreException
143: * if unable to set the source locator
144: */
145: protected void setDefaultSourceLocator(
146: ILaunchConfiguration configuration) throws CoreException {
147: ILaunchConfigurationWorkingCopy wc = null;
148: if (configuration.isWorkingCopy()) {
149: wc = (ILaunchConfigurationWorkingCopy) configuration;
150: } else {
151: wc = configuration.getWorkingCopy();
152: }
153: String id = configuration
154: .getAttribute(
155: IJavaLaunchConfigurationConstants.ATTR_SOURCE_PATH_PROVIDER,
156: (String) null);
157: if (!PDESourcePathProvider.ID.equals(id)) {
158: wc
159: .setAttribute(
160: IJavaLaunchConfigurationConstants.ATTR_SOURCE_PATH_PROVIDER,
161: PDESourcePathProvider.ID);
162: wc.doSave();
163: }
164: }
165:
166: /**
167: * Returns the entries that should appear on boot classpath.
168: *
169: * @param configuration
170: * launch configuration
171: * @return the location of startup.jar and
172: * the bootstrap classpath specified by the given launch configuration
173: *
174: * @exception CoreException
175: * if unable to find startup.jar
176: */
177: public String[] getClasspath(ILaunchConfiguration configuration)
178: throws CoreException {
179: String[] classpath = LaunchArgumentsHelper
180: .constructClasspath(configuration);
181: if (classpath == null) {
182: String message = PDEUIMessages.WorkbenchLauncherConfigurationDelegate_noStartup;
183: throw new CoreException(LauncherUtils
184: .createErrorStatus(message));
185: }
186: return classpath;
187: }
188:
189: /**
190: * Returns an array of environment variables to be used when
191: * launching the given configuration or <code>null</code> if unspecified.
192: *
193: * @param configuration launch configuration
194: * @throws CoreException if unable to access associated attribute or if
195: * unable to resolve a variable in an environment variable's value
196: */
197: public String[] getEnvironment(ILaunchConfiguration configuration)
198: throws CoreException {
199: return DebugPlugin.getDefault().getLaunchManager()
200: .getEnvironment(configuration);
201: }
202:
203: /**
204: * Returns the working directory path specified by the given launch
205: * configuration, or <code>null</code> if none.
206: *
207: * @param configuration
208: * launch configuration
209: * @return the working directory path specified by the given launch
210: * configuration, or <code>null</code> if none
211: * @exception CoreException
212: * if unable to retrieve the attribute
213: */
214: public File getWorkingDirectory(ILaunchConfiguration configuration)
215: throws CoreException {
216: return LaunchArgumentsHelper.getWorkingDirectory(configuration);
217: }
218:
219: /**
220: * Returns the Map of VM-specific attributes specified by the given launch
221: * configuration, or <code>null</code> if none.
222: *
223: * @param configuration
224: * launch configuration
225: * @return the <code>Map</code> of VM-specific attributes
226: * @exception CoreException
227: * if unable to retrieve the attribute
228: */
229: public Map getVMSpecificAttributesMap(
230: ILaunchConfiguration configuration) throws CoreException {
231: return LaunchArgumentsHelper
232: .getVMSpecificAttributesMap(configuration);
233: }
234:
235: /**
236: * Returns the VM arguments specified by the given launch configuration, as
237: * an array of strings.
238: *
239: * @param configuration
240: * launch configuration
241: * @return the VM arguments specified by the given launch configuration,
242: * possibly an empty array
243: * @exception CoreException
244: * if unable to retrieve the attribute
245: */
246: public String[] getVMArguments(ILaunchConfiguration configuration)
247: throws CoreException {
248: return new ExecutionArguments(LaunchArgumentsHelper
249: .getUserVMArguments(configuration), "").getVMArgumentsArray(); //$NON-NLS-1$
250: }
251:
252: /**
253: * Returns the program arguments to launch with.
254: * This list is a combination of arguments computed by PDE based on attributes
255: * specified in the given launch configuration, followed by the program arguments
256: * that the entered directly into the launch configuration.
257: *
258: * @param configuration
259: * launch configuration
260: * @return the program arguments necessary for launching
261: *
262: * @exception CoreException
263: * if unable to retrieve the attribute or create the
264: * necessary configuration files
265: */
266: public String[] getProgramArguments(
267: ILaunchConfiguration configuration) throws CoreException {
268: ArrayList programArgs = new ArrayList();
269:
270: // add tracing, if turned on
271: if (configuration.getAttribute(IPDELauncherConstants.TRACING,
272: false)
273: && !IPDELauncherConstants.TRACING_NONE
274: .equals(configuration.getAttribute(
275: IPDELauncherConstants.TRACING_CHECKED,
276: (String) null))) {
277: programArgs.add("-debug"); //$NON-NLS-1$
278: programArgs.add(LaunchArgumentsHelper
279: .getTracingFileArgument(configuration,
280: getConfigDir(configuration).toString()
281: + IPath.SEPARATOR + ".options")); //$NON-NLS-1$
282: }
283:
284: // add the program args specified by the user
285: String[] userArgs = LaunchArgumentsHelper
286: .getUserProgramArgumentArray(configuration);
287: ArrayList userDefined = new ArrayList();
288: for (int i = 0; i < userArgs.length; i++) {
289: // be forgiving if people have tracing turned on and forgot
290: // to remove the -debug from the program args field.
291: if (userArgs[i].equals("-debug") && programArgs.contains("-debug")) //$NON-NLS-1$ //$NON-NLS-2$
292: continue;
293: userDefined.add(userArgs[i]);
294: }
295:
296: if (!configuration.getAttribute(
297: IPDEUIConstants.APPEND_ARGS_EXPLICITLY, false)) {
298:
299: if (!userDefined.contains("-os")) { //$NON-NLS-1$
300: programArgs.add("-os"); //$NON-NLS-1$
301: programArgs.add(TargetPlatform.getOS());
302: }
303: if (!userDefined.contains("-ws")) { //$NON-NLS-1$
304: programArgs.add("-ws"); //$NON-NLS-1$
305: programArgs.add(TargetPlatform.getWS());
306: }
307: if (!userDefined.contains("-arch")) { //$NON-NLS-1$
308: programArgs.add("-arch"); //$NON-NLS-1$
309: programArgs.add(TargetPlatform.getOSArch());
310: }
311: }
312:
313: if (userDefined.size() > 0) {
314: programArgs.addAll(userDefined);
315: }
316:
317: return (String[]) programArgs.toArray(new String[programArgs
318: .size()]);
319: }
320:
321: /**
322: * Does sanity checking before launching. The criteria whether the launch should
323: * proceed or not is specific to the launch configuration type.
324: *
325: * @param configuration launch configuration
326: * @param launch the launch object to contribute processes and debug targets to
327: * @param monitor a progress monitor
328: *
329: * @throws CoreException exception thrown if launch fails or canceled or if unable to retrieve attributes
330: * from the launch configuration
331: *
332: */
333: protected void preLaunchCheck(ILaunchConfiguration configuration,
334: ILaunch launch, IProgressMonitor monitor)
335: throws CoreException {
336: boolean autoValidate = configuration.getAttribute(
337: IPDELauncherConstants.AUTOMATIC_VALIDATE, false);
338: monitor.beginTask("", autoValidate ? 3 : 4); //$NON-NLS-1$
339: if (autoValidate)
340: validatePluginDependencies(configuration,
341: new SubProgressMonitor(monitor, 1));
342: validateProjectDependencies(configuration,
343: new SubProgressMonitor(monitor, 1));
344: clear(configuration, new SubProgressMonitor(monitor, 1));
345: launch.setAttribute(IPDELauncherConstants.CONFIG_LOCATION,
346: getConfigDir(configuration).toString());
347: synchronizeManifests(configuration, new SubProgressMonitor(
348: monitor, 1));
349: }
350:
351: /**
352: * Returns the configuration area specified by the given launch
353: * configuration.
354: *
355: * @param configuration
356: * launch configuration
357: * @return the directory path specified by the given launch
358: * configuration
359: */
360: protected File getConfigDir(ILaunchConfiguration configuration) {
361: if (fConfigDir == null)
362: fConfigDir = LaunchConfigurationHelper
363: .getConfigurationArea(configuration);
364: return fConfigDir;
365: }
366:
367: /*
368: /* (non-Javadoc)
369: * @see org.eclipse.debug.core.model.LaunchConfigurationDelegate#getBuildOrder(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String)
370: */
371: protected IProject[] getBuildOrder(
372: ILaunchConfiguration configuration, String mode)
373: throws CoreException {
374: return computeBuildOrder(LaunchPluginValidator
375: .getAffectedProjects(configuration));
376: }
377:
378: /*
379: * (non-Javadoc)
380: * @see org.eclipse.debug.core.model.LaunchConfigurationDelegate#getProjectsForProblemSearch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String)
381: */
382: protected IProject[] getProjectsForProblemSearch(
383: ILaunchConfiguration configuration, String mode)
384: throws CoreException {
385: return LaunchPluginValidator.getAffectedProjects(configuration);
386: }
387:
388: /**
389: * Returns the fully-qualified name of the class to launch.
390: *
391: * @return the fully-qualified name of the class to launch. Must not return <code>null</code>.
392: * @since 3.3
393: */
394: public String getMainClass() {
395: if (TargetPlatformHelper.getTargetVersion() >= 3.3)
396: return "org.eclipse.equinox.launcher.Main"; //$NON-NLS-1$
397: return "org.eclipse.core.launcher.Main"; //$NON-NLS-1$
398: }
399:
400: /**
401: * Adds a listener to the launch to be notified at interesting launch lifecycle
402: * events such as when the launch terminates.
403: *
404: * @param launch
405: * the launch
406: *
407: * @since 3.3
408: */
409: protected void manageLaunch(ILaunch launch) {
410: PDEPlugin.getDefault().getLaunchListener().manage(launch);
411: }
412:
413: /**
414: * Checks for old-style plugin.xml files that have become stale since the last launch.
415: * For any stale plugin.xml files found, the corresponding MANIFEST.MF is deleted
416: * from the runtime configuration area so that it gets regenerated upon startup.
417: *
418: * @param configuration
419: * the launch configuration
420: * @param monitor
421: * a progress monitor
422: *
423: * @since 3.3
424: */
425: protected void synchronizeManifests(
426: ILaunchConfiguration configuration, IProgressMonitor monitor) {
427: LaunchConfigurationHelper.synchronizeManifests(configuration,
428: getConfigDir(configuration));
429: monitor.done();
430: }
431:
432: /**
433: * Checks if the Automated Management of Dependencies option is turned on.
434: * If so, it makes aure all manifests are updated with the correct dependencies.
435: *
436: * @param configuration
437: * the launch configuration
438: * @param monitor
439: * a progress monitor
440: *
441: * @since 3.3
442: */
443: protected void validateProjectDependencies(
444: ILaunchConfiguration configuration, IProgressMonitor monitor) {
445: LauncherUtils.validateProjectDependencies(configuration,
446: monitor);
447: }
448:
449: /**
450: * By default, this method does nothing. Clients should override, if appropriate.
451: *
452: * @param configuration
453: * the launch configuration
454: * @param monitor
455: * the progress monitor
456: * @throws CoreException
457: * if unable to retrieve launch attribute values
458: * @since 3.3
459: */
460: protected void clear(ILaunchConfiguration configuration,
461: IProgressMonitor monitor) throws CoreException {
462: }
463:
464: /**
465: * Validates inter-bundle dependencies automatically prior to launching
466: * if that option is turned on.
467: *
468: * @param configuration
469: * the launch configuration
470: * @param monitor
471: * a progress monitor
472: * @since 3.3
473: */
474: protected void validatePluginDependencies(
475: ILaunchConfiguration configuration, IProgressMonitor monitor)
476: throws CoreException {
477: EclipsePluginValidationOperation op = new EclipsePluginValidationOperation(
478: configuration);
479: LaunchPluginValidator.runValidationOperation(op, monitor);
480: }
481:
482: }
|