Bug 520245: Avoid writing launch files with no changes

On shutdown of a debug session the launch files are written, often
(normally) with no changes. This commit prevents unneeded deltas
on the launch files and prevents a lot of the callbacks of launch
configurations changing. This also ameliorates the case in Bug 500988.

Change-Id: Iddbd9c5c5695dcd2d255cbc761a48316fa5acbb1
diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/RegisterGroupsPersistance.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/RegisterGroupsPersistance.java
index 55afb15..e952de8 100644
--- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/RegisterGroupsPersistance.java
+++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/RegisterGroupsPersistance.java
@@ -15,6 +15,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 import org.eclipse.cdt.debug.core.CDebugCorePlugin;
 import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
@@ -32,7 +33,7 @@
 import org.w3c.dom.Node;
 
 public class RegisterGroupsPersistance {
-	private static final String BLANK_STRING = ""; //$NON-NLS-1$
+	private static final String DEFAULT_ATTR_DEBUGGER_REGISTER_GROUPS_VALUE = ""; //$NON-NLS-1$
 	private static final String DEFAULT_LAUNCH_CONFIGURATION_TARGET_ATTRIBUTE = ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_REGISTER_GROUPS;
 	private static final String ELEMENT_REGISTER_GROUP_LIST = "registerGroups"; //$NON-NLS-1$
 	private static final String ATTR_REGISTER_GROUP_MEMENTO = "memento"; //$NON-NLS-1$
@@ -166,7 +167,8 @@
 		List<IRegisterGroupDescriptor> groups = new ArrayList<IRegisterGroupDescriptor>();
 		String memento;
 		
-			memento = fLaunchConfig.getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_REGISTER_GROUPS, BLANK_STRING);
+		memento = fLaunchConfig.getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_REGISTER_GROUPS,
+				DEFAULT_ATTR_DEBUGGER_REGISTER_GROUPS_VALUE);
 
 			if (memento != null && memento.length() > 0) {
 				Node node = DebugPlugin.parseDocument(memento);
@@ -207,9 +209,19 @@
 		try {
 			ILaunchConfigurationWorkingCopy wc = fLaunchConfig.getWorkingCopy();
 
-			//if no groups present, save to a blank string, i.e. expected by CDI and handled by DSF
-			wc.setAttribute(fLaunchConfigTargetAttribute, (groups.length > 0) ? getMemento(groups) : BLANK_STRING);
-			wc.doSave();
+			// if no groups present, save to a blank string, i.e. expected by CDI and
+			// handled by DSF
+			String newValue = (groups.length > 0) ? getMemento(groups) : DEFAULT_ATTR_DEBUGGER_REGISTER_GROUPS_VALUE;
+			String oldValue = DEFAULT_ATTR_DEBUGGER_REGISTER_GROUPS_VALUE;
+			try {
+				oldValue = wc.getAttribute(fLaunchConfigTargetAttribute, DEFAULT_ATTR_DEBUGGER_REGISTER_GROUPS_VALUE);
+			} catch (CoreException e) {
+				// ignored, treat as default
+			}
+			if (!Objects.equals(oldValue, newValue)) {
+				wc.setAttribute(fLaunchConfigTargetAttribute, newValue);
+				wc.doSave();
+			}
 		} catch (CoreException e) {
 			abort(e.getMessage() + ", cause: " + e.getCause(), e); //$NON-NLS-1$
 		}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java
index c324522..fde1d55 100644
--- a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java
@@ -17,6 +17,7 @@
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.ExecutionException;
 
 import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
@@ -77,6 +78,7 @@
  */
 public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBlockRetrievalExtension
 {
+	private static final String DEFAULT_ATTR_DEBUGGER_MEMORY_BLOCKS_VALUE = ""; //$NON-NLS-1$
 	private final String           fModelId;
 	private final DsfSession       fSession;
     private final DsfExecutor      fExecutor;
@@ -213,7 +215,8 @@
      */
     public void initialize(final IMemoryDMContext memoryCtx) {
         try {
-            final String memento = fLaunchConfig.getAttribute(ATTR_DEBUGGER_MEMORY_BLOCKS, ""); //$NON-NLS-1$
+			final String memento = fLaunchConfig.getAttribute(ATTR_DEBUGGER_MEMORY_BLOCKS,
+					DEFAULT_ATTR_DEBUGGER_MEMORY_BLOCKS_VALUE);
             if (memento != null && memento.trim().length() != 0) {
                 // Submit the runnable to install the monitors on dispatch thread.
                 getExecutor().submit(new Runnable() {
@@ -281,11 +284,19 @@
 	public void saveMemoryBlocks() {
 		try {
 			ILaunchConfigurationWorkingCopy wc = fLaunchConfig.getWorkingCopy();
-			wc.setAttribute(ATTR_DEBUGGER_MEMORY_BLOCKS, getMemento());
-			wc.doSave();
-		}
-		catch( CoreException e ) {
-            DsfPlugin.getDefault().getLog().log(e.getStatus());
+			String newValue = getMemento();
+			String oldValue = DEFAULT_ATTR_DEBUGGER_MEMORY_BLOCKS_VALUE;
+			try {
+				oldValue = wc.getAttribute(ATTR_DEBUGGER_MEMORY_BLOCKS, DEFAULT_ATTR_DEBUGGER_MEMORY_BLOCKS_VALUE);
+			} catch (CoreException e) {
+				// ignored, treat as default
+			}
+			if (!Objects.equals(oldValue, newValue)) {
+				wc.setAttribute(ATTR_DEBUGGER_MEMORY_BLOCKS, newValue);
+				wc.doSave();
+			}
+		} catch (CoreException e) {
+			DsfPlugin.getDefault().getLog().log(e.getStatus());
 		}
 	}