diff options
author | Axel Richard | 2017-03-10 15:30:18 +0000 |
---|---|---|
committer | Sarika Sinha | 2017-12-11 05:47:08 +0000 |
commit | ca4c3de585c743486c2df55b551ec3f2dfd9b6a2 (patch) | |
tree | e408d2fd23d7014b1db5116fce46d5ce6e4f0bfb /org.eclipse.debug.core/core/org/eclipse/debug | |
parent | 8803c89e9471914c5a66f0f869cd4fea67357576 (diff) | |
download | eclipse.platform.debug-ca4c3de585c743486c2df55b551ec3f2dfd9b6a2.tar.gz eclipse.platform.debug-ca4c3de585c743486c2df55b551ec3f2dfd9b6a2.tar.xz eclipse.platform.debug-ca4c3de585c743486c2df55b551ec3f2dfd9b6a2.zip |
Bug 41353 - Launch configuration prototypesI20171211-2000
First implementation of the launch configuration prototypes mechanism.
Change-Id: I21a2a97b83aa9cb1be79153bbc4b72171cc6be20
Signed-off-by: Axel Richard <axel.richard@obeo.fr>
Diffstat (limited to 'org.eclipse.debug.core/core/org/eclipse/debug')
14 files changed, 1053 insertions, 73 deletions
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfiguration.java b/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfiguration.java index 020ca26cf..0ab64fb71 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfiguration.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfiguration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. + * Copyright (c) 2000, 2017 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 @@ -7,10 +7,12 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes *******************************************************************************/ package org.eclipse.debug.core; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -69,6 +71,14 @@ public interface ILaunchConfiguration extends IAdaptable { public static final String LAUNCH_CONFIGURATION_FILE_EXTENSION = "launch"; //$NON-NLS-1$ /** + * The file extension for launch configuration prototype files (value + * <code>"prototype"</code>). + * + * @since 3.12 + */ + public static final String LAUNCH_CONFIGURATION_PROTOTYPE_FILE_EXTENSION = "prototype"; //$NON-NLS-1$ + + /** * Launch configuration attribute storing an identifier of * a persistable source locator extension. When this attribute is * specified, a new source locator will be created automatically and @@ -91,6 +101,38 @@ public interface ILaunchConfiguration extends IAdaptable { public static final String ATTR_SOURCE_LOCATOR_MEMENTO = DebugPlugin.getUniqueIdentifier() + ".source_locator_memento"; //$NON-NLS-1$ /** + * Flag indicating that only this configuration is to be modified by an operation. + * Any prototype children referring to this configuration will not be modified. + * + * @since 3.12 + */ + public static final int UPDATE_NONE = 0; + + /** + * Flag indicating that this prototype and any effected prototype children of this prototype + * should be updated when this prototype is modified. + * + * @since 3.12 + */ + public static final int UPDATE_PROTOTYPE_CHILDREN = 1; + + /** + * Type constant (bit mask value 1) which identifies a launch configuration. + * + * @see #getKind() + * @since 3.12 + */ + public static final int CONFIGURATION = 0x1; + + /** + * Type constant (bit mask value 2) which identifies a launch configuration prototype. + * + * @see #getKind() + * @since 3.12 + */ + public static final int PROTOTYPE = 0x2; + + /** * Returns whether the contents of this launch configuration are * equal to the contents of the given launch configuration. * @@ -122,18 +164,39 @@ public interface ILaunchConfiguration extends IAdaptable { /** * Deletes this launch configuration. This configuration's underlying - * storage is deleted. Has no effect if this configuration - * does not exist. + * storage is deleted. Has no effect if this configuration does not exist. + * <p> + * Equivalent to #delete(UPDATE_NONE) + * </p> * * @exception CoreException if this method fails. Reasons include: - * <ul> - * <li>An exception occurs while deleting this configuration's - * underlying storage.</li> - * </ul> + * <ul> + * <li>An exception occurs while deleting this + * configuration's underlying storage.</li> + * </ul> */ public void delete() throws CoreException; /** + * Deletes this launch configuration. This configuration's underlying + * storage is deleted. Has no effect if this configuration does not exist. + * <p> + * When UPDATE_PROTOTYPE_CHILDREN is specified, back pointers to this + * prototype are cleared in any prototype children. + * </p> + * + * @param flag one of UPDATE_NONE or UPDATE_PROTOTYPE_CHILDREN + * @exception CoreException if this method fails. Reasons include: + * <ul> + * <li>An exception occurs while deleting this + * configuration's underlying storage or updating any + * prototype children.</li> + * </ul> + * @since 3.12 + */ + public void delete(int flag) throws CoreException; + + /** * Returns whether this launch configuration's underlying * storage exists. This is a handle-only method. * @@ -597,4 +660,79 @@ public interface ILaunchConfiguration extends IAdaptable { * @since 3.3 */ public boolean isReadOnly(); + + /** + * Returns the prototype this launch configuration was created from or + * <code>null</code> if none. + * + * @return the prototype this launch configuration was created from or + * <code>null</code> if none + * @throws CoreException if the prototype could not be retrieved or no + * longer exists + * @since 3.12 + */ + public ILaunchConfiguration getPrototype() throws CoreException; + + /** + * Check if the given attribute has the same value than the one from its prototype. + * @param attribute the attribute to check + * @return <code>true</code> if the attribute is modified, <code>false</code> otherwise. + * @throws CoreException if an exception occurs while checking + * @since 3.12 + */ + public boolean isAttributeModified(String attribute) throws CoreException; + + /** + * Returns whether this configuration is a prototype. + * + * @return whether this configuration is a prototype + * @since 3.12 + */ + public boolean isPrototype(); + + /** + * Returns all configurations made from this prototype, possibly an empty + * collection. + * + * @return all configurations made from this prototype + * @throws CoreException if unable to retrieve this prototype's children + * @since 3.12 + */ + public Collection<ILaunchConfiguration> getPrototypeChildren() throws CoreException; + + /** + * Returns this configuration's kind. One of CONFIGURATION or PROTOTYPE. + * + * @see #CONFIGURATION + * @see #PROTOTYPE + * + * @return this configuration's kind + * @throws CoreException if unable to retrieve this configuration's kind + * @since 3.12 + */ + public int getKind() throws CoreException; + + /** + * Get the visible attributes of this prototype (return <code>null</code> if + * the launch configuration is not a prototype). + * + * @return the visible attributes of this prototype (return + * <code>null</code> if the launch configuration is not a + * prototype). + * @throws CoreException if unable to retrieve this prototype's visible + * attribute set. + * @since 3.12 + */ + public Set<String> getPrototypeVisibleAttributes() throws CoreException; + + /** + * Set the visibility of the given prototype's attribute. + * + * @param attribute the attribute to set + * @param visible the visibility + * @throws CoreException if unable to set this prototype's attribute + * visibility + * @since 3.12 + */ + public void setPrototypeAttributeVisibility(String attribute, boolean visible) throws CoreException; } diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfigurationType.java b/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfigurationType.java index cd78a8ca4..fbcb08a1e 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfigurationType.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfigurationType.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. + * Copyright (c) 2000, 2017 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes *******************************************************************************/ package org.eclipse.debug.core; @@ -315,4 +316,45 @@ public interface ILaunchConfigurationType extends IAdaptable { */ public String getContributorName(); + /** + * Returns all launch configuration prototypes of the this type, possibly + * an empty collection. + * + * @return all launch configuration prototypes of the this type + * @throws CoreException if unable to retrieve the prototypes + * @since 3.12 + */ + public ILaunchConfiguration[] getPrototypes() throws CoreException; + + /** + * Returns a new launch configuration working copy of this type, that + * resides in the specified container, with the given name. When + * <code>container</code> is </code>null</code>, the configuration will + * reside locally in the metadata area. Note: a launch configuration is not + * actually created until the working copy is saved. + * <p> + * The configuration <code>name</code> parameter cannot contain file + * separator characters (sub directories) when the <code>container</code> is + * <code>null</code> (i.e. when the configuration is to be stored in the + * local metadata area. + * </p> + * + * @param container the container in which the new configuration will + * reside, or <code>null</code> if the configuration should + * reside locally with the metadata. + * @param name name for the launch configuration + * @return a new launch configuration working copy instance of this type + * @exception CoreException if an instance of this type of launch + * configuration could not be created for any reason + * @since 3.12 + */ + public ILaunchConfigurationWorkingCopy newPrototypeInstance(IContainer container, String name) throws CoreException; + + /** + * Returns whether this type of launch configuration supports prototypes. + * + * @return whether this kind of launch configuration supports the prototypes + * @since 3.12 + */ + public boolean supportsPrototypes(); } diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfigurationWorkingCopy.java b/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfigurationWorkingCopy.java index b46e3747b..7b2b5326f 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfigurationWorkingCopy.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchConfigurationWorkingCopy.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. + * Copyright (c) 2000, 2017 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes *******************************************************************************/ package org.eclipse.debug.core; @@ -64,13 +65,41 @@ public interface ILaunchConfigurationWorkingCopy extends ILaunchConfiguration, I * saved to the parent working copy and the parent working copy is returned without * effecting the original launch configuration. * </p> + * <p> + * Equivalent to #doSave(UPDATE_NONE). + * </p> * @return handle to saved launch configuration * @exception CoreException if an exception occurs while * writing this configuration to its underlying file. + * @see #doSave(int) */ public ILaunchConfiguration doSave() throws CoreException; /** + * Saves this working copy to its underlying file and returns a handle to + * the resulting launch configuration. Has no effect if this configuration + * does not need saving. Creates the underlying file if not yet created. + * <p> + * Since 3.3, if this is a nested working copy, the contents of this working + * copy are saved to the parent working copy and the parent working copy is + * returned without effecting the original launch configuration. + * </p> + * <p> + * Updates any affected prototype children based on the given flag. When a + * working copy is renamed or moved to a new location, prototype children's + * back pointers will be updated to refer the proper configuration. + * </p> + * @param flag one of {@link ILaunchConfiguration#UPDATE_NONE} or + * {@link ILaunchConfiguration#UPDATE_PROTOTYPE_CHILDREN} + * @return handle to saved launch configuration + * @exception CoreException if an exception occurs while writing this + * configuration or any of its affected prototype children to + * underlying storage + * @since 3.12 + */ + public ILaunchConfiguration doSave(int flag) throws CoreException; + + /** * Sets the integer-valued attribute with the given name. * * @param attributeName the name of the attribute, cannot be <code>null</code> @@ -131,6 +160,15 @@ public interface ILaunchConfigurationWorkingCopy extends ILaunchConfiguration, I public void setAttribute(String attributeName, boolean value); /** + * Sets the valued attribute with the given name. + * + * @param attributeName the name of the attribute, cannot be <code>null</code> + * @param value the value + * @since 3.12 + */ + public void setAttribute(String attributeName, Object value); + + /** * Returns the original launch configuration this working copy * was created from or <code>null</code> if this is a new * working copy created from a launch configuration type. @@ -277,4 +315,35 @@ public interface ILaunchConfigurationWorkingCopy extends ILaunchConfiguration, I * @since 3.3 */ public ILaunchConfigurationWorkingCopy getParent(); + + /** + * Copies all attributes from the given prototype to this working. + * Overwrites any existing attributes with the same key. + * + * @param prototype configuration prototype + * @exception CoreException if unable to retrieve attributes from the prototype + * @since 3.12 + */ + public void copyAttributes(ILaunchConfiguration prototype) throws CoreException; + + /** + * Sets the prototype that this configuration is based on, possibly <code>null</code>, + * and optionally copies attributes from the prototype to this working copy. + * <p> + * When the specified prototype is <code>null</code>, this working copy is no longer + * associated with any prototype. + * </p> + * @param prototype prototype or <code>null</code> + * @param copy whether to copy attributes from the prototype to this working copy. Has + * no effect when prototype is <code>null</code> + * @exception CoreException if + * <ul> + * <li>unable to generate a memento for the given configuration + * or copy its attributes</li> + * <li>if attempting to set a prototype attribute on an existing prototype - prototypes + * cannot be nested</li> + * </ul> + * @since 3.12 + */ + public void setPrototype(ILaunchConfiguration prototype, boolean copy) throws CoreException; } diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchManager.java b/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchManager.java index 534abe840..41ac5e15f 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchManager.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/core/ILaunchManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. + * Copyright (c) 2000, 2017 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes *******************************************************************************/ package org.eclipse.debug.core; @@ -208,7 +209,10 @@ public interface ILaunchManager { * in the specified file. This method does not check if the specified <code>IFile</code> is * a launch configuration file or that it exists in the local or * remote file system. - * + * <p> + * Since 3.12, the returned configuration may be a launch configuration template. + * </p> + * * @param file launch configuration file * @return a handle to the launch configuration contained * in the specified file @@ -218,7 +222,10 @@ public interface ILaunchManager { /** * Returns a handle to the launch configuration specified by * the given memento. The configuration may not exist. - * + * <p> + * Since 3.12, the returned configuration may be a launch configuration template. + * </p> + * * @param memento launch configuration memento * @return a handle to the launch configuration specified by * the given memento @@ -234,20 +241,56 @@ public interface ILaunchManager { * @return all launch configurations defined in the workspace * @exception CoreException if an exception occurs retrieving configurations * @since 2.0 + * @see ILaunchConfigurationType#getPrototypes() */ public ILaunchConfiguration[] getLaunchConfigurations() throws CoreException; /** * Returns all launch configurations of the specified type defined in the workspace - * + * <p> + * Does not include launch configuration templates. + * </p> * @param type a launch configuration type * @return all launch configurations of the specified type defined in the workspace * @exception CoreException if an error occurs while retrieving * a launch configuration * @since 2.0 + * @see ILaunchConfigurationType#getPrototypes() */ public ILaunchConfiguration[] getLaunchConfigurations(ILaunchConfigurationType type) throws CoreException; /** + * Returns all launch configurations defined in the workspace of the specified + * kind(s) (configurations and/or prototypes). + * + * @param kinds bit mask of kinds of configurations to consider + * @return all launch configurations defined in the workspace + * @exception CoreException if an exception occurs retrieving configurations + * @since 3.12 + * @see ILaunchConfiguration#CONFIGURATION + * @see ILaunchConfiguration#PROTOTYPE + * @see ILaunchConfiguration#getKind() + * @see ILaunchConfigurationType#getPrototypes() + */ + public ILaunchConfiguration[] getLaunchConfigurations(int kinds) throws CoreException; + + /** + * Returns all launch configurations of the specified type defined in the workspace + * of the specified kind(s) (configurations and/or prototypes). + * + * @param type a launch configuration type + * @param kinds bit mask of kinds of configurations to consider + * @return all launch configurations of the specified type defined in the workspace + * @exception CoreException if an error occurs while retrieving + * a launch configuration + * @since 3.12 + * @see ILaunchConfiguration#CONFIGURATION + * @see ILaunchConfiguration#PROTOTYPE + * @see ILaunchConfiguration#getKind() + * @see ILaunchConfigurationType#getPrototypes() + */ + public ILaunchConfiguration[] getLaunchConfigurations(ILaunchConfigurationType type, int kinds) throws CoreException; + + /** * Returns the launch configuration type extension with the specified * id, or <code>null</code> if it does not exist. * diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/core/IPrototypeAttributesLabelProvider.java b/org.eclipse.debug.core/core/org/eclipse/debug/core/IPrototypeAttributesLabelProvider.java new file mode 100644 index 000000000..ab98d0369 --- /dev/null +++ b/org.eclipse.debug.core/core/org/eclipse/debug/core/IPrototypeAttributesLabelProvider.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2017 Obeo. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.core; + +/** + * A prototype attributes label provider is contributed as an optional attribute + * of a <code>launchConfigurationType</code> extension and is responsible for + * displaying launch configurations prototype attributes of that type. + * + * @since 3.12 + */ +public interface IPrototypeAttributesLabelProvider { + + /** + * Get a human readable label to associate to this attribute. + * + * @param attribute the given attribute. + * @return a human readable label of this attribute. + */ + public String getAttributeLabel(String attribute); +} diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.java index c93185478..535a8d628 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.java @@ -8,6 +8,7 @@ * Contributors: * IBM - Initial API and implementation * Anton Kosyakov (Itemis AG) - Bug 438621 - [step filtering] Provide an extension point to enhance methods step filtering. + * Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes *******************************************************************************/ package org.eclipse.debug.internal.core; @@ -68,6 +69,9 @@ public class DebugCoreMessages extends NLS { public static String LaunchConfigurationWorkingCopy_1; public static String LaunchConfigurationWorkingCopy_2; public static String LaunchConfigurationWorkingCopy_3; + public static String LaunchConfigurationWorkingCopy_6; + public static String LaunchConfigurationWorkingCopy_7; + public static String LaunchConfigurationWorkingCopy_8; public static String LaunchDelegate_0; public static String LaunchDelegate_1; public static String LaunchDelegate_2; diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.properties b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.properties index 988bdef8a..446354429 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.properties +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.properties @@ -8,6 +8,7 @@ # Contributors: # IBM Corporation - initial API and implementation # Anton Kosyakov (Itemis AG) - Bug 438621 - [step filtering] Provide an extension point to enhance methods step filtering. +# Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes ############################################################################### Breakpoint_no_associated_marker=Breakpoint does not have an associated marker. @@ -79,6 +80,9 @@ LaunchConfigurationWorkingCopy_1=Writing local file LaunchConfigurationWorkingCopy_2=Creating new file {0}.launch in workspace LaunchConfigurationWorkingCopy_3=Setting contents of {0}.launch LaunchConfigurationWorkingCopy_4=Unable to obtain storage to write launch configuration +LaunchConfigurationWorkingCopy_6=The launch configuration must be a prototype +LaunchConfigurationWorkingCopy_7=Unable to set a launch configuration prototype on a launch configuration working copy +LaunchConfigurationWorkingCopy_8=Writing local file LaunchManager__0__occurred_while_reading_launch_configuration_file__1___1={0} occurred while reading launch configuration file: {1}. LaunchManager_Invalid_launch_configuration_index__18=Invalid launch configuration index. LaunchManager_does_not_exist=Launch configuration {0} at {1} does not exist. diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/IConfigurationElementConstants.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/IConfigurationElementConstants.java index 2e225285e..1948399de 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/IConfigurationElementConstants.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/IConfigurationElementConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2008 IBM Corporation and others. + * Copyright (c) 2006, 2017 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes *******************************************************************************/ package org.eclipse.debug.internal.core; @@ -341,4 +342,14 @@ public interface IConfigurationElementConstants { * <p>Equal to the word: <code>editorInput</code></p> */ public static final String EDITOR_INPUT = "editorInput"; //$NON-NLS-1$ + + /** + * The allowPrototypes node name for a configuration element + * <p> + * Equal to the word: <code>allowPrototypes</code> + * </p> + * + * @since 3.12 + */ + public static final String ALLOW_PROTOTYPES = "allowPrototypes"; //$NON-NLS-1$ } diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfiguration.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfiguration.java index e6a15dfc7..df33c3472 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfiguration.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfiguration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2017 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 @@ -8,6 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Sascha Radike - bug 56642 + * Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes *******************************************************************************/ package org.eclipse.debug.internal.core; @@ -17,6 +18,7 @@ import java.io.IOException; import java.io.StringReader; import java.net.URI; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -109,6 +111,22 @@ public class LaunchConfiguration extends PlatformObject implements ILaunchConfig public static final String ATTR_PREFERRED_LAUNCHERS = DebugPlugin.getUniqueIdentifier() + ".preferred_launchers"; //$NON-NLS-1$ /** + * Launch configuration attribute storing a memento identifying the prototype + * this configuration was made from, possibly <code>null</code>. + * + * @since 3.12 + */ + public static final String ATTR_PROTOTYPE = DebugPlugin.getUniqueIdentifier() + ".ATTR_PROTOTYPE"; //$NON-NLS-1$ + + /** + * Launch configuration attribute storing if this configuration is a + * prototype or not. + * + * @since 3.12 + */ + public static final String IS_PROTOTYPE = DebugPlugin.getUniqueIdentifier() + ".IS_PROTOTYPE"; //$NON-NLS-1$ + + /** * Status handler to prompt in the UI thread * * @since 3.3 @@ -142,6 +160,12 @@ public class LaunchConfiguration extends PlatformObject implements ILaunchConfig private IContainer fContainer; /** + * If this configuration is a prototype. + * @since 3.12 + */ + private boolean fIsPrototype; + + /** * Constructs a launch configuration with the given name. The configuration * is stored in the given container or locally with workspace metadata if * the specified container is <code>null</code>. @@ -151,9 +175,24 @@ public class LaunchConfiguration extends PlatformObject implements ILaunchConfig * @since 3.5 */ protected LaunchConfiguration(String name, IContainer container) { + this(name, container, false); + } + + /** + * Constructs a launch configuration with the given name. The configuration + * is stored in the given container or locally with workspace metadata if + * the specified container is <code>null</code>. + * + * @param name launch configuration name + * @param container parent container or <code>null</code> + * @param prototype if the configuration is a prototype or not + * @since 3.12 + */ + protected LaunchConfiguration(String name, IContainer container, boolean prototype) { initialize(); setName(name); setContainer(container); + fIsPrototype = prototype; } /** @@ -170,11 +209,11 @@ public class LaunchConfiguration extends PlatformObject implements ILaunchConfig * @since 3.5 */ protected LaunchConfiguration(IFile file) { - this(getSimpleName(file.getName()), file.getParent()); + this(getSimpleName(file.getName()), file.getParent(), isPrototype(file)); } /** - * Given a name that ends with .launch, return the simple name of the configuration. + * Given a name that ends with .launch or .prototype, return the simple name of the configuration. * * @param fileName the name to parse * @return simple name @@ -184,6 +223,8 @@ public class LaunchConfiguration extends PlatformObject implements ILaunchConfig IPath path = new Path(fileName); if(ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION.equals(path.getFileExtension())) { return path.removeFileExtension().toString(); + } else if (ILaunchConfiguration.LAUNCH_CONFIGURATION_PROTOTYPE_FILE_EXTENSION.equals(path.getFileExtension())) { + return path.removeFileExtension().toString(); } return fileName; } @@ -304,6 +345,23 @@ public class LaunchConfiguration extends PlatformObject implements ILaunchConfig } } + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfiguration#delete(int) + */ + @Override + public void delete(int flag) throws CoreException { + if (flag == UPDATE_PROTOTYPE_CHILDREN && isPrototype()) { + // clear back pointers to this configuration + Collection<ILaunchConfiguration> children = getPrototypeChildren(); + for (ILaunchConfiguration child : children) { + ILaunchConfigurationWorkingCopy childWC = child.getWorkingCopy(); + childWC.setPrototype(null, false); + childWC.doSave(); + } + } + delete(); + } + /** * Returns whether this configuration is equal to the * given configuration. Two configurations are equal if @@ -449,12 +507,16 @@ public class LaunchConfiguration extends PlatformObject implements ILaunchConfig * Returns the simple file name of this launch configuration. * * @return the simple file name of this launch configuration - for example - * "Abc.launch" + * "Abc.launch" or "Abc.prototype" */ protected String getFileName() { StringBuffer buf = new StringBuffer(getName()); buf.append('.'); - buf.append(ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION); + if (isPrototype()) { + buf.append(ILaunchConfiguration.LAUNCH_CONFIGURATION_PROTOTYPE_FILE_EXTENSION); + } else { + buf.append(ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION); + } return buf.toString(); } @@ -994,5 +1056,116 @@ public class LaunchConfiguration extends PlatformObject implements ILaunchConfig return getName(); } + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfiguration#getPrototype() + */ + @Override + public ILaunchConfiguration getPrototype() throws CoreException { + String memento = getAttribute(ATTR_PROTOTYPE, (String)null); + if (memento != null) { + LaunchConfiguration prototype = new LaunchConfiguration(memento); + prototype.setIsPrototype(true); + return prototype; + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfiguration#getPrototypeChildren() + */ + @Override + public Collection<ILaunchConfiguration> getPrototypeChildren() throws CoreException { + ILaunchConfiguration[] configurations = getLaunchManager().getLaunchConfigurations(getType()); + List<ILaunchConfiguration> proteges = new ArrayList<ILaunchConfiguration>(); + for (int i = 0; i < configurations.length; i++) { + ILaunchConfiguration config = configurations[i]; + if (this.equals(config.getPrototype())) { + proteges.add(config); + } + } + return proteges; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfiguration#isPrototype() + */ + @Override + public boolean isPrototype() { + return fIsPrototype; + } + + /** + * Set the prototype state of this configuration. + * + * @param isPrototype the prototype state. + * + * @since 3.12 + */ + protected void setIsPrototype(boolean isPrototype) { + fIsPrototype = isPrototype; + } + + /** + * Check if the given file is a launch configuration prototype or not. + * + * @param file the given {@link IFile}. + * @return <code>true</code> if the given file is a launch configuration + * prototype, false otherwise. + * + * @since 3.12 + */ + protected static boolean isPrototype(IFile file) { + if (ILaunchConfiguration.LAUNCH_CONFIGURATION_PROTOTYPE_FILE_EXTENSION.equals(file.getFileExtension())) { + return true; + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfiguration#getKind() + */ + @Override + public int getKind() throws CoreException { + if (fIsPrototype) { + return PROTOTYPE; + } + return CONFIGURATION; + } + + /* + * (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfiguration#isAttributeModified(java.lang.String) + */ + @Override + public boolean isAttributeModified(String attribute) throws CoreException { + ILaunchConfiguration prototype = getPrototype(); + if (prototype != null) { + Object prototypeValue = prototype.getAttributes().get(attribute); + Object attributeValue = getAttributes().get(attribute); + return !LaunchConfigurationInfo.compareAttribute(attribute, prototypeValue, attributeValue); + } + return false; + } + + /* + * (non-Javadoc) + * @see + * org.eclipse.debug.core.ILaunchConfiguration#getPrototypeVisibleAttributes + * () + */ + @Override + public Set<String> getPrototypeVisibleAttributes() throws CoreException { + return getInfo().getVisibleAttributes(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfiguration# + * setPrototypeAttributeVisibility(java.lang.String, boolean) + */ + @Override + public void setPrototypeAttributeVisibility(String attribute, boolean visible) throws CoreException { + getInfo().setAttributeVisibility(attribute, visible); + } } diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationInfo.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationInfo.java index 1692d6101..72aa2114d 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationInfo.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationInfo.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2015 IBM Corporation and others. + * Copyright (c) 2000, 2017 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 @@ -7,12 +7,14 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes *******************************************************************************/ package org.eclipse.debug.internal.core; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -22,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; +import java.util.stream.Collectors; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; @@ -31,6 +34,7 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -60,6 +64,8 @@ public class LaunchConfigurationInfo { private static final String INT_ATTRIBUTE = "intAttribute"; //$NON-NLS-1$ private static final String STRING_ATTRIBUTE = "stringAttribute"; //$NON-NLS-1$ private static final String TYPE = "type"; //$NON-NLS-1$ + private static final String PROTOTYPE = "prototype"; //$NON-NLS-1$ + private static final String VISIBLE_ATTRIBUTES = "visibleAttributes"; //$NON-NLS-1$ /** * This configurations attribute table. Keys are <code>String</code>s and @@ -76,6 +82,26 @@ public class LaunchConfigurationInfo { private ILaunchConfigurationType fType; /** + * Whether this configuration is a prototype + */ + private boolean fIsPrototype = false; + + /** + * This launch configuration's prototype (can be <code>null</code> if this launch configuration is already a prototype). + */ + private ILaunchConfiguration fPrototype; + + /** + * This prototype's visible attributes (can be <code>null</code> if launch configuration is not a prototype). + */ + private Set<String> fVisibleAttributes; + + /** + * Static access to the launch manager. + */ + private static LaunchManager fgLaunchManager = (LaunchManager)DebugPlugin.getDefault().getLaunchManager(); + + /** * Whether running on Sun 1.4 VM - see bug 110215 */ private static boolean fgIsSun14x = false; @@ -270,6 +296,18 @@ public class LaunchConfigurationInfo { } /** + * Returns the raw object from the attribute table or <code>null</code> if none. + * + * @param key attribute key + * @return raw attribute value + * + * @since 3.12 + */ + protected Object getObjectAttribute(String key) { + return getAttributeTable().get(key); + } + + /** * Returns the <code>java.util.Map</code> attribute with the given key or * the given default value if undefined. * @param key the name of the attribute @@ -316,6 +354,28 @@ public class LaunchConfigurationInfo { return fType; } + /** + * Sets this configuration's prototype. + * + * @param prototype + * launch configuration prototype + * + * @since 3.12 + */ + protected void setPrototype(ILaunchConfiguration prototype) { + fPrototype = prototype; + } + + /** + * Returns this configuration's prototype, if it exists. + * + * @return launch configuration prototype (can be <code>null</code>) + * + * @since 3.12 + */ + protected ILaunchConfiguration getPrototype() { + return fPrototype; + } /** * Returns a copy of this info object @@ -326,6 +386,9 @@ public class LaunchConfigurationInfo { LaunchConfigurationInfo copy = new LaunchConfigurationInfo(); copy.setType(getType()); copy.setAttributeTable(getAttributes()); + copy.setIsPrototype(isPrototype()); + copy.setPrototype(getPrototype()); + copy.setVisibleAttributes(getVisibleAttributes()); return copy; } @@ -350,8 +413,14 @@ public class LaunchConfigurationInfo { protected void setAttribute(String key, Object value) { if (value == null) { getAttributeTable().remove(key); + setAttributeVisibility(key, false); } else { - getAttributeTable().put(key, value); + Object attribute = getAttributeTable().put(key, value); + // If attribute is new in the table and the configuration is a + // prototype, then add it to the visible attributes + if (attribute == null && fIsPrototype) { + setAttributeVisibility(key, true); + } } } @@ -376,6 +445,13 @@ public class LaunchConfigurationInfo { configRootElement.setAttribute(TYPE, getType().getIdentifier()); + ILaunchConfiguration prototype = getPrototype(); + if (prototype != null) { + configRootElement.setAttribute(PROTOTYPE, prototype.getName()); + } else if (isPrototype()) { + configRootElement.setAttribute(VISIBLE_ATTRIBUTES, getVisibleAttributes().stream().collect(Collectors.joining(", "))); //$NON-NLS-1$ + } + for (String key : getAttributeTable().keySet()) { if (key == null) { throw new DebugException( @@ -509,6 +585,19 @@ public class LaunchConfigurationInfo { * @throws CoreException if a problem is encountered */ protected void initializeFromXML(Element root) throws CoreException { + initializeFromXML(root, false); + } + + /** + * Initializes the mapping of attributes from the XML file + * + * @param root the root node from the XML document + * @param isPrototype if the XML file corresponds to a prototype + * @throws CoreException if a problem is encountered + * + * @since 3.12 + */ + protected void initializeFromXML(Element root, boolean isPrototype) throws CoreException { if (!root.getNodeName().equalsIgnoreCase(LAUNCH_CONFIGURATION)) { throw getInvalidFormatDebugException(); } @@ -555,6 +644,27 @@ public class LaunchConfigurationInfo { } } } + + if (isPrototype) { + setIsPrototype(true); + String visibleAttributes = root.getAttribute(VISIBLE_ATTRIBUTES); + if (visibleAttributes != null && visibleAttributes.length() > 0) { + String[] split = visibleAttributes.split(", "); //$NON-NLS-1$ + setVisibleAttributes(new HashSet<>(Arrays.asList(split))); + } + } else { + setIsPrototype(false); + String prototype = root.getAttribute(PROTOTYPE); + if (prototype != null && prototype.length() > 0) { + ILaunchConfiguration[] launchConfigurations = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(ILaunchConfiguration.PROTOTYPE); + for (ILaunchConfiguration iLaunchConfiguration : launchConfigurations) { + if (prototype.equals(iLaunchConfiguration.getName())) { + setPrototype(iLaunchConfiguration); + break; + } + } + } + } } /** @@ -730,6 +840,13 @@ public class LaunchConfigurationInfo { return false; } + // In case of a prototype, make sure the visible attributes are the same + if (isPrototype() != other.isPrototype()) { + return false; + } else if (isPrototype() && !getVisibleAttributes().equals(other.getVisibleAttributes())) { + return false; + } + // Make sure the attributes are the same return compareAttributes(fAttributes, other.getAttributeTable()); } @@ -743,42 +860,63 @@ public class LaunchConfigurationInfo { * @return whether the two attribute maps are equal */ protected boolean compareAttributes(TreeMap<String, Object> map1, TreeMap<String, Object> map2) { - LaunchManager manager = (LaunchManager)DebugPlugin.getDefault().getLaunchManager(); if (map1.size() == map2.size()) { Iterator<String> attributes = map1.keySet().iterator(); while (attributes.hasNext()) { String key = attributes.next(); Object attr1 = map1.get(key); Object attr2 = map2.get(key); - if (attr2 == null) { + if (!compareAttribute(key, attr1, attr2)) { return false; } - Comparator<Object> comp = manager.getComparator(key); - if (comp == null) { - if (fgIsSun14x) { - if(attr2 instanceof String & attr1 instanceof String) { - // this is a hack for bug 110215, on SUN 1.4.x, \r - // is stripped off when the stream is written to the - // DOM - // this is not the case for 1.5.x, so to be safe we - // are stripping \r off all strings before we - // compare for equality - attr1 = ((String)attr1).replaceAll("\\r", ""); //$NON-NLS-1$ //$NON-NLS-2$ - attr2 = ((String)attr2).replaceAll("\\r", ""); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - if (!attr1.equals(attr2)) { - return false; - } - } else { - if (comp.compare(attr1, attr2) != 0) { + } + return true; + } + return false; + } + + /** + * Returns whether the two attributes are equal, considering comparator extensions. + * + * @param key attribute key + * @param attr1 attribute value + * @param attr2 attribute value to compare to, possibly <code>null</code> + * @return whether equivalent + * + * @since 3.12 + */ + protected static boolean compareAttribute(String key, Object attr1, Object attr2) { + if (attr2 == null) { + return false; + } + Comparator<Object> comp = fgLaunchManager.getComparator(key); + if (comp == null) { + String strAttr1 = null; + String strAttr2 = null; + if (fgIsSun14x) { + if(attr2 instanceof String & attr1 instanceof String) { + // this is a hack for bug 110215, on SUN 1.4.x, \r + // is stripped off when the stream is written to the + // DOM + // this is not the case for 1.5.x, so to be safe we + // are stripping \r off all strings before we + // compare for equality + strAttr1 = ((String)attr1).replaceAll("\\r", ""); //$NON-NLS-1$ //$NON-NLS-2$ + strAttr2 = ((String)attr2).replaceAll("\\r", ""); //$NON-NLS-1$ //$NON-NLS-2$ + if (!strAttr1.equals(strAttr2)) { return false; } } } - return true; + if (strAttr1 == null && strAttr2 == null && !attr1.equals(attr2)) { + return false; + } + } else { + if (comp.compare(attr1, attr2) != 0) { + return false; + } } - return false; + return true; } /** @@ -815,5 +953,89 @@ public class LaunchConfigurationInfo { } return null; } + + /** + * Sets whether this info is a prototype. + * + * @param isPrototype + * + * @since 3.12 + */ + protected void setIsPrototype(boolean isPrototype) { + fIsPrototype = isPrototype; + } + + /** + * Returns whether this info is a prototype. + * + * @return whether a prototype + * + * @since 3.12 + */ + protected boolean isPrototype() { + return fIsPrototype; + } + + /** + * Get the visible attributes of this prototype (return <code>null</code> if + * the launch configuration is not a prototype). + * + * @return the visible attributes of this prototype (return + * <code>null</code> if the launch configuration is not a + * prototype). + * + * @since 3.12 + */ + protected Set<String> getVisibleAttributes() { + if (!isPrototype()) { + return null; + } else if (fVisibleAttributes == null) { + initializeVisibleAttributes(); + } + return fVisibleAttributes; + } + + /** + * Initialize the visible attributes of this launch configuration. All + * attributes are visible by default. + * + * @since 3.12 + */ + private void initializeVisibleAttributes() { + fVisibleAttributes = new HashSet<>(getAttributeTable().keySet()); + } + + /** + * Set the visible attributes of this prototype. Do not call this method on + * a launch configuration that is not a prototype. + * + * @param visibleAttributes the visible attributes + * + * @since 3.12 + */ + protected void setVisibleAttributes(Set<String> visibleAttributes) { + if (visibleAttributes != null) { + fVisibleAttributes = new HashSet<>(visibleAttributes); + } + } + + /** + * Set visibility of the given attribute. Do not call this method on a + * launch configuration that is not a prototype. + * + * @param attribute the given attribute + * @param visible the visibility + * + * @since 3.12 + */ + protected void setAttributeVisibility(String attribute, boolean visible) { + if (fVisibleAttributes != null) { + if (visible) { + fVisibleAttributes.add(attribute); + } else { + fVisibleAttributes.remove(attribute); + } + } + } } diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationType.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationType.java index 8848883ed..cd7595266 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationType.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationType.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. + * Copyright (c) 2000, 2017 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes *******************************************************************************/ package org.eclipse.debug.internal.core; @@ -518,5 +519,37 @@ public class LaunchConfigurationType extends PlatformObject implements ILaunchCo void resetPreferredDelegates() { fPreferredDelegates = null; } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfigurationType#getPrototypes() + */ + @Override + public ILaunchConfiguration[] getPrototypes() throws CoreException { + return DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(this, ILaunchConfiguration.PROTOTYPE); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfigurationType#newPrototypeInstance(org.eclipse.core.resources.IContainer, java.lang.String) + */ + @Override + public ILaunchConfigurationWorkingCopy newPrototypeInstance(IContainer container, String name) throws CoreException { + LaunchConfigurationWorkingCopy wc = new LaunchConfigurationWorkingCopy(container, name, this, true); + return wc; + } + + /* + * (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfigurationType#supportsPrototypes() + */ + @Override + public boolean supportsPrototypes() { + String allowPrototypesString = fElement.getAttribute(IConfigurationElementConstants.ALLOW_PROTOTYPES); + if (allowPrototypesString != null) { + if (allowPrototypesString.equalsIgnoreCase("true")) { //$NON-NLS-1$ + return true; + } + } + return false; + } } diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationWorkingCopy.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationWorkingCopy.java index cbf77aabf..ec489c414 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationWorkingCopy.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchConfigurationWorkingCopy.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2015 IBM Corporation and others. + * Copyright (c) 2000, 2017 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes *******************************************************************************/ package org.eclipse.debug.internal.core; @@ -16,6 +17,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -91,7 +93,7 @@ public class LaunchConfigurationWorkingCopy extends LaunchConfiguration implemen * working copy's attributes based on the original configuration */ protected LaunchConfigurationWorkingCopy(LaunchConfiguration original) throws CoreException { - super(original.getName(), original.getContainer()); + super(original.getName(), original.getContainer(), original.isPrototype()); copyFrom(original); setOriginal(original); fSuppressChange = false; @@ -117,7 +119,7 @@ public class LaunchConfigurationWorkingCopy extends LaunchConfiguration implemen * working copy's attributes based on the original configuration */ protected LaunchConfigurationWorkingCopy(LaunchConfigurationWorkingCopy parent) throws CoreException { - super(parent.getName(), parent.getContainer()); + super(parent.getName(), parent.getContainer(), parent.isPrototype()); copyFrom(parent); setOriginal((LaunchConfiguration) parent.getOriginal()); fParent = parent; @@ -136,7 +138,7 @@ public class LaunchConfigurationWorkingCopy extends LaunchConfiguration implemen * working copy's attributes based on the original configuration */ protected LaunchConfigurationWorkingCopy(LaunchConfiguration original, String name) throws CoreException { - super(name, original.getContainer()); + super(name, original.getContainer(), original.isPrototype()); copyFrom(original); fSuppressChange = false; } @@ -151,9 +153,26 @@ public class LaunchConfigurationWorkingCopy extends LaunchConfiguration implemen * @param type the type of this working copy */ protected LaunchConfigurationWorkingCopy(IContainer container, String name, ILaunchConfigurationType type) { - super(name, container); + this(container, name, type, false); + } + + /** + * Constructs a new working copy to be created in the specified + * location. + * + * @param container the container that the configuration will be created in + * or <code>null</code> if to be local + * @param name the name of the new launch configuration + * @param type the type of this working copy + * @param prototype if this copy is a prototype or not + * + * @since 3.12 + */ + protected LaunchConfigurationWorkingCopy(IContainer container, String name, ILaunchConfigurationType type, boolean prototype) { + super(name, container, prototype); setInfo(new LaunchConfigurationInfo()); getInfo().setType(type); + getInfo().setIsPrototype(prototype); fSuppressChange = false; } @@ -227,7 +246,7 @@ public class LaunchConfigurationWorkingCopy extends LaunchConfiguration implemen lmonitor.done(); } } - return new LaunchConfiguration(getName(), getContainer()); + return new LaunchConfiguration(getName(), getContainer(), isPrototype()); } /** @@ -241,7 +260,7 @@ public class LaunchConfigurationWorkingCopy extends LaunchConfiguration implemen // set up from/to information if this is a move boolean moved = (!isNew() && isMoved()); if (moved) { - ILaunchConfiguration to = new LaunchConfiguration(getName(), getContainer()); + ILaunchConfiguration to = new LaunchConfiguration(getName(), getContainer(), isPrototype()); ILaunchConfiguration from = getOriginal(); getLaunchManager().setMovedFromTo(from, to); } @@ -379,9 +398,9 @@ public class LaunchConfigurationWorkingCopy extends LaunchConfiguration implemen } // notify of add/change for both local and shared configurations - see bug 288368 if (added) { - getLaunchManager().launchConfigurationAdded(new LaunchConfiguration(getName(), getContainer())); + getLaunchManager().launchConfigurationAdded(new LaunchConfiguration(getName(), getContainer(), isPrototype())); } else { - getLaunchManager().launchConfigurationChanged(new LaunchConfiguration(getName(), getContainer())); + getLaunchManager().launchConfigurationChanged(new LaunchConfiguration(getName(), getContainer(), isPrototype())); } } finally { @@ -462,6 +481,15 @@ public class LaunchConfigurationWorkingCopy extends LaunchConfiguration implemen } /** + * @see ILaunchConfigurationWorkingCopy#setAttribute(String, Object) + */ + @Override + public void setAttribute(String attributeName, Object value) { + getInfo().setAttribute(attributeName, value); + setDirty(); + } + + /** * @see ILaunchConfigurationWorkingCopy#getOriginal() */ @Override @@ -755,5 +783,81 @@ public class LaunchConfigurationWorkingCopy extends LaunchConfiguration implemen public Object removeAttribute(String attributeName) { return getInfo().removeAttribute(attributeName); } -} + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfigurationWorkingCopy#copyAttributes(org.eclipse.debug.core.ILaunchConfiguration) + */ + @Override + public void copyAttributes(ILaunchConfiguration prototype) throws CoreException { + Map<String, Object> map = prototype.getAttributes(); + LaunchConfigurationInfo info = getInfo(); + info.setPrototype(prototype); + Set<String> prototypeVisibleAttributes = prototype.getPrototypeVisibleAttributes(); + if (prototypeVisibleAttributes != null) { + prototypeVisibleAttributes.forEach(key -> { + Object value = map.get(key); + if (value != null) { + info.setAttribute(key, value); + } + }); + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfigurationWorkingCopy#setTemplate(org.eclipse.debug.core.ILaunchConfiguration, boolean) + */ + @Override + public void setPrototype(ILaunchConfiguration prototype, boolean copy) throws CoreException { + if (prototype != null && !prototype.isPrototype()) { + throw new CoreException(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugCoreMessages.LaunchConfigurationWorkingCopy_6)); + } + if (prototype != null && prototype.isWorkingCopy()) { + throw new CoreException(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugCoreMessages.LaunchConfigurationWorkingCopy_7)); + } + if (prototype == null) { + getInfo().setPrototype(null); + removeAttribute(ATTR_PROTOTYPE); + } else { + if (isPrototype()) { + throw new CoreException(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugCoreMessages.LaunchConfigurationWorkingCopy_8)); + } + getInfo().setPrototype(prototype); + if (copy) { + copyAttributes(prototype); + } + setAttribute(ATTR_PROTOTYPE, prototype.getMemento()); + setAttribute(IS_PROTOTYPE, false); + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfigurationWorkingCopy#doSave(int) + */ + @Override + public ILaunchConfiguration doSave(int flag) throws CoreException { + Collection<ILaunchConfiguration> children = null; + if (UPDATE_PROTOTYPE_CHILDREN == flag) { + if (!isNew() && isMoved() && getParent() == null) { + children = getOriginal().getPrototypeChildren(); + } + } + ILaunchConfiguration saved = doSave(); + if (children != null) { + for (ILaunchConfiguration child : children) { + ILaunchConfigurationWorkingCopy wc = child.getWorkingCopy(); + wc.setPrototype(saved, false); + wc.doSave(); + } + } + return saved; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchConfiguration#setAttributeVisibility(String, boolean) + */ + @Override + public void setPrototypeAttributeVisibility(String attribute, boolean visible) throws CoreException { + super.setPrototypeAttributeVisibility(attribute, visible); + setDirty(); + } +} diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchManager.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchManager.java index 32cdb6a01..f7078181f 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchManager.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/LaunchManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2016 IBM Corporation and others. + * Copyright (c) 2000, 2017 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 @@ -12,6 +12,7 @@ * attempt to disconnect debug targets before terminating them * Alena Laskavaia - Bug 259281 * Marc Khouzam - Bug 313143: Preferred Launch Delegate not recovered from preferences + * Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes *******************************************************************************/ package org.eclipse.debug.internal.core; @@ -34,6 +35,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -378,7 +380,7 @@ public class LaunchManager extends PlatformObject implements ILaunchManager, IRe IResource resource = delta.getResource(); if (resource instanceof IFile) { IFile file = (IFile)resource; - if (ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION.equals(file.getFileExtension())) { + if (ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION.equals(file.getFileExtension()) || ILaunchConfiguration.LAUNCH_CONFIGURATION_PROTOTYPE_FILE_EXTENSION.equals(file.getFileExtension())) { ILaunchConfiguration handle = new LaunchConfiguration(file); switch (delta.getKind()) { case IResourceDelta.ADDED : @@ -476,7 +478,7 @@ public class LaunchManager extends PlatformObject implements ILaunchManager, IRe @Override public boolean visit(IResourceProxy proxy) { if (proxy.getType() == IResource.FILE) { - if (ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION.equalsIgnoreCase(proxy.requestFullPath().getFileExtension())) { + if (ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION.equalsIgnoreCase(proxy.requestFullPath().getFileExtension()) | ILaunchConfiguration.LAUNCH_CONFIGURATION_PROTOTYPE_FILE_EXTENSION.equalsIgnoreCase(proxy.requestFullPath().getFileExtension())) { fList.add(proxy.requestResource()); } return false; @@ -947,12 +949,33 @@ public class LaunchManager extends PlatformObject implements ILaunchManager, IRe ParserConfigurationException, IOException, SAXException { + return createInfoFromXML(stream, false); + } + + /** + * 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 + * @param isPrototype if the XML corresponds to a prototype + * @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 + * + * @since 3.12 + */ + protected LaunchConfigurationInfo createInfoFromXML(InputStream stream, boolean isPrototype) 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); + info.initializeFromXML(root, isPrototype); return info; } @@ -1011,23 +1034,37 @@ public class LaunchManager extends PlatformObject implements ILaunchManager, IRe IPath containerPath = LOCAL_LAUNCH_CONFIGURATION_CONTAINER_PATH; final File directory = containerPath.toFile(); if (directory.isDirectory()) { - FilenameFilter filter = new FilenameFilter() { + List<ILaunchConfiguration> configs = new ArrayList<ILaunchConfiguration>(); + FilenameFilter configFilter = 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); + File[] configFiles = directory.listFiles(configFilter); + if (configFiles.length > 0) { + LaunchConfiguration config = null; + for (int i = 0; i < configFiles.length; i++) { + config = new LaunchConfiguration(LaunchConfiguration.getSimpleName(configFiles[i].getName()), null, false); + configs.add(config); + } + } + FilenameFilter prototypeFilter = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return dir.equals(directory) && name.endsWith(ILaunchConfiguration.LAUNCH_CONFIGURATION_PROTOTYPE_FILE_EXTENSION); + } + }; + File[] prototypeFiles = directory.listFiles(prototypeFilter); + if (prototypeFiles.length > 0) { LaunchConfiguration config = null; - for (int i = 0; i < files.length; i++) { - config = new LaunchConfiguration(LaunchConfiguration.getSimpleName(files[i].getName()), null); + for (int i = 0; i < prototypeFiles.length; i++) { + config = new LaunchConfiguration(LaunchConfiguration.getSimpleName(prototypeFiles[i].getName()), null, true); configs.add(config); } - return configs; } + return configs; } return Collections.EMPTY_LIST; } @@ -1160,7 +1197,8 @@ public class LaunchManager extends PlatformObject implements ILaunchManager, IRe */ protected synchronized String[] getAllSortedConfigNames() { if (fSortedConfigNames == null) { - ILaunchConfiguration[] configs = getLaunchConfigurations(); + List<ILaunchConfiguration> collection = getAllLaunchConfigurations(); + ILaunchConfiguration[] configs = collection.toArray(new ILaunchConfiguration[collection.size()]); fSortedConfigNames = new String[configs.length]; for (int i = 0; i < configs.length; i++) { fSortedConfigNames[i] = configs[i].getName(); @@ -1368,7 +1406,7 @@ public class LaunchManager extends PlatformObject implements ILaunchManager, IRe BufferedInputStream stream = null; try { stream = new BufferedInputStream(store.openInputStream(EFS.NONE, null)); - info = createInfoFromXML(stream); + info = createInfoFromXML(stream, isPrototype(store)); synchronized (this) { fLaunchConfigurations.put(config, info); } @@ -1403,6 +1441,38 @@ public class LaunchManager extends PlatformObject implements ILaunchManager, IRe } /** + * Check if the given {@link IFileStore} is a prototype. + * + * @param store the given {@link IFileStore} + * @return <code>true</code> if the given {@link IFileStore} is a prototype, + * <code>false</code> otherwise. + * + * @since 3.12 + */ + private boolean isPrototype(IFileStore store) { + if (store.getName().endsWith("." + ILaunchConfiguration.LAUNCH_CONFIGURATION_PROTOTYPE_FILE_EXTENSION)) { //$NON-NLS-1$ + return true; + } + return false; + } + + /** + * Check if the given {@link File} is a prototype. + * + * @param file the given {@link File} + * @return <code>true</code> if the given {@link File} is a prototype, + * <code>false</code> otherwise. + * + * @since 3.12 + */ + private boolean isPrototype(File file) { + if (file.getName().endsWith("." + ILaunchConfiguration.LAUNCH_CONFIGURATION_PROTOTYPE_FILE_EXTENSION)) { //$NON-NLS-1$ + return true; + } + return false; + } + + /** * @see ILaunchManager#getLaunchConfiguration(IFile) */ @Override @@ -1425,8 +1495,33 @@ public class LaunchManager extends PlatformObject implements ILaunchManager, IRe */ @Override public synchronized ILaunchConfiguration[] getLaunchConfigurations() { + return getLaunchConfigurations(ILaunchConfiguration.CONFIGURATION); + } + + /** + * @see org.eclipse.debug.core.ILaunchManager#getLaunchConfigurations(int) + */ + @Override + public ILaunchConfiguration[] getLaunchConfigurations(int kinds) { List<ILaunchConfiguration> allConfigs = getAllLaunchConfigurations(); - return allConfigs.toArray(new ILaunchConfiguration[allConfigs.size()]); + if (((kinds & ILaunchConfiguration.CONFIGURATION) > 0) && ((kinds & ILaunchConfiguration.PROTOTYPE) > 0)) { + // all kinds + return allConfigs.toArray(new ILaunchConfiguration[allConfigs.size()]); + } else { + List<ILaunchConfiguration> select = new ArrayList<ILaunchConfiguration>(allConfigs.size()); + Iterator<ILaunchConfiguration> iterator = allConfigs.iterator(); + while (iterator.hasNext()) { + ILaunchConfiguration config = iterator.next(); + try { + if ((config.getKind() & kinds) > 0) { + select.add(config); + } + } catch (CoreException e) { + DebugPlugin.log(e); + } + } + return select.toArray(new ILaunchConfiguration[select.size()]); + } } /** @@ -1434,9 +1529,17 @@ public class LaunchManager extends PlatformObject implements ILaunchManager, IRe */ @Override public synchronized ILaunchConfiguration[] getLaunchConfigurations(ILaunchConfigurationType type) throws CoreException { + return getLaunchConfigurations(type, ILaunchConfiguration.CONFIGURATION); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchManager#getLaunchConfigurations(org.eclipse.debug.core.ILaunchConfigurationType, int) + */ + @Override + public synchronized ILaunchConfiguration[] getLaunchConfigurations(ILaunchConfigurationType type, int kinds) throws CoreException { List<ILaunchConfiguration> configs = new ArrayList<ILaunchConfiguration>(); for (ILaunchConfiguration config : getAllLaunchConfigurations()) { - if (config.getType().equals(type)) { + if (config.getType().equals(type) && ((config.getKind() & kinds) > 0)) { configs.add(config); } } @@ -2571,7 +2674,11 @@ public class LaunchManager extends PlatformObject implements ILaunchManager, IRe if (!config.isLocal()) { StringBuffer buf = new StringBuffer(config.getName()); buf.append('.'); - buf.append(ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION); + if (config.isPrototype()) { + buf.append(ILaunchConfiguration.LAUNCH_CONFIGURATION_PROTOTYPE_FILE_EXTENSION); + } else { + buf.append(ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION); + } sharedConfigs.put(buf.toString(), config); } } @@ -2592,7 +2699,7 @@ public class LaunchManager extends PlatformObject implements ILaunchManager, IRe boolean added = !target.exists(); try { copyFile(source, target); - ILaunchConfiguration configuration = new LaunchConfiguration(LaunchConfiguration.getSimpleName(source.getName()), null); + ILaunchConfiguration configuration = new LaunchConfiguration(LaunchConfiguration.getSimpleName(source.getName()), null, isPrototype(source)); ILaunchConfiguration shared = sharedConfigs.get(target.getName()); if (shared != null) { setMovedFromTo(shared, configuration); diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupMemberChangeListener.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupMemberChangeListener.java index 3208b538b..55d63d0ca 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupMemberChangeListener.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupMemberChangeListener.java @@ -7,6 +7,7 @@ * * Contributors: * SSI Schaefer IT Solutions GmbH + * Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes *******************************************************************************/ package org.eclipse.debug.internal.core.groups; @@ -40,7 +41,7 @@ public class GroupMemberChangeListener implements ILaunchConfigurationListener { return; } try { - for (ILaunchConfiguration c : DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(type)) { + for (ILaunchConfiguration c : DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(type, ILaunchConfiguration.CONFIGURATION | ILaunchConfiguration.PROTOTYPE)) { List<GroupLaunchElement> elements = GroupLaunchConfigurationDelegate.createLaunchElements(c); boolean updated = false; for (GroupLaunchElement e : elements) { |