| /******************************************************************************* |
| * Copyright (c) 2000, 2015 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| * Sebastian Davids - bug 50567 Eclipse native environment support on Win98 |
| * Pawel Piech - Bug 82001: When shutting down the IDE, the debugger should first |
| * attempt to disconnect debug targets before terminating them |
| * Alena Laskavaia - Bug 259281 |
| * Marc Khouzam - Bug 313143: Preferred Launch Delegate not recovered from preferences |
| *******************************************************************************/ |
| package org.eclipse.debug.internal.core; |
| |
| |
| import java.io.BufferedInputStream; |
| import java.io.BufferedReader; |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.FilenameFilter; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| 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.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.transform.OutputKeys; |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.TransformerException; |
| import javax.xml.transform.TransformerFactory; |
| import javax.xml.transform.dom.DOMSource; |
| import javax.xml.transform.stream.StreamResult; |
| |
| import org.eclipse.core.filesystem.EFS; |
| import org.eclipse.core.filesystem.IFileStore; |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceChangeEvent; |
| import org.eclipse.core.resources.IResourceChangeListener; |
| import org.eclipse.core.resources.IResourceDelta; |
| import org.eclipse.core.resources.IResourceDeltaVisitor; |
| import org.eclipse.core.resources.IResourceProxy; |
| import org.eclipse.core.resources.IResourceProxyVisitor; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.ISafeRunnable; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.PlatformObject; |
| import org.eclipse.core.runtime.SafeRunner; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubMonitor; |
| import org.eclipse.core.variables.VariablesPlugin; |
| import org.eclipse.debug.core.DebugException; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.ILaunch; |
| import org.eclipse.debug.core.ILaunchConfiguration; |
| import org.eclipse.debug.core.ILaunchConfigurationListener; |
| import org.eclipse.debug.core.ILaunchConfigurationType; |
| import org.eclipse.debug.core.ILaunchDelegate; |
| import org.eclipse.debug.core.ILaunchListener; |
| import org.eclipse.debug.core.ILaunchManager; |
| import org.eclipse.debug.core.ILaunchMode; |
| import org.eclipse.debug.core.ILaunchesListener; |
| import org.eclipse.debug.core.ILaunchesListener2; |
| import org.eclipse.debug.core.model.IDebugTarget; |
| import org.eclipse.debug.core.model.IDisconnect; |
| import org.eclipse.debug.core.model.IPersistableSourceLocator; |
| import org.eclipse.debug.core.model.IProcess; |
| import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupDirector; |
| import org.eclipse.debug.core.sourcelookup.ISourceContainerType; |
| import org.eclipse.debug.core.sourcelookup.ISourcePathComputer; |
| import org.eclipse.debug.internal.core.sourcelookup.SourceContainerType; |
| import org.eclipse.debug.internal.core.sourcelookup.SourcePathComputer; |
| import org.eclipse.osgi.service.environment.Constants; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.helpers.DefaultHandler; |
| |
| import com.ibm.icu.text.MessageFormat; |
| |
| /** |
| * Manages launch configurations, launch configuration types, and registered launches. |
| * |
| * @see ILaunchManager |
| */ |
| public class LaunchManager extends PlatformObject implements ILaunchManager, IResourceChangeListener { |
| |
| /** |
| * Preferred launch delegate preference name. |
| * <p> |
| * Prior to 3.5 this preferred launch delegates for all launch |
| * configuration types were serialized into a single XML string |
| * and stored in this preference. |
| * </p> |
| * <p> |
| * Since 3.5, the preferred launch delegates are stored in a separate |
| * preference for each launch configuration type. The name of this |
| * preference is composed of the prefix, followed by a slash, followed by |
| * the launch configuration type id. The values contain a set of launch |
| * delegates, delimited by a semicolon, and each delegate entry contains |
| * the delegate ID, followed by a comma, followed by comma-delimited |
| * launch modes. |
| * |
| * @since 3.3 |
| */ |
| protected static final String PREF_PREFERRED_DELEGATES = DebugPlugin.getUniqueIdentifier() + ".PREFERRED_DELEGATES"; //$NON-NLS-1$ |
| |
| /** |
| * Constant to define debug.ui for the status codes |
| * |
| * @since 3.2 |
| */ |
| private static final String DEBUG_UI = "org.eclipse.debug.ui"; //$NON-NLS-1$ |
| |
| /** |
| * Listing of unsupported launch configuration names for the Win 32 platform |
| * @since 3.5 |
| */ |
| static final String[] UNSUPPORTED_WIN32_CONFIG_NAMES = new String[] {"aux", "clock$", "com1", "com2", "com3", "com4", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ |
| "com5", "com6", "com7", "com8", "com9", "con", "lpt1", "lpt2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ |
| "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "nul", "prn"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ |
| |
| /** |
| * Disallowed characters for launch configuration names |
| * '@' and '&' are disallowed because they corrupt menu items. |
| * |
| * @since 3.5 |
| */ |
| static final char[] DISALLOWED_CONFIG_NAME_CHARS = new char[] { '@', '&','\\', '/', ':', '*', '?', '"', '<', '>', '|', '\0' }; |
| |
| /** |
| * Status code for which a UI prompter is registered. |
| * |
| * @since 3.2 |
| */ |
| protected static final IStatus promptStatus = new Status(IStatus.INFO, DEBUG_UI, 200, IInternalDebugCoreConstants.EMPTY_STRING, null); |
| |
| /** |
| * Step filter manager |
| */ |
| private StepFilterManager fStepFilterManager = null; |
| |
| /** |
| * Notifies a launch config listener in a safe runnable to handle |
| * exceptions. |
| */ |
| class ConfigurationNotifier implements ISafeRunnable { |
| |
| private ILaunchConfigurationListener fListener; |
| private int fType; |
| private ILaunchConfiguration fConfiguration; |
| |
| /** |
| * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable) |
| */ |
| @Override |
| public void handleException(Throwable exception) { |
| IStatus status = new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "An exception occurred during launch configuration change notification.", exception); //$NON-NLS-1$ |
| DebugPlugin.log(status); |
| } |
| |
| /** |
| * Notifies the given listener of the add/change/remove |
| * |
| * @param configuration the configuration that has changed |
| * @param update the type of change |
| */ |
| public void notify(ILaunchConfiguration configuration, int update) { |
| fConfiguration = configuration; |
| fType = update; |
| if (fLaunchConfigurationListeners.size() > 0) { |
| Object[] listeners = fLaunchConfigurationListeners.getListeners(); |
| for (int i = 0; i < listeners.length; i++) { |
| fListener = (ILaunchConfigurationListener)listeners[i]; |
| SafeRunner.run(this); |
| } |
| } |
| fConfiguration = null; |
| fListener = null; |
| } |
| |
| /** |
| * @see org.eclipse.core.runtime.ISafeRunnable#run() |
| */ |
| @Override |
| public void run() throws Exception { |
| switch (fType) { |
| case ADDED: |
| fListener.launchConfigurationAdded(fConfiguration); |
| break; |
| case REMOVED: |
| fListener.launchConfigurationRemoved(fConfiguration); |
| break; |
| case CHANGED: |
| fListener.launchConfigurationChanged(fConfiguration); |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Notifies a launch listener (multiple launches) in a safe runnable to |
| * handle exceptions. |
| */ |
| class LaunchesNotifier implements ISafeRunnable { |
| |
| private ILaunchesListener fListener; |
| private int fType; |
| private ILaunch[] fNotifierLaunches; |
| private ILaunch[] fRegistered; |
| |
| /** |
| * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable) |
| */ |
| @Override |
| public void handleException(Throwable exception) { |
| IStatus status = new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "An exception occurred during launch change notification.", exception); //$NON-NLS-1$ |
| DebugPlugin.log(status); |
| } |
| |
| /** |
| * Notifies the given listener of the adds/changes/removes |
| * |
| * @param launches the launches that changed |
| * @param update the type of change |
| */ |
| public void notify(ILaunch[] launches, int update) { |
| fNotifierLaunches = launches; |
| fType = update; |
| fRegistered = null; |
| Object[] copiedListeners= fLaunchesListeners.getListeners(); |
| for (int i= 0; i < copiedListeners.length; i++) { |
| fListener = (ILaunchesListener)copiedListeners[i]; |
| SafeRunner.run(this); |
| } |
| fNotifierLaunches = null; |
| fRegistered = null; |
| fListener = null; |
| } |
| |
| /** |
| * @see org.eclipse.core.runtime.ISafeRunnable#run() |
| */ |
| @Override |
| public void run() throws Exception { |
| switch (fType) { |
| case ADDED: |
| fListener.launchesAdded(fNotifierLaunches); |
| break; |
| case REMOVED: |
| fListener.launchesRemoved(fNotifierLaunches); |
| break; |
| case CHANGED: |
| case TERMINATE: |
| if (fRegistered == null) { |
| List<ILaunch> registered = null; |
| for (int j = 0; j < fNotifierLaunches.length; j++) { |
| if (isRegistered(fNotifierLaunches[j])) { |
| if (registered != null) { |
| registered.add(fNotifierLaunches[j]); |
| } |
| } else { |
| if (registered == null) { |
| registered = new ArrayList<ILaunch>(fNotifierLaunches.length); |
| for (int k = 0; k < j; k++) { |
| registered.add(fNotifierLaunches[k]); |
| } |
| } |
| } |
| } |
| if (registered == null) { |
| fRegistered = fNotifierLaunches; |
| } else { |
| fRegistered = registered.toArray(new ILaunch[registered.size()]); |
| } |
| } |
| if (fRegistered.length > 0) { |
| if (fType == CHANGED) { |
| fListener.launchesChanged(fRegistered); |
| } |
| if (fType == TERMINATE && fListener instanceof ILaunchesListener2) { |
| ((ILaunchesListener2)fListener).launchesTerminated(fRegistered); |
| } |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Visitor for handling a resource begin deleted, and the need to check mapped configurations |
| * for auto-deletion |
| * @since 3.4 |
| */ |
| class MappedResourceVisitor implements IResourceDeltaVisitor { |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta) |
| */ |
| @Override |
| public boolean visit(IResourceDelta delta) throws CoreException { |
| if (0 != (delta.getFlags() & IResourceDelta.OPEN)) { |
| return false; |
| } |
| if(delta.getKind() == IResourceDelta.REMOVED && delta.getFlags() != IResourceDelta.MOVED_TO) { |
| ArrayList<ILaunchConfiguration> configs = collectAssociatedLaunches(delta.getResource()); |
| for (ILaunchConfiguration config : configs) { |
| try { |
| config.delete(); |
| } catch (CoreException e) { |
| DebugPlugin.log(e.getStatus()); |
| } |
| } |
| return false; |
| } |
| return true; |
| } |
| } |
| |
| /** |
| * Visitor for handling resource deltas. |
| */ |
| class LaunchManagerVisitor implements IResourceDeltaVisitor { |
| |
| /** |
| * @see IResourceDeltaVisitor#visit(IResourceDelta) |
| */ |
| @Override |
| public boolean visit(IResourceDelta delta) { |
| if (delta == null) { |
| return false; |
| } |
| if (0 != (delta.getFlags() & IResourceDelta.OPEN)) { |
| if (delta.getResource() instanceof IProject) { |
| IProject project = (IProject)delta.getResource(); |
| if (project.isOpen()) { |
| LaunchManager.this.projectOpened(project); |
| } else { |
| LaunchManager.this.projectClosed(project); |
| } |
| } |
| return false; |
| } |
| IResource resource = delta.getResource(); |
| if (resource instanceof IFile) { |
| IFile file = (IFile)resource; |
| if (ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION.equals(file.getFileExtension())) { |
| ILaunchConfiguration handle = new LaunchConfiguration(file); |
| switch (delta.getKind()) { |
| case IResourceDelta.ADDED : |
| LaunchManager.this.launchConfigurationAdded(handle); |
| break; |
| case IResourceDelta.REMOVED : |
| LaunchManager.this.launchConfigurationDeleted(handle); |
| break; |
| case IResourceDelta.CHANGED : |
| LaunchManager.this.launchConfigurationChanged(handle); |
| break; |
| default: |
| break; |
| } |
| } |
| return false; |
| } |
| return true; |
| } |
| } |
| |
| /** |
| * Notifies a launch listener (single launch) in a safe runnable to handle |
| * exceptions. |
| */ |
| class LaunchNotifier implements ISafeRunnable { |
| |
| private ILaunchListener fListener; |
| private int fType; |
| private ILaunch fLaunch; |
| |
| /** |
| * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable) |
| */ |
| @Override |
| public void handleException(Throwable exception) { |
| IStatus status = new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "An exception occurred during launch change notification.", exception); //$NON-NLS-1$ |
| DebugPlugin.log(status); |
| } |
| |
| /** |
| * Notifies listeners of the add/change/remove |
| * |
| * @param launch the launch that has changed |
| * @param update the type of change |
| */ |
| public void notify(ILaunch launch, int update) { |
| fLaunch = launch; |
| fType = update; |
| Object[] copiedListeners= fListeners.getListeners(); |
| for (int i= 0; i < copiedListeners.length; i++) { |
| fListener = (ILaunchListener)copiedListeners[i]; |
| SafeRunner.run(this); |
| } |
| fLaunch = null; |
| fListener = null; |
| } |
| |
| /** |
| * @see org.eclipse.core.runtime.ISafeRunnable#run() |
| */ |
| @Override |
| public void run() throws Exception { |
| switch (fType) { |
| case ADDED: |
| fListener.launchAdded(fLaunch); |
| break; |
| case REMOVED: |
| fListener.launchRemoved(fLaunch); |
| break; |
| case CHANGED: |
| if (isRegistered(fLaunch)) { |
| fListener.launchChanged(fLaunch); |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Collects files whose extension matches the launch configuration file |
| * extension. |
| */ |
| class ResourceProxyVisitor implements IResourceProxyVisitor { |
| |
| private List<IResource> fList; |
| |
| protected ResourceProxyVisitor(List<IResource> list) { |
| fList= list; |
| } |
| /** |
| * @see org.eclipse.core.resources.IResourceProxyVisitor#visit(org.eclipse.core.resources.IResourceProxy) |
| */ |
| @Override |
| public boolean visit(IResourceProxy proxy) { |
| if (proxy.getType() == IResource.FILE) { |
| if (ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION.equalsIgnoreCase(proxy.requestFullPath().getFileExtension())) { |
| fList.add(proxy.requestResource()); |
| } |
| return false; |
| } |
| return true; |
| } |
| } |
| |
| /** |
| * Internal class used to hold information about a preferred delegate |
| * |
| * @since 3.3 |
| */ |
| class PreferredDelegate { |
| private ILaunchDelegate fDelegate = null; |
| private String fTypeid = null; |
| private Set<String> fModes = null; |
| |
| public PreferredDelegate(ILaunchDelegate delegate, String typeid, Set<String> modes) { |
| fDelegate = delegate; |
| fTypeid = typeid; |
| fModes = modes; |
| } |
| |
| public String getTypeId() { |
| return fTypeid; |
| } |
| |
| public Set<String> getModes() { |
| return fModes; |
| } |
| |
| public ILaunchDelegate getDelegate() { |
| return fDelegate; |
| } |
| } |
| |
| /** |
| * Types of notifications |
| */ |
| public static final int ADDED = 0; |
| public static final int REMOVED= 1; |
| public static final int CHANGED= 2; |
| public static final int TERMINATE= 3; |
| |
| /** |
| * The collection of native environment variables on the user's system. Cached |
| * after being computed once as the environment cannot change. |
| */ |
| private static HashMap<String, String> fgNativeEnv = null; |
| private static HashMap<String, String> fgNativeEnvCasePreserved = null; |
| |
| /** |
| * Path to the local directory where local launch configurations |
| * are stored with the workspace. |
| */ |
| public static final IPath LOCAL_LAUNCH_CONFIGURATION_CONTAINER_PATH = |
| DebugPlugin.getDefault().getStateLocation().append(".launches"); //$NON-NLS-1$ |
| /** |
| * Returns a Document that can be used to build a DOM tree |
| * @return the Document |
| * @throws ParserConfigurationException if an exception occurs creating the document builder |
| * @since 3.0 |
| */ |
| public static Document getDocument() throws ParserConfigurationException { |
| DocumentBuilderFactory dfactory= DocumentBuilderFactory.newInstance(); |
| DocumentBuilder docBuilder= dfactory.newDocumentBuilder(); |
| Document doc= docBuilder.newDocument(); |
| return doc; |
| } |
| |
| /** |
| * Serializes a XML document into a string - encoded in UTF8 format, |
| * with platform line separators. |
| * |
| * @param doc document to serialize |
| * @return the document as a string |
| * @throws TransformerException if an unrecoverable error occurs during the serialization |
| * @throws IOException if the encoding attempted to be used is not supported |
| */ |
| public static String serializeDocument(Document doc) throws TransformerException, IOException { |
| ByteArrayOutputStream s = new ByteArrayOutputStream(); |
| TransformerFactory factory = TransformerFactory.newInstance(); |
| Transformer transformer = factory.newTransformer(); |
| transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ |
| transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ |
| DOMSource source = new DOMSource(doc); |
| StreamResult outputTarget = new StreamResult(s); |
| transformer.transform(source, outputTarget); |
| return s.toString("UTF8"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Collection of defined launch configuration type |
| * extensions. |
| */ |
| private List<ILaunchConfigurationType> fLaunchConfigurationTypes = null; |
| |
| /** |
| * Launch configuration cache. Keys are <code>LaunchConfiguration</code>, |
| * values are <code>LaunchConfigurationInfo</code>. |
| */ |
| private Map<ILaunchConfiguration, LaunchConfigurationInfo> fLaunchConfigurations = new HashMap<ILaunchConfiguration, LaunchConfigurationInfo>(10); |
| |
| /** |
| * A cache of launch configuration names currently in the workspace. |
| */ |
| private String[] fSortedConfigNames = null; |
| |
| /** |
| * Collection of all launch configurations in the workspace. |
| * <code>List</code> of <code>ILaunchConfiguration</code>. |
| */ |
| private List<ILaunchConfiguration> fLaunchConfigurationIndex = null; |
| |
| /** |
| * Launch configuration comparator extensions, |
| * keyed by attribute name. |
| */ |
| private Map<String, LaunchConfigurationComparator> fComparators = null; |
| |
| /** |
| * Registered launch modes, or <code>null</code> if not initialized. |
| * Keys are mode identifiers, values are <code>ILaunchMode</code>s. |
| */ |
| private Map<String, ILaunchMode> fLaunchModes = null; |
| |
| /** |
| * A map of LaunchDelegate objects stored by id of delegate, or launch config type |
| */ |
| private HashMap<String, LaunchDelegate> fLaunchDelegates = null; |
| |
| /** |
| * Initial startup cache of preferred delegate so that the debug preferences are only parsed once |
| * |
| * @since 3.3 |
| */ |
| private Set<PreferredDelegate> fPreferredDelegates = null; |
| |
| /** |
| * Collection of launches |
| */ |
| private List<ILaunch> fLaunches = new ArrayList<ILaunch>(10); |
| /** |
| * Set of launches for efficient 'isRegistered()' check TODO remove this - |
| * Launches don't implement hashCode() or equals() - so its no more |
| * efficient than walking the other collection |
| */ |
| private Set<ILaunch> fLaunchSet = new HashSet<ILaunch>(10); |
| |
| /** |
| * Collection of listeners |
| */ |
| private ListenerList fListeners = new ListenerList(); |
| |
| /** |
| * Collection of "plural" listeners. |
| * @since 2.1 |
| */ |
| private ListenerList fLaunchesListeners = new ListenerList(); |
| |
| /** |
| * Visitor used to process resource deltas, |
| * to update launch configuration index. |
| */ |
| private LaunchManagerVisitor fgVisitor; |
| |
| /** |
| * Visitor used to process a deleted resource, |
| * to remove mapped launch configurations in the event |
| * auto-removal of launch configurations is enabled |
| * |
| * @since 3.4 |
| */ |
| private MappedResourceVisitor fgMRVisitor; |
| |
| /** |
| * Whether this manager is listening for resource change events |
| */ |
| private boolean fListening = false; |
| |
| /** |
| * Launch configuration listeners |
| */ |
| private ListenerList fLaunchConfigurationListeners = new ListenerList(); |
| |
| /** |
| * Table of source locator extensions. Keys |
| * are identifiers, and values are associated |
| * configuration elements. |
| */ |
| private Map<String, IConfigurationElement> fSourceLocators = null; |
| |
| /** |
| * The handles of launch configurations being moved, or <code>null</code> |
| */ |
| private ILaunchConfiguration fFrom; |
| |
| private ILaunchConfiguration fTo; |
| |
| /** |
| * Map of source container type extensions. Keys are extension ids |
| * and values are associated configuration elements. |
| */ |
| private Map<String, ISourceContainerType> sourceContainerTypes; |
| |
| /** |
| * Map of source path computer extensions. Keys are extension ids |
| * and values are associated configuration elements. |
| */ |
| private Map<String, ISourcePathComputer> sourcePathComputers; |
| |
| /** |
| * TODO, we can probably remove this too |
| */ |
| private Set<String> fActiveModes; |
| |
| /** |
| * @see ILaunchManager#addLaunch(ILaunch) |
| */ |
| @Override |
| public void addLaunch(ILaunch launch) { |
| if (internalAddLaunch(launch)) { |
| fireUpdate(launch, ADDED); |
| fireUpdate(new ILaunch[] {launch}, ADDED); |
| } |
| } |
| |
| /** |
| * @see ILaunchManager#addLaunchConfigurationListener(ILaunchConfigurationListener) |
| */ |
| @Override |
| public void addLaunchConfigurationListener(ILaunchConfigurationListener listener) { |
| fLaunchConfigurationListeners.add(listener); |
| } |
| |
| /** |
| * @see org.eclipse.debug.core.ILaunchManager#addLaunches(org.eclipse.debug.core.ILaunch[]) |
| */ |
| @Override |
| public void addLaunches(ILaunch[] launches) { |
| List<ILaunch> added = new ArrayList<ILaunch>(launches.length); |
| for (int i = 0; i < launches.length; i++) { |
| if (internalAddLaunch(launches[i])) { |
| added.add(launches[i]); |
| } |
| } |
| if (!added.isEmpty()) { |
| ILaunch[] addedLaunches = added.toArray(new ILaunch[added.size()]); |
| fireUpdate(addedLaunches, ADDED); |
| for (int i = 0; i < addedLaunches.length; i++) { |
| fireUpdate(launches[i], ADDED); |
| } |
| } |
| } |
| |
| /** |
| * @see org.eclipse.debug.core.ILaunchManager#addLaunchListener(org.eclipse.debug.core.ILaunchesListener) |
| */ |
| @Override |
| public void addLaunchListener(ILaunchesListener listener) { |
| fLaunchesListeners.add(listener); |
| } |
| |
| /** |
| * @see ILaunchManager#addLaunchListener(ILaunchListener) |
| */ |
| @Override |
| public void addLaunchListener(ILaunchListener listener) { |
| fListeners.add(listener); |
| } |
| |
| /** |
| * Computes and caches the native system environment variables as a map of |
| * variable names and values (Strings) in the given map. |
| * <p> |
| * Note that WIN32 system environment preserves |
| * the case of variable names but is otherwise case insensitive. |
| * Depending on what you intend to do with the environment, the |
| * lack of normalization may or may not be create problems. This |
| * method preserves mixed-case keys using the variable names |
| * recorded by the OS. |
| * </p> |
| * @param cache the map |
| * @since 3.1 |
| */ |
| private void cacheNativeEnvironment(Map<String, String> cache) { |
| try { |
| String nativeCommand= null; |
| boolean isWin9xME= false; //see bug 50567 |
| String fileName= null; |
| if (Platform.getOS().equals(Constants.OS_WIN32)) { |
| String osName= System.getProperty("os.name"); //$NON-NLS-1$ |
| isWin9xME= osName != null && (osName.startsWith("Windows 9") || osName.startsWith("Windows ME")); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (isWin9xME) { |
| // Win 95, 98, and ME |
| // SET might not return therefore we pipe into a file |
| IPath stateLocation= DebugPlugin.getDefault().getStateLocation(); |
| fileName= stateLocation.toOSString() + File.separator + "env.txt"; //$NON-NLS-1$ |
| nativeCommand= "command.com /C set > " + fileName; //$NON-NLS-1$ |
| } else { |
| // Win NT, 2K, XP |
| nativeCommand= "cmd.exe /C set"; //$NON-NLS-1$ |
| } |
| } else if (!Platform.getOS().equals(Constants.OS_UNKNOWN)){ |
| nativeCommand= "env"; //$NON-NLS-1$ |
| } |
| if (nativeCommand == null) { |
| return; |
| } |
| Process process= Runtime.getRuntime().exec(nativeCommand); |
| if (isWin9xME) { |
| //read piped data on Win 95, 98, and ME |
| Properties p= new Properties(); |
| File file= new File(fileName); |
| try(InputStream stream = new BufferedInputStream(new FileInputStream(file))){ |
| p.load(stream); |
| if (!file.delete()) { |
| file.deleteOnExit(); // if delete() fails try again on VM close |
| } |
| for (Entry<Object, Object> entry : p.entrySet()) { |
| // Win32's environment variables are case insensitive. Put everything |
| // to uppercase so that (for example) the "PATH" variable will match |
| // "pAtH" correctly on Windows. |
| String key = (String) entry.getKey(); |
| //no need to cast value |
| cache.put(key, (String) p.get(key)); |
| } |
| } |
| } else { |
| //read process directly on other platforms |
| //we need to parse out matching '{' and '}' for function declarations in .bash environments |
| // pattern is [func name]=() { and we must find the '}' on its own line with no trailing ';' |
| try (InputStream stream = process.getInputStream(); |
| InputStreamReader isreader = new InputStreamReader(stream); |
| BufferedReader reader = new BufferedReader(isreader)) { |
| String line = reader.readLine(); |
| String key = null; |
| String value = null; |
| String newLine = System.getProperty("line.separator"); //$NON-NLS-1$ |
| while (line != null) { |
| int func = line.indexOf("=()"); //$NON-NLS-1$ |
| if (func > 0) { |
| key = line.substring(0, func); |
| // scan until we find the closing '}' with no |
| // following chars |
| value = line.substring(func + 1); |
| while (line != null && !line.equals("}")) { //$NON-NLS-1$ |
| line = reader.readLine(); |
| if (line != null) { |
| value += newLine + line; |
| } |
| } |
| line = reader.readLine(); |
| } |
| else { |
| int separator = line.indexOf('='); |
| if (separator > 0) { |
| key = line.substring(0, separator); |
| value = line.substring(separator + 1); |
| line = reader.readLine(); |
| if (line != null) { |
| // this line has a '=' read ahead to check |
| // next line for '=', might be broken on |
| // more than one line |
| // also if line starts with non-identifier - |
| // it is remainder of previous variable |
| while (line.indexOf('=') < 0 || (line.length() > 0 && !Character.isJavaIdentifierStart(line.charAt(0)))) { |
| value += newLine + line; |
| line = reader.readLine(); |
| if (line == null) { |
| // if next line read is the end of |
| // the file quit the loop |
| break; |
| } |
| } |
| } |
| } |
| } |
| if (key != null) { |
| cache.put(key, value); |
| key = null; |
| value = null; |
| } else { |
| line = reader.readLine(); |
| } |
| } |
| } |
| } |
| } catch (IOException e) { |
| // Native environment-fetching code failed. |
| // This can easily happen and is not useful to log. |
| } |
| } |
| |
| /** |
| * Clears all launch configurations (if any have been accessed) |
| */ |
| private void clearAllLaunchConfigurations() { |
| if (fLaunchConfigurationTypes != null) { |
| fLaunchConfigurationTypes.clear(); |
| } |
| if (fLaunchConfigurationIndex != null) { |
| fLaunchConfigurationIndex.clear(); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchManager#getEncoding(org.eclipse.debug.core.ILaunchConfiguration) |
| */ |
| @Override |
| public String getEncoding(ILaunchConfiguration configuration) throws CoreException { |
| String encoding = configuration.getAttribute(DebugPlugin.ATTR_CONSOLE_ENCODING, (String)null); |
| if(encoding == null) { |
| IResource[] resources = configuration.getMappedResources(); |
| if(resources != null && resources.length > 0) { |
| IResource res = resources[0]; |
| if(res instanceof IFile) { |
| return ((IFile)res).getCharset(); |
| } |
| else if(res instanceof IContainer) { |
| return ((IContainer)res).getDefaultCharset(); |
| } |
| } |
| else { |
| return ResourcesPlugin.getEncoding(); |
| } |
| } |
| return encoding; |
| } |
| |
| /** |
| * The launch config name cache is cleared when a config is added, deleted or changed. |
| */ |
| protected void clearConfigNameCache() { |
| fSortedConfigNames = null; |
| } |
| |
| /** |
| * Return an instance of DebugException containing the specified message and Throwable. |
| * @param message the message for the new {@link DebugException} |
| * @param throwable the underlying {@link Exception} |
| * @return the new {@link DebugException} |
| */ |
| protected DebugException createDebugException(String message, Throwable throwable) { |
| return new DebugException( |
| new Status( |
| IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), |
| DebugException.REQUEST_FAILED, message, throwable |
| ) |
| ); |
| } |
| |
| /** |
| * Return a LaunchConfigurationInfo object initialized from XML contained in |
| * the specified stream. Simply pass out any exceptions encountered so that |
| * caller can deal with them. This is important since caller may need access to the |
| * actual exception. |
| * |
| * @param stream the {@link InputStream} to read from |
| * @return the new {@link LaunchConfigurationInfo} |
| * @throws CoreException if a problem is encountered |
| * @throws ParserConfigurationException if the stream fails to parse |
| * @throws IOException if there is a problem handling the given stream or writing the new info file |
| * @throws SAXException if there is a SAX parse exception |
| */ |
| protected LaunchConfigurationInfo createInfoFromXML(InputStream stream) throws CoreException, |
| ParserConfigurationException, |
| IOException, |
| SAXException { |
| Element root = null; |
| DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); |
| parser.setErrorHandler(new DefaultHandler()); |
| root = parser.parse(new InputSource(stream)).getDocumentElement(); |
| LaunchConfigurationInfo info = new LaunchConfigurationInfo(); |
| info.initializeFromXML(root); |
| return info; |
| } |
| |
| /** |
| * Finds and returns all launch configurations in the given |
| * container (and sub-containers) |
| * |
| * @param container the container to search |
| * @return all launch configurations in the given container |
| */ |
| protected List<ILaunchConfiguration> findLaunchConfigurations(IContainer container) { |
| if (container instanceof IProject && !((IProject)container).isOpen()) { |
| return Collections.EMPTY_LIST; |
| } |
| List<IResource> list = new ArrayList<IResource>(10); |
| ResourceProxyVisitor visitor= new ResourceProxyVisitor(list); |
| try { |
| container.accept(visitor, IResource.NONE); |
| } catch (CoreException ce) { |
| //Closed project...should not be possible with previous check |
| } |
| List<ILaunchConfiguration> configs = new ArrayList<ILaunchConfiguration>(list.size()); |
| for (IResource resource : list) { |
| ILaunchConfiguration config = getLaunchConfiguration((IFile) resource); |
| if(config != null && config.exists()) { |
| configs.add(config); |
| } |
| } |
| return configs; |
| } |
| |
| /** |
| * Searches for the {@link ILaunchConfiguration} with the given name |
| * @param name the name to search for |
| * @return the {@link ILaunchConfiguration} with the given name or <code>null</code> |
| * @since 3.8 |
| */ |
| public ILaunchConfiguration findLaunchConfiguration(String name) { |
| if(name != null) { |
| ILaunchConfiguration[] configs = getLaunchConfigurations(); |
| for (int i = 0; i < configs.length; i++) { |
| if(name.equals(configs[i].getName())) { |
| return configs[i]; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Finds and returns all local launch configurations. |
| * |
| * @return all local launch configurations |
| */ |
| protected List<ILaunchConfiguration> findLocalLaunchConfigurations() { |
| IPath containerPath = LOCAL_LAUNCH_CONFIGURATION_CONTAINER_PATH; |
| final File directory = containerPath.toFile(); |
| if (directory.isDirectory()) { |
| FilenameFilter filter = new FilenameFilter() { |
| @Override |
| public boolean accept(File dir, String name) { |
| return dir.equals(directory) && |
| name.endsWith(ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION); |
| } |
| }; |
| File[] files = directory.listFiles(filter); |
| if (files.length > 0) { |
| List<ILaunchConfiguration> configs = new ArrayList<ILaunchConfiguration>(10); |
| LaunchConfiguration config = null; |
| for (int i = 0; i < files.length; i++) { |
| config = new LaunchConfiguration(LaunchConfiguration.getSimpleName(files[i].getName()), null); |
| configs.add(config); |
| } |
| return configs; |
| } |
| } |
| return Collections.EMPTY_LIST; |
| } |
| |
| /** |
| * Fires notification to (single) listeners that a launch has been |
| * added/changed/removed. |
| * |
| * @param launch launch that has changed |
| * @param update type of change |
| */ |
| public void fireUpdate(ILaunch launch, int update) { |
| new LaunchNotifier().notify(launch, update); |
| } |
| |
| /** |
| * Fires notification to (plural) listeners that a launch has been |
| * added/changed/removed. |
| * |
| * @param launches launches that have changed |
| * @param update type of change |
| */ |
| public void fireUpdate(ILaunch[] launches, int update) { |
| new LaunchesNotifier().notify(launches, update); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchManager#generateUniqueLaunchConfigurationNameFrom(java.lang.String) |
| */ |
| @Override |
| public String generateUniqueLaunchConfigurationNameFrom(String baseName) { |
| int index = 1; |
| int length = baseName.length(); |
| int copyIndex = baseName.lastIndexOf(" ("); //$NON-NLS-1$ |
| String base = baseName; |
| if (copyIndex > -1 && length > copyIndex + 2 && baseName.charAt(length - 1) == ')') { |
| String trailer = baseName.substring(copyIndex + 2, length - 1); |
| if (isNumber(trailer)) { |
| try { |
| index = Integer.parseInt(trailer); |
| base = baseName.substring(0, copyIndex); |
| } |
| catch (NumberFormatException nfe) {} |
| } |
| } |
| String newName = base; |
| while (isExistingLaunchConfigurationName(newName)) { |
| newName = MessageFormat.format(DebugCoreMessages.LaunchManager_31, new Object[] { |
| base, Integer.toString(index) }); |
| index++; |
| } |
| return newName; |
| } |
| |
| /** |
| * Return a String that can be used as the name of a launch configuration. The name |
| * is guaranteed to be unique (no existing or temporary launch configurations will have this name). |
| * The name that is returned uses the <code>basename</code> as a starting point. If |
| * there is no existing launch configuration with this name, then <code>basename</code> |
| * is returned. Otherwise, the value returned consists of the specified base plus |
| * some suffix that guarantees uniqueness. Passing <code>null</code> as the set of reserved names will cause this |
| * method to return <code>generateUniqueLaunchConfigurationNameFrom(String baseName)</code>. |
| * |
| * By specifying a set of reserved names, you can further constrain the name that will be generated |
| * by this method. For example you can give a base name of 'test' and a reserved set of [test(1), test(2)], |
| * which will result in a name of 'test(3)' being returned iff a configuration with the name 'test' already exists. |
| * |
| * @return launch configuration name |
| * @param basename the String that the returned name must begin with |
| * @param reservednames a set of strings that is further used to constrain what names can be generated |
| * @since 3.3 |
| */ |
| public String generateUniqueLaunchConfigurationNameFrom(String basename, Set<String> reservednames) { |
| if(reservednames == null) { |
| return generateUniqueLaunchConfigurationNameFrom(basename); |
| } |
| int index = 1; |
| int length= basename.length(); |
| String base = basename; |
| int copyIndex = base.lastIndexOf(" ("); //$NON-NLS-1$ |
| if (copyIndex > -1 && length > copyIndex + 2 && base.charAt(length - 1) == ')') { |
| String trailer = base.substring(copyIndex + 2, length -1); |
| if (isNumber(trailer)) { |
| try { |
| index = Integer.parseInt(trailer); |
| base = base.substring(0, copyIndex); |
| } |
| catch (NumberFormatException nfe) {} |
| } |
| } |
| String newname = base; |
| StringBuffer buffer = null; |
| while (isExistingLaunchConfigurationName(newname) || reservednames.contains(newname)) { |
| buffer = new StringBuffer(base); |
| buffer.append(" ("); //$NON-NLS-1$ |
| buffer.append(String.valueOf(index)); |
| index++; |
| buffer.append(')'); |
| newname = buffer.toString(); |
| } |
| return newname; |
| } |
| |
| /** |
| * Returns a collection of all launch configuration handles in |
| * the workspace. This collection is initialized lazily. |
| * |
| * @return all launch configuration handles |
| */ |
| private synchronized List<ILaunchConfiguration> getAllLaunchConfigurations() { |
| if (fLaunchConfigurationIndex == null) { |
| try { |
| fLaunchConfigurationIndex = new ArrayList<ILaunchConfiguration>(20); |
| List<ILaunchConfiguration> configs = findLocalLaunchConfigurations(); |
| verifyConfigurations(configs, fLaunchConfigurationIndex); |
| configs = findLaunchConfigurations(ResourcesPlugin.getWorkspace().getRoot()); |
| verifyConfigurations(configs, fLaunchConfigurationIndex); |
| } finally { |
| hookResourceChangeListener(); |
| } |
| } |
| return fLaunchConfigurationIndex; |
| } |
| |
| /** |
| * Return a sorted array of the names of all <code>ILaunchConfiguration</code>s in |
| * the workspace. These are cached, and cache is cleared when a new config is added, |
| * deleted or changed. |
| * @return the sorted array of {@link ILaunchConfiguration} names |
| */ |
| protected synchronized String[] getAllSortedConfigNames() { |
| if (fSortedConfigNames == null) { |
| ILaunchConfiguration[] configs = getLaunchConfigurations(); |
| fSortedConfigNames = new String[configs.length]; |
| for (int i = 0; i < configs.length; i++) { |
| fSortedConfigNames[i] = configs[i].getName(); |
| } |
| Arrays.sort(fSortedConfigNames); |
| } |
| return fSortedConfigNames; |
| } |
| |
| /** |
| * Returns the comparator registered for the given attribute, or |
| * <code>null</code> if none. |
| * |
| * @param attributeName attribute for which a comparator is required |
| * @return comparator, or <code>null</code> if none |
| */ |
| protected Comparator<Object> getComparator(String attributeName) { |
| Map<String, LaunchConfigurationComparator> map = getComparators(); |
| return map.get(attributeName); |
| } |
| |
| /** |
| * Returns comparators, loading if required |
| * @return the complete map of {@link ILaunchConfiguration} {@link Comparator}s |
| */ |
| protected Map<String, LaunchConfigurationComparator> getComparators() { |
| initializeComparators(); |
| return fComparators; |
| } |
| |
| /** |
| * Returns the launch configurations specified by the given |
| * XML document. |
| * |
| * @param root XML document |
| * @return list of launch configurations |
| * @throws CoreException if a problem is encountered |
| */ |
| protected List<ILaunchConfiguration> getConfigsFromXML(Element root) throws CoreException { |
| DebugException invalidFormat = |
| new DebugException( |
| new Status( |
| IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), |
| DebugException.REQUEST_FAILED, DebugCoreMessages.LaunchManager_Invalid_launch_configuration_index__18, null |
| ) |
| ); |
| |
| if (!root.getNodeName().equalsIgnoreCase("launchConfigurations")) { //$NON-NLS-1$ |
| throw invalidFormat; |
| } |
| |
| // read each launch configuration |
| List<ILaunchConfiguration> configs = new ArrayList<ILaunchConfiguration>(4); |
| NodeList list = root.getChildNodes(); |
| int length = list.getLength(); |
| Node node = null; |
| Element entry = null; |
| String memento = null; |
| for (int i = 0; i < length; ++i) { |
| node = list.item(i); |
| short type = node.getNodeType(); |
| if (type == Node.ELEMENT_NODE) { |
| entry = (Element) node; |
| if (!entry.getNodeName().equals("launchConfiguration")) { //$NON-NLS-1$ |
| throw invalidFormat; |
| } |
| memento = entry.getAttribute("memento"); //$NON-NLS-1$ |
| if (memento == null) { |
| throw invalidFormat; |
| } |
| configs.add(getLaunchConfiguration(memento)); |
| } |
| } |
| return configs; |
| } |
| |
| protected ConfigurationNotifier getConfigurationNotifier() { |
| return new ConfigurationNotifier(); |
| } |
| |
| /** |
| * @see ILaunchManager#getDebugTargets() |
| */ |
| @Override |
| public IDebugTarget[] getDebugTargets() { |
| synchronized (fLaunches) { |
| List<IDebugTarget> allTargets = new ArrayList<IDebugTarget>(fLaunches.size()); |
| IDebugTarget[] targets = null; |
| for (ILaunch launch : fLaunches) { |
| targets = launch.getDebugTargets(); |
| for (int i = 0; i < targets.length; i++) { |
| allTargets.add(targets[i]); |
| } |
| } |
| return allTargets.toArray(new IDebugTarget[allTargets.size()]); |
| } |
| } |
| |
| /** |
| * Returns the resource delta visitor for the launch manager. |
| * |
| * @return the resource delta visitor for the launch manager |
| */ |
| private LaunchManagerVisitor getDeltaVisitor() { |
| if (fgVisitor == null) { |
| fgVisitor= new LaunchManagerVisitor(); |
| } |
| return fgVisitor; |
| } |
| |
| /** |
| * Returns the resource delta visitor for auto-removal of mapped launch configurations |
| * @return the resource delta visitor for auto-removal of mapped launch configurations |
| * |
| * @since 3.4 |
| */ |
| private MappedResourceVisitor getMappedResourceVisitor() { |
| if(fgMRVisitor == null) { |
| fgMRVisitor = new MappedResourceVisitor(); |
| } |
| return fgMRVisitor; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchManager#getEnvironment(org.eclipse.debug.core.ILaunchConfiguration) |
| */ |
| @Override |
| public String[] getEnvironment(ILaunchConfiguration configuration) throws CoreException { |
| Map<String, String> configEnv = configuration.getAttribute(ATTR_ENVIRONMENT_VARIABLES, (Map<String, String>) null); |
| if (configEnv == null) { |
| return null; |
| } |
| Map<String, String> env = new HashMap<String, String>(); |
| // build base environment |
| boolean append = configuration.getAttribute(ATTR_APPEND_ENVIRONMENT_VARIABLES, true); |
| if (append) { |
| env.putAll(getNativeEnvironmentCasePreserved()); |
| } |
| |
| // Add variables from config |
| boolean win32= Platform.getOS().equals(Constants.OS_WIN32); |
| String key = null; |
| String value = null; |
| Object nativeValue = null; |
| String nativeKey = null; |
| for (Entry<String, String> entry : configEnv.entrySet()) { |
| key = entry.getKey(); |
| value = entry.getValue(); |
| // translate any string substitution variables |
| if (value != null) { |
| value = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(value); |
| } |
| boolean added= false; |
| if (win32) { |
| // First, check if the key is an exact match for an existing key. |
| nativeValue = env.get(key); |
| if (nativeValue != null) { |
| // If an exact match is found, just replace the value |
| env.put(key, value); |
| } else { |
| // Win32 variables are case-insensitive. If an exact match isn't found, iterate to |
| // check for a case-insensitive match. We maintain the key's case (see bug 86725), |
| // but do a case-insensitive comparison (for example, "pAtH" will still override "PATH"). |
| for (Entry<String, String> nativeEntry : env.entrySet()) { |
| nativeKey = (nativeEntry).getKey(); |
| if (nativeKey.equalsIgnoreCase(key)) { |
| nativeEntry.setValue(value); |
| added = true; |
| break; |
| } |
| } |
| } |
| } |
| if (!added) { |
| env.put(key, value); |
| } |
| } |
| List<String> strings = new ArrayList<String>(env.size()); |
| StringBuffer buffer = null; |
| for (Entry<String, String> entry : env.entrySet()) { |
| buffer = new StringBuffer(entry.getKey()); |
| buffer.append('=').append(entry.getValue()); |
| strings.add(buffer.toString()); |
| } |
| return strings.toArray(new String[strings.size()]); |
| } |
| |
| /** |
| * Returns the info object for the specified launch configuration. |
| * If the configuration exists, but is not yet in the cache, |
| * an info object is built and added to the cache. |
| * @param config the {@link ILaunchConfiguration} to get the info object from |
| * @return the {@link LaunchConfigurationInfo} object from the given {@link ILaunchConfiguration} |
| * |
| * @exception CoreException if an exception occurs building |
| * the info object |
| * @exception DebugException if the config does not exist |
| * @since 3.5 |
| */ |
| protected LaunchConfigurationInfo getInfo(LaunchConfiguration config) throws CoreException { |
| LaunchConfigurationInfo info = fLaunchConfigurations.get(config); |
| if (info == null) { |
| IFileStore store = config.getFileStore(); |
| if (config.exists()) { |
| BufferedInputStream stream = null; |
| try { |
| stream = new BufferedInputStream(store.openInputStream(EFS.NONE, null)); |
| info = createInfoFromXML(stream); |
| synchronized (this) { |
| fLaunchConfigurations.put(config, info); |
| } |
| } catch (FileNotFoundException e) { |
| throwException(config, e); |
| } catch (SAXException e) { |
| throwException(config, e); |
| } catch (ParserConfigurationException e) { |
| throwException(config, e); |
| } catch (IOException e) { |
| throwException(config, e); |
| } finally { |
| if (stream != null) { |
| try { |
| stream.close(); |
| } catch (IOException e) { |
| throwException(config, e); |
| } |
| } |
| } |
| |
| } else { |
| if (store != null){ |
| throw createDebugException(MessageFormat.format(DebugCoreMessages.LaunchManager_does_not_exist, new Object[] { |
| config.getName(), store.toURI().toString() }), null); |
| } else { |
| throw createDebugException(MessageFormat.format(DebugCoreMessages.LaunchManager_does_not_exist_no_store_found, new Object[] { config.getName() }), null); |
| } |
| } |
| } |
| return info; |
| } |
| |
| /** |
| * @see ILaunchManager#getLaunchConfiguration(IFile) |
| */ |
| @Override |
| public ILaunchConfiguration getLaunchConfiguration(IFile file) { |
| hookResourceChangeListener(); |
| return new LaunchConfiguration(file); |
| } |
| |
| /** |
| * @see ILaunchManager#getLaunchConfiguration(String) |
| */ |
| @Override |
| public ILaunchConfiguration getLaunchConfiguration(String memento) throws CoreException { |
| hookResourceChangeListener(); |
| return new LaunchConfiguration(memento); |
| } |
| |
| /** |
| * @see ILaunchManager#getLaunchConfigurations() |
| */ |
| @Override |
| public synchronized ILaunchConfiguration[] getLaunchConfigurations() { |
| List<ILaunchConfiguration> allConfigs = getAllLaunchConfigurations(); |
| return allConfigs.toArray(new ILaunchConfiguration[allConfigs.size()]); |
| } |
| |
| /** |
| * @see ILaunchManager#getLaunchConfigurations(ILaunchConfigurationType) |
| */ |
| @Override |
| public synchronized ILaunchConfiguration[] getLaunchConfigurations(ILaunchConfigurationType type) throws CoreException { |
| List<ILaunchConfiguration> configs = new ArrayList<ILaunchConfiguration>(); |
| for (ILaunchConfiguration config : getAllLaunchConfigurations()) { |
| if (config.getType().equals(type)) { |
| configs.add(config); |
| } |
| } |
| return configs.toArray(new ILaunchConfiguration[configs.size()]); |
| } |
| |
| /** |
| * Returns all launch configurations that are stored as resources |
| * in the given project. |
| * |
| * @param project a project |
| * @return collection of launch configurations that are stored as resources |
| * in the given project |
| */ |
| protected synchronized List<ILaunchConfiguration> getLaunchConfigurations(IProject project) { |
| List<ILaunchConfiguration> configs = new ArrayList<ILaunchConfiguration>(); |
| for (ILaunchConfiguration config : getAllLaunchConfigurations()) { |
| IFile file = config.getFile(); |
| if (file != null && file.getProject().equals(project)) { |
| configs.add(config); |
| } |
| } |
| return configs; |
| } |
| |
| /** |
| * @see ILaunchManager#getLaunchConfigurationType(String) |
| */ |
| @Override |
| public ILaunchConfigurationType getLaunchConfigurationType(String id) { |
| ILaunchConfigurationType[] types = getLaunchConfigurationTypes(); |
| for(int i = 0; i < types.length; i++) { |
| if (types[i].getIdentifier().equals(id)) { |
| return types[i]; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * @see ILaunchManager#getLaunchConfigurationTypes() |
| */ |
| @Override |
| public ILaunchConfigurationType[] getLaunchConfigurationTypes() { |
| initializeLaunchConfigurationTypes(); |
| return fLaunchConfigurationTypes.toArray(new ILaunchConfigurationType[fLaunchConfigurationTypes.size()]); |
| } |
| |
| /** |
| * @see ILaunchManager#getLaunches() |
| */ |
| @Override |
| public ILaunch[] getLaunches() { |
| synchronized (fLaunches) { |
| return fLaunches.toArray(new ILaunch[fLaunches.size()]); |
| } |
| } |
| |
| /**) |
| * @see org.eclipse.debug.core.ILaunchManager#getLaunchMode(java.lang.String) |
| */ |
| @Override |
| public ILaunchMode getLaunchMode(String mode) { |
| initializeLaunchModes(); |
| return fLaunchModes.get(mode); |
| } |
| |
| /** |
| * @see org.eclipse.debug.core.ILaunchManager#getLaunchModes() |
| */ |
| @Override |
| public ILaunchMode[] getLaunchModes() { |
| initializeLaunchModes(); |
| Collection<ILaunchMode> collection = fLaunchModes.values(); |
| return collection.toArray(new ILaunchMode[collection.size()]); |
| } |
| |
| /** |
| * Returns all of the launch delegates. The returned listing of delegates cannot be directly used to launch, |
| * instead the method <code>IlaunchDelegate.getDelegate</code> must be used to acquire an executable form of |
| * the delegate, allowing us to maintain lazy loading of the delegates themselves. |
| * @return all of the launch delegates |
| * |
| * @since 3.3 |
| */ |
| public ILaunchDelegate[] getLaunchDelegates() { |
| initializeLaunchDelegates(); |
| Collection<LaunchDelegate> col = fLaunchDelegates.values(); |
| return col.toArray(new ILaunchDelegate[col.size()]); |
| } |
| |
| /** |
| * Returns the listing of launch delegates that apply to the specified |
| * <code>ILaunchConfigurationType</code> id |
| * @param typeid the id of the launch configuration type to get delegates for |
| * @return An array of <code>LaunchDelegate</code>s that apply to the specified launch configuration |
| * type, or an empty array, never <code>null</code> |
| * |
| * @since 3.3 |
| */ |
| public LaunchDelegate[] getLaunchDelegates(String typeid) { |
| initializeLaunchDelegates(); |
| ArrayList<LaunchDelegate> list = new ArrayList<LaunchDelegate>(); |
| for (Entry<String, LaunchDelegate> entry : fLaunchDelegates.entrySet()) { |
| LaunchDelegate ld = entry.getValue(); |
| if (ld.getLaunchConfigurationTypeId().equals(typeid)) { |
| list.add(ld); |
| } |
| } |
| return list.toArray(new LaunchDelegate[list.size()]); |
| } |
| |
| /** |
| * This method returns the <code>ILaunchDelegate</code> instance corresponding to the id |
| * of the launch delegate specified |
| * @param id the id of the <code>ILaunchDelegate</code> to find |
| * @return the <code>ILaunchDelegate</code> or <code>null</code> if not found |
| * |
| * @since 3.3 |
| */ |
| public ILaunchDelegate getLaunchDelegate(String id) { |
| if(id != null) { |
| ILaunchDelegate[] delegates = getLaunchDelegates(); |
| for(int i = 0; i < delegates.length; i++) { |
| if(id.equals(delegates[i].getId())) { |
| return delegates[i]; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Initializes the listing of delegates available to the launching framework |
| * |
| * @since 3.3 |
| */ |
| private synchronized void initializeLaunchDelegates() { |
| if(fLaunchDelegates == null) { |
| fLaunchDelegates = new HashMap<String, LaunchDelegate>(); |
| //get all launch delegate contributions |
| IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(DebugPlugin.getUniqueIdentifier(), DebugPlugin.EXTENSION_POINT_LAUNCH_DELEGATES); |
| IConfigurationElement[] infos = extensionPoint.getConfigurationElements(); |
| LaunchDelegate delegate = null; |
| for(int i = 0; i < infos.length; i++) { |
| delegate = new LaunchDelegate(infos[i]); |
| fLaunchDelegates.put(delegate.getId(), delegate); |
| } |
| //get all delegates from launch configuration type contributions |
| extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(DebugPlugin.getUniqueIdentifier(), DebugPlugin.EXTENSION_POINT_LAUNCH_CONFIGURATION_TYPES); |
| infos = extensionPoint.getConfigurationElements(); |
| for(int i = 0; i < infos.length; i++) { |
| //must check to see if delegate is provided in contribution |
| if(infos[i].getAttribute(IConfigurationElementConstants.DELEGATE) != null) { |
| delegate = new LaunchDelegate(infos[i]); |
| fLaunchDelegates.put(delegate.getId(), delegate); |
| } |
| } |
| } |
| } |
| |
| /** |
| * This method is used to initialize a simple listing of all preferred delegates, which is then used by each |
| * <code>ILaunchConfigurationType</code> to find if they have preferred delegates. Once an <code>ILaunchConfigurationType</code> |
| * has used this listing to initialize its preferred delegates it will maintain changes to its preferred delegate, which are |
| * then written back to the preference store only when the launch manager shuts down. |
| * <p> |
| * This cache is not synchronized with the runtime preferred delegates stored in launch configuration types. |
| * </p> |
| * @since 3.3 |
| */ |
| private synchronized void initializePreferredDelegates() { |
| if(fPreferredDelegates == null) { |
| fPreferredDelegates = new HashSet<PreferredDelegate>(); |
| String preferred = Platform.getPreferencesService().getString(DebugPlugin.getUniqueIdentifier(), LaunchManager.PREF_PREFERRED_DELEGATES, IInternalDebugCoreConstants.EMPTY_STRING, null); |
| if(!IInternalDebugCoreConstants.EMPTY_STRING.equals(preferred)) { |
| try { |
| Element root = DebugPlugin.parseDocument(preferred); |
| NodeList nodes = root.getElementsByTagName(IConfigurationElementConstants.DELEGATE); |
| Element element = null; |
| String typeid = null; |
| Set<String> modeset = null; |
| for(int i = 0; i < nodes.getLength(); i++) { |
| element = (Element) nodes.item(i); |
| String delegateid = element.getAttribute(IConfigurationElementConstants.ID); |
| typeid = element.getAttribute(IConfigurationElementConstants.TYPE_ID); |
| String[] modes = element.getAttribute(IConfigurationElementConstants.MODES).split(","); //$NON-NLS-1$ |
| modeset = new HashSet<String>(Arrays.asList(modes)); |
| LaunchDelegate delegate = getLaunchDelegateExtension(typeid, delegateid, modeset); |
| if (delegate != null) { |
| //take type id, modeset, delegate and create entry |
| if(!IInternalDebugCoreConstants.EMPTY_STRING.equals(typeid) & modeset != null) { |
| fPreferredDelegates.add(new PreferredDelegate(delegate, typeid, modeset)); |
| } |
| } |
| } |
| } |
| catch (CoreException e) {DebugPlugin.log(e);} |
| } |
| } |
| } |
| |
| /** |
| * Allows internal access to reset preferred delegates when re-importing |
| * preferences. |
| * |
| * @since 3.6 |
| */ |
| protected void resetPreferredDelegates() { |
| fPreferredDelegates = null; |
| } |
| |
| /** |
| * Allows internal access to a preferred delegate for a given type and mode set |
| * @param typeid the id of the <code>ILaunchConfigurationType</code> to find a delegate for |
| * @param modes the set of modes for the delegate |
| * @return the preferred delegate for the specified type id and mode set, or <code>null</code> if none |
| * |
| * @since 3.3 |
| */ |
| protected ILaunchDelegate getPreferredDelegate(String typeid, Set<String> modes) { |
| // Retrieve preferred delegates using legacy mechanism for backward |
| // compatibility. |
| initializePreferredDelegates(); |
| for (PreferredDelegate pd : fPreferredDelegates) { |
| if(pd.getModes().equals(modes) & pd.getTypeId().equals(typeid)) { |
| return pd.getDelegate(); |
| } |
| } |
| |
| // @since 3.5 |
| // If the legacy mechanism didn't work, try the new preference name for |
| // the given launch type. |
| String preferred = Platform.getPreferencesService().getString(DebugPlugin.getUniqueIdentifier(), "//" + LaunchManager.PREF_PREFERRED_DELEGATES + '/' + typeid, IInternalDebugCoreConstants.EMPTY_STRING, null); //$NON-NLS-1$ |
| if (preferred != null && preferred.length() != 0) { |
| StringTokenizer tokenizer = new StringTokenizer(preferred, ";"); //$NON-NLS-1$ |
| while(tokenizer.hasMoreTokens()) { |
| StringTokenizer tokenizer2 = new StringTokenizer(tokenizer.nextToken(), ","); //$NON-NLS-1$ |
| String delegateId = tokenizer2.nextToken(); |
| HashSet<String> modeset = new HashSet<String>(); |
| while(tokenizer2.hasMoreTokens()) { |
| modeset.add(tokenizer2.nextToken()); |
| } |
| LaunchDelegate delegate = getLaunchDelegateExtension(typeid, delegateId, modeset); |
| if (delegate != null && modeset.equals(modes)) { |
| return delegate; |
| } |
| } |
| |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the launch delegate extension that matches the given type, delegate ID, and |
| * set of modes. |
| * |
| * @param typeId Launch configuration type. |
| * @param id Launch delegate ID. |
| * @param modeset Set of modes that the launch delegate applies to. |
| * @return The launch delegate matching the specified parameters, or |
| * <code>null</code> if not found. |
| * |
| * @since 3.5 |
| */ |
| private LaunchDelegate getLaunchDelegateExtension(String typeId, String id, Set<String> modeset) { |
| LaunchDelegate[] extensions = getLaunchDelegates(typeId); |
| for(int j = 0; j < extensions.length; j++) { |
| if(id.equals(extensions[j].getId())) { |
| List<Set<String>> modesets = extensions[j].getModes(); |
| if(modesets.contains(modeset)) { |
| return extensions[j]; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns all launch configurations that are stored locally. |
| * |
| * @return collection of launch configurations stored locally |
| */ |
| protected synchronized List<ILaunchConfiguration> getLocalLaunchConfigurations() { |
| List<ILaunchConfiguration> configs = new ArrayList<ILaunchConfiguration>(); |
| for (ILaunchConfiguration config : getAllLaunchConfigurations()) { |
| if (config.isLocal()) { |
| configs.add(config); |
| } |
| } |
| return configs; |
| } |
| |
| /** |
| * Returns the launch configurations mapping to the specified resource |
| * @param resource the resource to collect mapped launch configurations for |
| * @return a list of launch configurations if found or an empty list, never null |
| * @since 3.2 |
| */ |
| public ILaunchConfiguration[] getMappedConfigurations(IResource resource) { |
| List<ILaunchConfiguration> configurations = new ArrayList<ILaunchConfiguration>(); |
| for (ILaunchConfiguration config : getAllLaunchConfigurations()) { |
| try { |
| IResource[] resources = config.getMappedResources(); |
| if(resources != null) { |
| for(int j = 0; j < resources.length; j++) { |
| if(resources[j].equals(resource)) { |
| configurations.add(config); |
| break; |
| } |
| } |
| } |
| } catch (CoreException ce) { |
| DebugPlugin.log(ce); |
| } |
| } |
| return configurations.toArray(new ILaunchConfiguration[configurations.size()]); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchManager#getMigrationCandidates() |
| */ |
| @Override |
| public ILaunchConfiguration[] getMigrationCandidates() throws CoreException { |
| List<ILaunchConfiguration> configs = new ArrayList<ILaunchConfiguration>(); |
| for (ILaunchConfiguration config : getAllLaunchConfigurations()) { |
| if (!config.isReadOnly() && config.isMigrationCandidate()) { |
| configs.add(config); |
| } |
| } |
| return configs.toArray(new ILaunchConfiguration[configs.size()]); |
| } |
| |
| /** |
| * @see org.eclipse.debug.core.ILaunchManager#getMovedFrom(org.eclipse.debug.core.ILaunchConfiguration) |
| */ |
| @Override |
| public ILaunchConfiguration getMovedFrom(ILaunchConfiguration addedConfiguration) { |
| if (addedConfiguration.equals(fTo)) { |
| return fFrom; |
| } |
| return null; |
| } |
| |
| /** |
| * @see org.eclipse.debug.core.ILaunchManager#getMovedTo(org.eclipse.debug.core.ILaunchConfiguration) |
| */ |
| @Override |
| public ILaunchConfiguration getMovedTo(ILaunchConfiguration removedConfiguration) { |
| if (removedConfiguration.equals(fFrom)) { |
| return fTo; |
| } |
| return null; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchManager#getNativeEnvironment() |
| */ |
| @Override |
| public synchronized Map<String, String> getNativeEnvironment() { |
| if (fgNativeEnv == null) { |
| Map<String, String> casePreserved = getNativeEnvironmentCasePreserved(); |
| if (Platform.getOS().equals(Constants.OS_WIN32)) { |
| fgNativeEnv = new HashMap<String, String>(); |
| for (Entry<String, String> entry : casePreserved.entrySet()) { |
| fgNativeEnv.put(entry.getKey().toUpperCase(), entry.getValue()); |
| } |
| } else { |
| fgNativeEnv = new HashMap<String, String>(casePreserved); |
| } |
| } |
| return new HashMap<String, String>(fgNativeEnv); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchManager#getNativeEnvironmentCasePreserved() |
| */ |
| @Override |
| public synchronized Map<String, String> getNativeEnvironmentCasePreserved() { |
| if (fgNativeEnvCasePreserved == null) { |
| fgNativeEnvCasePreserved = new HashMap<String, String>(); |
| cacheNativeEnvironment(fgNativeEnvCasePreserved); |
| } |
| return new HashMap<String, String>(fgNativeEnvCasePreserved); |
| } |
| |
| /** |
| * @see ILaunchManager#getProcesses() |
| */ |
| @Override |
| public IProcess[] getProcesses() { |
| synchronized (fLaunches) { |
| List<IProcess> allProcesses = new ArrayList<IProcess>(fLaunches.size()); |
| IProcess[] processes = null; |
| for (ILaunch launch : fLaunches) { |
| processes = launch.getProcesses(); |
| for (int i= 0; i < processes.length; i++) { |
| allProcesses.add(processes[i]); |
| } |
| } |
| return allProcesses.toArray(new IProcess[allProcesses.size()]); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchManager#getSourceContainerType(java.lang.String) |
| */ |
| @Override |
| public ISourceContainerType getSourceContainerType(String id) { |
| initializeSourceContainerTypes(); |
| return sourceContainerTypes.get(id); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchManager#getSourceContainerTypes() |
| */ |
| @Override |
| public ISourceContainerType[] getSourceContainerTypes() { |
| initializeSourceContainerTypes(); |
| Collection<ISourceContainerType> containers = sourceContainerTypes.values(); |
| return containers.toArray(new ISourceContainerType[containers.size()]); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchManager#newSourcePathComputer(org.eclipse.debug.core.ILaunchConfiguration) |
| */ |
| @Override |
| public ISourcePathComputer getSourcePathComputer(ILaunchConfiguration configuration) throws CoreException { |
| String id = null; |
| id = configuration.getAttribute(ISourcePathComputer.ATTR_SOURCE_PATH_COMPUTER_ID, (String)null); |
| |
| if (id == null) { |
| //use default computer for configuration type, if any |
| return configuration.getType().getSourcePathComputer(); |
| } |
| return getSourcePathComputer(id); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchManager#getSourcePathComputer(java.lang.String) |
| */ |
| @Override |
| public ISourcePathComputer getSourcePathComputer(String id) { |
| initializeSourceContainerTypes(); |
| return sourcePathComputers.get(id); |
| } |
| |
| /** |
| * Starts listening for resource change events |
| */ |
| private synchronized void hookResourceChangeListener() { |
| if (!fListening) { |
| ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_DELETE); |
| fListening = true; |
| } |
| } |
| |
| /** |
| * Load comparator extensions. |
| */ |
| private synchronized void initializeComparators() { |
| if (fComparators == null) { |
| IExtensionPoint extensionPoint= Platform.getExtensionRegistry().getExtensionPoint(DebugPlugin.getUniqueIdentifier(), DebugPlugin.EXTENSION_POINT_LAUNCH_CONFIGURATION_COMPARATORS); |
| IConfigurationElement[] infos= extensionPoint.getConfigurationElements(); |
| fComparators = new HashMap<String, LaunchConfigurationComparator>(infos.length); |
| IConfigurationElement configurationElement = null; |
| String attr = null; |
| for (int i= 0; i < infos.length; i++) { |
| configurationElement = infos[i]; |
| attr = configurationElement.getAttribute("attribute"); //$NON-NLS-1$ |
| if (attr != null) { |
| fComparators.put(attr, new LaunchConfigurationComparator(configurationElement)); |
| } else { |
| // invalid status handler |
| IStatus s = new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugException.INTERNAL_ERROR, |
| MessageFormat.format("Invalid launch configuration comparator extension defined by plug-in {0} - attribute not specified.", new Object[] { configurationElement.getContributor().getName() }), null); //$NON-NLS-1$ |
| DebugPlugin.log(s); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Initializes the listing of <code>LaunchConfigurationType</code>s. |
| */ |
| private synchronized void initializeLaunchConfigurationTypes() { |
| if (fLaunchConfigurationTypes == null) { |
| hookResourceChangeListener(); |
| IExtensionPoint extensionPoint= Platform.getExtensionRegistry().getExtensionPoint(DebugPlugin.getUniqueIdentifier(), DebugPlugin.EXTENSION_POINT_LAUNCH_CONFIGURATION_TYPES); |
| IConfigurationElement[] infos = extensionPoint.getConfigurationElements(); |
| fLaunchConfigurationTypes = new ArrayList<ILaunchConfigurationType>(infos.length); |
| for (int i= 0; i < infos.length; i++) { |
| fLaunchConfigurationTypes.add(new LaunchConfigurationType(infos[i])); |
| } |
| } |
| } |
| |
| /** |
| * Load comparator extensions. |
| */ |
| private synchronized void initializeLaunchModes() { |
| if (fLaunchModes == null) { |
| try { |
| IExtensionPoint extensionPoint= Platform.getExtensionRegistry().getExtensionPoint(DebugPlugin.getUniqueIdentifier(), DebugPlugin.EXTENSION_POINT_LAUNCH_MODES); |
| IConfigurationElement[] infos= extensionPoint.getConfigurationElements(); |
| fLaunchModes = new HashMap<String, ILaunchMode>(); |
| ILaunchMode mode = null; |
| for (int i= 0; i < infos.length; i++) { |
| mode = new LaunchMode(infos[i]); |
| fLaunchModes.put(mode.getIdentifier(), mode); |
| } |
| } |
| catch (CoreException e) {DebugPlugin.log(e);} |
| } |
| } |
| |
| /** |
| * Initializes source container type and source path computer extensions. |
| */ |
| private synchronized void initializeSourceContainerTypes() { |
| if (sourceContainerTypes == null) { |
| IExtensionPoint extensionPoint= Platform.getExtensionRegistry().getExtensionPoint(DebugPlugin.getUniqueIdentifier(), DebugPlugin.EXTENSION_POINT_SOURCE_CONTAINER_TYPES); |
| IConfigurationElement[] extensions = extensionPoint.getConfigurationElements(); |
| sourceContainerTypes = new HashMap<String, ISourceContainerType>(); |
| for (int i = 0; i < extensions.length; i++) { |
| sourceContainerTypes.put( |
| extensions[i].getAttribute(IConfigurationElementConstants.ID), |
| new SourceContainerType(extensions[i])); |
| } |
| extensionPoint= Platform.getExtensionRegistry().getExtensionPoint(DebugPlugin.getUniqueIdentifier(), DebugPlugin.EXTENSION_POINT_SOURCE_PATH_COMPUTERS); |
| extensions = extensionPoint.getConfigurationElements(); |
| sourcePathComputers = new HashMap<String, ISourcePathComputer>(); |
| for (int i = 0; i < extensions.length; i++) { |
| sourcePathComputers.put( |
| extensions[i].getAttribute(IConfigurationElementConstants.ID), |
| new SourcePathComputer(extensions[i])); |
| } |
| } |
| } |
| |
| /** |
| * Register source locators. |
| */ |
| private synchronized void initializeSourceLocators() { |
| if (fSourceLocators == null) { |
| IExtensionPoint extensionPoint= Platform.getExtensionRegistry().getExtensionPoint(DebugPlugin.getUniqueIdentifier(), DebugPlugin.EXTENSION_POINT_SOURCE_LOCATORS); |
| IConfigurationElement[] infos= extensionPoint.getConfigurationElements(); |
| fSourceLocators = new HashMap<String, IConfigurationElement>(infos.length); |
| IConfigurationElement configurationElement = null; |
| String id = null; |
| for (int i= 0; i < infos.length; i++) { |
| configurationElement = infos[i]; |
| id = configurationElement.getAttribute(IConfigurationElementConstants.ID); |
| if (id != null) { |
| fSourceLocators.put(id,configurationElement); |
| } else { |
| // invalid status handler |
| IStatus s = new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugException.INTERNAL_ERROR, |
| MessageFormat.format("Invalid source locator extension defined by plug-in \"{0}\": \"id\" not specified.", new Object[] { configurationElement.getContributor().getName() }), null); //$NON-NLS-1$ |
| DebugPlugin.log(s); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Adds the given launch object to the list of registered launches, |
| * and returns whether the launch was added. |
| * |
| * @param launch launch to register |
| * @return whether the launch was added |
| */ |
| protected boolean internalAddLaunch(ILaunch launch) { |
| // ensure the step filter manager is created on the first launch |
| getStepFilterManager(); |
| synchronized (fLaunches) { |
| if (fLaunches.contains(launch)) { |
| return false; |
| } |
| fLaunches.add(launch); |
| fLaunchSet.add(launch); |
| return true; |
| } |
| } |
| |
| /** |
| * Removes the given launch object from the collection of registered |
| * launches. Returns whether the launch was removed. |
| * |
| * @param launch the launch to remove |
| * @return whether the launch was removed |
| */ |
| protected boolean internalRemoveLaunch(ILaunch launch) { |
| if (launch == null) { |
| return false; |
| } |
| synchronized (fLaunches) { |
| fLaunchSet.remove(launch); |
| return fLaunches.remove(launch); |
| } |
| } |
| /** |
| * @see ILaunchManager#isExistingLaunchConfigurationName(String) |
| */ |
| @Override |
| public boolean isExistingLaunchConfigurationName(String name) { |
| String[] sortedConfigNames = getAllSortedConfigNames(); |
| int index = Arrays.binarySearch(sortedConfigNames, name); |
| if (index < 0) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Returns whether the given String is composed solely of digits |
| * @param string the {@link String} to check |
| * @return <code>true</code> if the given {@link String} is a number <code>false</code> otherwise |
| */ |
| private boolean isNumber(String string) { |
| int numChars= string.length(); |
| if (numChars == 0) { |
| return false; |
| } |
| for (int i= 0; i < numChars; i++) { |
| if (!Character.isDigit(string.charAt(i))) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Returns whether the user has selected to delete associated configurations when a |
| * project is deleted. |
| * |
| * @return whether to auto-delete configurations |
| */ |
| private boolean isDeleteConfigurations() { |
| return Platform.getPreferencesService().getBoolean(DebugPlugin.getUniqueIdentifier(), DebugPlugin.PREF_DELETE_CONFIGS_ON_PROJECT_DELETE, true, null); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILaunchManager#isRegistered(org.eclipse.debug.core.ILaunch) |
| */ |
| @Override |
| public boolean isRegistered(ILaunch launch) { |
| synchronized (fLaunches) { |
| return fLaunchSet.contains(launch); |
| } |
| } |
| |
| /** |
| * Returns whether the given launch configuration passes a basic |
| * integrity test by retrieving its type. |
| * |
| * @param config the configuration to verify |
| * @return whether the config meets basic integrity constraints |
| */ |
| protected boolean isValid(ILaunchConfiguration config) { |
| try { |
| config.getType(); |
| } catch (CoreException e) { |
| if (e.getStatus().getCode() != DebugException.MISSING_LAUNCH_CONFIGURATION_TYPE) { |
| // only log warnings due to something other than a missing |
| // launch config type |
| DebugPlugin.log(e); |
| } |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Notifies the launch manager that a launch configuration |
| * has been added. The configuration is added to the index of |
| * configurations by project, and listeners are notified. |
| * |
| * @param config the launch configuration that was added |
| */ |
| protected void launchConfigurationAdded(ILaunchConfiguration config) { |
| if (config.isWorkingCopy()) { |
| return; |
| } |
| if (isValid(config)) { |
| boolean added = false; |
| synchronized (this) { |
| List<ILaunchConfiguration> allConfigs = getAllLaunchConfigurations(); |
| if (!allConfigs.contains(config)) { |
| allConfigs.add(config); |
| added = true; |
| } |
| } |
| if (added) { |
| getConfigurationNotifier().notify(config, ADDED); |
| clearConfigNameCache(); |
| } |
| } else { |
| launchConfigurationDeleted(config); |
| } |
| } |
| |
| /** |
| * Notifies the launch manager that a launch configuration |
| * has been changed. The configuration is removed from the |
| * cache of info objects such that the new attributes will |
| * be updated on the next access. Listeners are notified of |
| * the change. |
| * |
| * @param config the launch configuration that was changed |
| */ |
| protected void launchConfigurationChanged(ILaunchConfiguration config) { |
| synchronized(this) { |
| fLaunchConfigurations.remove(config); |
| } |
| clearConfigNameCache(); |
| if (isValid(config)) { |
| // in case the config has been refreshed and it was removed from the |
| // index due to 'out of synch with local file system' (see bug 36147), |
| // add it back (will only add if required) |
| launchConfigurationAdded(config); |
| getConfigurationNotifier().notify(config, CHANGED); |
| } else { |
| launchConfigurationDeleted(config); |
| } |
| } |
| |
| /** |
| * Notifies the launch manager that a launch configuration |
| * has been deleted. The configuration is removed from the |
| * cache of info and from the index of configurations by |
| * project, and listeners are notified. |
| * |
| * @param config the launch configuration that was deleted |
| */ |
| protected void launchConfigurationDeleted(ILaunchConfiguration config) { |
| boolean removed = false; |
| synchronized (this) { |
| Object key = fLaunchConfigurations.remove(config); |
| removed = key != null; |
| getAllLaunchConfigurations().remove(config); |
| } |
| if (removed) { |
| getConfigurationNotifier().notify(config, REMOVED); |
| clearConfigNameCache(); |
| } |
| } |
| |
| /** |
| * @see ILaunchManager#newSourceLocator(String) |
| */ |
| @Override |
| public IPersistableSourceLocator newSourceLocator(String identifier) throws CoreException { |
| initializeSourceLocators(); |
| IConfigurationElement config = fSourceLocators.get(identifier); |
| if (config == null) { |
| throw new CoreException(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugException.INTERNAL_ERROR, |
| MessageFormat.format(DebugCoreMessages.LaunchManager_Source_locator_does_not_exist___0__13, new Object[] { identifier }), null)); |
| } |
| IPersistableSourceLocator sourceLocator = (IPersistableSourceLocator)config.createExecutableExtension("class"); //$NON-NLS-1$ |
| if (sourceLocator instanceof AbstractSourceLookupDirector) { |
| ((AbstractSourceLookupDirector)sourceLocator).setId(identifier); |
| } |
| return sourceLocator; |
| } |
| |
| /** |
| * The specified project has just closed - remove its |
| * launch configurations from the cached index. |
| * |
| * @param project the project that has been closed |
| */ |
| protected void projectClosed(IProject project) { |
| for (ILaunchConfiguration config : getLaunchConfigurations(project)) { |
| launchConfigurationDeleted(config); |
| } |
| //bug 12134 |
| terminateMappedConfigurations(project); |
| } |
| |
| /** |
| * The specified project has just opened - add all launch |
| * configs in the project to the index of all configs. |
| * |
| * @param project the project that has been opened |
| */ |
| protected void projectOpened(IProject project) { |
| for (ILaunchConfiguration config : findLaunchConfigurations(project)) { |
| launchConfigurationAdded(config); |
| } |
| } |
| |
| /** |
| * @see ILaunchManager#removeLaunch(ILaunch) |
| */ |
| @Override |
| public void removeLaunch(final ILaunch launch) { |
| if (internalRemoveLaunch(launch)) { |
| fireUpdate(launch, REMOVED); |
| fireUpdate(new ILaunch[] {launch}, REMOVED); |
| } |
| } |
| |
| /** |
| * @see ILaunchManager#removeLaunchConfigurationListener(ILaunchConfigurationListener) |
| */ |
| @Override |
| public void removeLaunchConfigurationListener(ILaunchConfigurationListener listener) { |
| fLaunchConfigurationListeners.remove(listener); |
| } |
| |
| /** |
| * @see org.eclipse.debug.core.ILaunchManager#removeLaunches(org.eclipse.debug.core.ILaunch[]) |
| */ |
| @Override |
| public void removeLaunches(ILaunch[] launches) { |
| List<ILaunch> removed = new ArrayList<ILaunch>(launches.length); |
| for (int i = 0; i < launches.length; i++) { |
| if (internalRemoveLaunch(launches[i])) { |
| removed.add(launches[i]); |
| } |
| } |
| if (!removed.isEmpty()) { |
| ILaunch[] removedLaunches = removed.toArray(new ILaunch[removed.size()]); |
| fireUpdate(removedLaunches, REMOVED); |
| for (int i = 0; i < removedLaunches.length; i++) { |
| fireUpdate(removedLaunches[i], REMOVED); |
| } |
| } |
| } |
| /** |
| * @see org.eclipse.debug.core.ILaunchManager#removeLaunchListener(org.eclipse.debug.core.ILaunchesListener) |
| */ |
| @Override |
| public void removeLaunchListener(ILaunchesListener listener) { |
| fLaunchesListeners.remove(listener); |
| } |
| |
| /** |
| * @see ILaunchManager#removeLaunchListener(ILaunchListener) |
| */ |
| @Override |
| public void removeLaunchListener(ILaunchListener listener) { |
| fListeners.remove(listener); |
| } |
| |
| /** |
| * Traverses the delta looking for added/removed/changed launch |
| * configuration files. |
| * |
| * @see IResourceChangeListener#resourceChanged(IResourceChangeEvent) |
| */ |
| @Override |
| public void resourceChanged(IResourceChangeEvent event) { |
| IResourceDelta delta = event.getDelta(); |
| if (delta != null) { |
| LaunchManagerVisitor visitor = getDeltaVisitor(); |
| MappedResourceVisitor v = null; |
| if (isDeleteConfigurations()) { |
| v = getMappedResourceVisitor(); |
| } |
| try { |
| delta.accept(visitor); |
| if (v != null) { |
| delta.accept(v); |
| } |
| } catch (CoreException e) { |
| DebugPlugin.log(e.getStatus()); |
| } |
| } |
| } |
| |
| /** |
| * Gets the launch configuration associated with the specified <code>IResource</code>. |
| * This method relies on the resource mapping existing, if no such mapping |
| * exists the launch configuration is ignored. |
| * |
| * @param resource the resource to collect launch configurations for |
| * @return the list of associated launch configurations |
| */ |
| private ArrayList<ILaunchConfiguration> collectAssociatedLaunches(IResource resource) { |
| ArrayList<ILaunchConfiguration> list = new ArrayList<ILaunchConfiguration>(); |
| try { |
| ILaunchConfiguration[] configs = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(); |
| IResource[] resources = null; |
| for(int i = 0; i < configs.length; i++) { |
| if(configs[i].isLocal()) { |
| resources = configs[i].getMappedResources(); |
| if(resources != null) { |
| for(int j = 0; j < resources.length; j++){ |
| if(resource.equals(resources[j]) || |
| resource.getFullPath().isPrefixOf(resources[j].getFullPath())) { |
| list.add(configs[i]); |
| break; |
| } |
| } |
| } |
| } |
| } |
| } catch (CoreException e) { |
| DebugPlugin.log(e); |
| } |
| return list; |
| } |
| |
| /** |
| * Indicates the given launch configuration is being moved from the given |
| * location to the new location. |
| * |
| * @param from the location a launch configuration is being moved from, or |
| * <code>null</code> |
| * @param to the location a launch configuration is being moved to, |
| * or <code>null</code> |
| */ |
| protected void setMovedFromTo(ILaunchConfiguration from, ILaunchConfiguration to) { |
| fFrom = from; |
| fTo = to; |
| } |
| /** |
| * Terminates/Disconnects any active debug targets/processes. |
| * Clears launch configuration types. |
| */ |
| public void shutdown() { |
| fListeners = new ListenerList(); |
| fLaunchesListeners = new ListenerList(); |
| fLaunchConfigurationListeners = new ListenerList(); |
| ILaunch[] launches = getLaunches(); |
| ILaunch launch = null; |
| for (int i= 0; i < launches.length; i++) { |
| launch = launches[i]; |
| if(launch != null) { |
| try { |
| if (launch instanceof IDisconnect) { |
| IDisconnect disconnect = (IDisconnect)launch; |
| if (disconnect.canDisconnect()) { |
| disconnect.disconnect(); |
| } |
| } |
| if (launch.canTerminate()) { |
| launch.terminate(); |
| } |
| } catch (DebugException e) { |
| DebugPlugin.log(e); |
| } |
| } |
| } |
| |
| persistPreferredLaunchDelegates(); |
| clearAllLaunchConfigurations(); |
| fStepFilterManager = null; |
| ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); |
| } |
| |
| /** |
| * Saves the listings of preferred launch delegates from all of the launch configuration types |
| * |
| * @since 3.3 |
| */ |
| public void persistPreferredLaunchDelegates() { |
| ILaunchConfigurationType[] types = getLaunchConfigurationTypes(); |
| for(int i = 0; i < types.length; i++) { |
| persistPreferredLaunchDelegate((LaunchConfigurationType)types[i]); |
| } |
| } |
| |
| /** |
| * Persists the given launch configuration delegate. |
| * @param type Launch configuration type to persist |
| * |
| * @since 3.6 |
| */ |
| public void persistPreferredLaunchDelegate(LaunchConfigurationType type) { |
| String preferenceName = PREF_PREFERRED_DELEGATES + '/' + type.getIdentifier(); |
| Map<Set<String>, ILaunchDelegate> preferred = type.getPreferredDelegates(); |
| if(preferred != null && preferred.size() > 0) { |
| StringBuffer str = new StringBuffer(); |
| for (Entry<Set<String>, ILaunchDelegate> entry : preferred.entrySet()) { |
| Set<String> modes = entry.getKey(); |
| ILaunchDelegate delegate = entry.getValue(); |
| if (delegate != null) { |
| str.append(delegate.getId()); |
| str.append(','); |
| for (String mode : modes) { |
| str.append(mode).append(','); |
| } |
| str.append(';'); |
| } |
| } |
| Preferences.setString(DebugPlugin.getUniqueIdentifier(), preferenceName, str.toString(), null); |
| } else { |
| Preferences.setToDefault(DebugPlugin.getUniqueIdentifier(), preferenceName); |
| } |
| |
| // Reset the legacy preference string. |
| Preferences.setToDefault(DebugPlugin.getUniqueIdentifier(), PREF_PREFERRED_DELEGATES); |
| } |
| |
| /** |
| * finds and terminates any running launch configurations associated with the given resource |
| * @param resource the resource to search for launch configurations and hence launches for |
| * @since 3.2 |
| */ |
| protected void terminateMappedConfigurations(IResource resource) { |
| ILaunch[] launches = getLaunches(); |
| ILaunchConfiguration[] configs = getMappedConfigurations(resource); |
| try { |
| for(int i = 0; i < launches.length; i++) { |
| for(int j = 0; j < configs.length; j++) { |
| if(configs[j].equals(launches[i].getLaunchConfiguration()) & launches[i].canTerminate()) { |
| launches[i].terminate(); |
| } |
| } |
| } |
| } |
| catch(CoreException e) {DebugPlugin.log(e);} |
| } |
| |
| /** |
| * Throws a debug exception with the given throwable that occurred |
| * while processing the given configuration. |
| * @param config the {@link ILaunchConfiguration} causing the exception |
| * @param e the {@link Exception} to throw |
| * @throws DebugException the new {@link DebugException} wrapping the given {@link Exception} and {@link ILaunchConfiguration} |
| * @since 3.5 |
| */ |
| private void throwException(LaunchConfiguration config, Throwable e) throws DebugException { |
| String uri = config.getName(); |
| try { |
| IFileStore store = config.getFileStore(); |
| if (store != null) { |
| uri = store.toString(); |
| } |
| } catch (CoreException ce) { |
| } |
| throw createDebugException(MessageFormat.format(DebugCoreMessages.LaunchManager__0__occurred_while_reading_launch_configuration_file__1___1, new Object[] { |
| e.toString(), uri }), e); |
| } |
| |
| /** |
| * Verify basic integrity of launch configurations in the given list, |
| * adding valid configurations to the collection of all launch configurations. |
| * Exceptions are logged for invalid configurations. |
| * |
| * @param verify the list of configurations to verify |
| * @param valid the list to place valid configurations in |
| */ |
| protected void verifyConfigurations(List<ILaunchConfiguration> verify, List<ILaunchConfiguration> valid) { |
| for (ILaunchConfiguration config : verify) { |
| if (!valid.contains(config) && isValid(config)) { |
| valid.add(config); |
| } |
| } |
| } |
| |
| /** |
| * Returns the name of the given launch mode with accelerators removed, |
| * or <code>null</code> if none. |
| * |
| * @param id launch mode identifier |
| * @return launch mode name with accelerators removed or <code>null</code> |
| */ |
| public String getLaunchModeName(String id) { |
| ILaunchMode launchMode = getLaunchMode(id); |
| if (launchMode != null) { |
| return removeAccelerators(launchMode.getLabel()); |
| } |
| return null; |
| } |
| /** |
| * Returns the label with any accelerators removed. |
| * |
| * @param label label to process |
| * @return label without accelerators |
| */ |
| public static String removeAccelerators(String label) { |
| String title = label; |
| if (title != null) { |
| // strip out any '&' (accelerators) |
| int index = title.indexOf('&'); |
| if (index == 0) { |
| title = title.substring(1); |
| } else if (index > 0) { |
| //DBCS languages use "(&X)" format |
| if (title.charAt(index - 1) == '(' && title.length() >= index + 3 && title.charAt(index + 2) == ')') { |
| String first = title.substring(0, index - 1); |
| String last = title.substring(index + 3); |
| title = first + last; |
| } else if (index < (title.length() - 1)) { |
| String first = title.substring(0, index); |
| String last = title.substring(index + 1); |
| title = first + last; |
| } |
| } |
| } |
| return title; |
| } |
| |
| /** |
| * Returns the singleton step filter manager. |
| * |
| * @return the step filter manager |
| */ |
| public synchronized StepFilterManager getStepFilterManager() { |
| if (fStepFilterManager == null) { |
| fStepFilterManager = new StepFilterManager(); |
| } |
| return fStepFilterManager; |
| } |
| |
| /** |
| * Imports launch configurations represented by the given local files, overwriting |
| * any existing configurations. Sends launch configuration change notification |
| * as required (i.e. added or changed). |
| * <p> |
| * If a file is imported that has the same name as a configuration in the workspace |
| * (i.e. a shared configuration), the shared configuration is deleted (becomes local). |
| * </p> |
| * @param files files to import |
| * @param monitor progress monitor or <code>null</code> |
| * @throws CoreException if an exception occurs while importing configurations |
| * @since 3.4.0 |
| */ |
| public void importConfigurations(File[] files, IProgressMonitor monitor) throws CoreException { |
| Map<String, ILaunchConfiguration> sharedConfigs = new HashMap<String, ILaunchConfiguration>(); |
| for (ILaunchConfiguration config : getAllLaunchConfigurations()) { |
| if (!config.isLocal()) { |
| StringBuffer buf = new StringBuffer(config.getName()); |
| buf.append('.'); |
| buf.append(ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION); |
| sharedConfigs.put(buf.toString(), config); |
| } |
| } |
| List<Status> stati = null; |
| SubMonitor lmonitor = SubMonitor.convert(monitor, DebugCoreMessages.LaunchManager_29, files.length); |
| for (int i = 0; i < files.length; i++) { |
| if (lmonitor.isCanceled()) { |
| break; |
| } |
| File source = files[i]; |
| lmonitor.subTask(MessageFormat.format(DebugCoreMessages.LaunchManager_28, new Object[] { source.getName() })); |
| IPath location = new Path(LOCAL_LAUNCH_CONFIGURATION_CONTAINER_PATH.toOSString()).append(source.getName()); |
| File target = location.toFile(); |
| IPath locationdir = location.removeLastSegments(1); |
| if(!locationdir.toFile().exists()) { |
| locationdir.toFile().mkdirs(); |
| } |
| boolean added = !target.exists(); |
| try { |
| copyFile(source, target); |
| ILaunchConfiguration configuration = new LaunchConfiguration(LaunchConfiguration.getSimpleName(source.getName()), null); |
| ILaunchConfiguration shared = sharedConfigs.get(target.getName()); |
| if (shared != null) { |
| setMovedFromTo(shared, configuration); |
| shared.delete(); |
| launchConfigurationChanged(configuration); |
| } else if (added) { |
| launchConfigurationAdded(configuration); |
| } else { |
| launchConfigurationChanged(configuration); |
| } |
| } catch (IOException e) { |
| if (stati == null) { |
| stati = new ArrayList<Status>(); |
| } |
| stati.add(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.ERROR, |
| MessageFormat.format(DebugCoreMessages.LaunchManager_27, new Object[] { source.getPath() }), e)); |
| } |
| lmonitor.worked(1); |
| } |
| if (!lmonitor.isCanceled()) { |
| lmonitor.done(); |
| } |
| if (stati != null) { |
| if (stati.size() > 1) { |
| MultiStatus multi = new MultiStatus(DebugPlugin.getUniqueIdentifier(), DebugPlugin.ERROR, DebugCoreMessages.LaunchManager_26, null); |
| for (Status status : stati) { |
| multi.add(status); |
| } |
| throw new CoreException(multi); |
| } else { |
| throw new CoreException(stati.get(0)); |
| } |
| } |
| } |
| |
| /** |
| * Copies a file from one location to another, replacing any existing file. |
| * |
| * @param in the file to copy |
| * @param out the file to be copied out to |
| * @throws IOException if the file read fails |
| * @since 3.4.0 |
| */ |
| private void copyFile(File in, File out) throws IOException { |
| try (FileInputStream fis = new FileInputStream(in); FileOutputStream fos = new FileOutputStream(out)) { |
| byte[] buf = new byte[1024]; |
| int i = 0; |
| while ((i = fis.read(buf)) != -1) { |
| fos.write(buf, 0, i); |
| } |
| } |
| } |
| |
| /** |
| * Returns whether any launch config supports the given mode. |
| * |
| * @param mode launch mode |
| * @return whether any launch config supports the given mode |
| */ |
| public synchronized boolean launchModeAvailable(String mode) { |
| if (fActiveModes == null) { |
| ILaunchConfigurationType[] types = getLaunchConfigurationTypes(); |
| ILaunchMode[] modes = getLaunchModes(); |
| fActiveModes = new HashSet<String>(3); |
| for (int i = 0; i < types.length; i++) { |
| for (int j = 0; j < modes.length; j++) { |
| if (types[i].supportsMode(modes[j].getIdentifier())) { |
| fActiveModes.add(modes[j].getIdentifier()); |
| } |
| } |
| } |
| } |
| return fActiveModes.contains(mode); |
| } |
| |
| /** |
| * @see org.eclipse.debug.core.ILaunchManager#generateLaunchConfigurationName(java.lang.String) |
| */ |
| @Override |
| public String generateLaunchConfigurationName(String namePrefix) { |
| String name = generateUniqueLaunchConfigurationNameFrom(namePrefix); |
| try { |
| isValidLaunchConfigurationName(name); |
| return name; |
| } |
| catch(IllegalArgumentException iae) { |
| //blanket change all reserved names |
| if(Platform.OS_WIN32.equals(Platform.getOS())) { |
| for(int i = 0; i < UNSUPPORTED_WIN32_CONFIG_NAMES.length; i++) { |
| if(UNSUPPORTED_WIN32_CONFIG_NAMES[i].equals(name)) { |
| name = "launch_configuration"; //$NON-NLS-1$ |
| } |
| } |
| } |
| //blanket replace all invalid chars |
| for (int i = 0; i < DISALLOWED_CONFIG_NAME_CHARS.length; i++) { |
| name = name.replace(DISALLOWED_CONFIG_NAME_CHARS[i], '_'); |
| } |
| } |
| //run it through the generator once more in case a replaced name has already been done |
| return generateUniqueLaunchConfigurationNameFrom(name); |
| } |
| |
| /** |
| * @see org.eclipse.debug.core.ILaunchManager#isValidLaunchConfigurationName(java.lang.String) |
| */ |
| @Override |
| public boolean isValidLaunchConfigurationName(String configname) throws IllegalArgumentException { |
| if(Platform.OS_WIN32.equals(Platform.getOS())) { |
| for(int i = 0; i < UNSUPPORTED_WIN32_CONFIG_NAMES.length; i++) { |
| if(configname.equals(UNSUPPORTED_WIN32_CONFIG_NAMES[i])) { |
| throw new IllegalArgumentException(MessageFormat.format(DebugCoreMessages.LaunchManager_invalid_config_name, new Object[] { configname })); |
| } |
| } |
| } |
| for (int i = 0; i < DISALLOWED_CONFIG_NAME_CHARS.length; i++) { |
| if (configname.indexOf(DISALLOWED_CONFIG_NAME_CHARS[i]) > -1) { |
| throw new IllegalArgumentException(MessageFormat.format(DebugCoreMessages.LaunchManager_invalid_config_name_char, new Object[] { String.valueOf(DISALLOWED_CONFIG_NAME_CHARS[i]) })); |
| } |
| } |
| return true; |
| } |
| |
| } |