[Preferences] Make rebuild by ConfigurationBlocks compatible with
PreferenceSetService

Change-Id: I41ac7bf76f1eb319912ca28bdd307b92dbf668b7
diff --git a/ecommons/org.eclipse.statet.ecommons.preferences.core/src/org/eclipse/statet/ecommons/preferences/core/PreferenceSetService.java b/ecommons/org.eclipse.statet.ecommons.preferences.core/src/org/eclipse/statet/ecommons/preferences/core/PreferenceSetService.java
index 8c0adc2..2caf341 100644
--- a/ecommons/org.eclipse.statet.ecommons.preferences.core/src/org/eclipse/statet/ecommons/preferences/core/PreferenceSetService.java
+++ b/ecommons/org.eclipse.statet.ecommons.preferences.core/src/org/eclipse/statet/ecommons/preferences/core/PreferenceSetService.java
@@ -14,7 +14,6 @@
 
 package org.eclipse.statet.ecommons.preferences.core;
 
-import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.core.runtime.preferences.IScopeContext;
 
 import org.eclipse.statet.jcommons.collections.ImList;
@@ -56,7 +55,7 @@
 	
 	boolean pause(String sourceId);
 	void resume(String sourceId);
-	Job createResumeJob(String sourceId);
+	void addResumeListener(Runnable listener);
 	
 	void addChangeListener(ChangeListener listener,
 			ImList<IScopeContext> contexts, ImSet<String> qualifiers);
diff --git a/ecommons/org.eclipse.statet.ecommons.preferences.core/src/org/eclipse/statet/ecommons/preferences/core/util/ResumeJob.java b/ecommons/org.eclipse.statet.ecommons.preferences.core/src/org/eclipse/statet/ecommons/preferences/core/util/ResumeJob.java
new file mode 100644
index 0000000..563e7f7
--- /dev/null
+++ b/ecommons/org.eclipse.statet.ecommons.preferences.core/src/org/eclipse/statet/ecommons/preferences/core/util/ResumeJob.java
@@ -0,0 +1,52 @@
+/*=============================================================================#
+ # Copyright (c) 2021 Stephan Wahlbrink and others.
+ # 
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ # 
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ # 
+ # Contributors:
+ #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.ecommons.preferences.core.util;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+
+import org.eclipse.statet.ecommons.preferences.core.PreferenceSetService;
+
+
+@NonNullByDefault
+public class ResumeJob extends Job {
+	
+	
+	private final PreferenceSetService service;
+	
+	private final String sourceId;
+	
+	
+	public ResumeJob(final PreferenceSetService service, final String sourceId) {
+		super("Resume PreferenceSetService");
+		this.service= service;
+		this.sourceId= sourceId;
+		
+		setSystem(true);
+		setPriority(SHORT);
+	}
+	
+	
+	@Override
+	protected IStatus run(final IProgressMonitor monitor) {
+		this.service.resume(this.sourceId);
+		return Status.OK_STATUS;
+	}
+	
+}
diff --git a/ecommons/org.eclipse.statet.ecommons.preferences.core/src/org/eclipse/statet/internal/ecommons/preferences/core/PreferenceSetServiceImpl.java b/ecommons/org.eclipse.statet.ecommons.preferences.core/src/org/eclipse/statet/internal/ecommons/preferences/core/PreferenceSetServiceImpl.java
index 88d3e58..764b344 100644
--- a/ecommons/org.eclipse.statet.ecommons.preferences.core/src/org/eclipse/statet/internal/ecommons/preferences/core/PreferenceSetServiceImpl.java
+++ b/ecommons/org.eclipse.statet.ecommons.preferences.core/src/org/eclipse/statet/internal/ecommons/preferences/core/PreferenceSetServiceImpl.java
@@ -14,6 +14,8 @@
 
 package org.eclipse.statet.internal.ecommons.preferences.core;
 
+import static org.eclipse.statet.internal.ecommons.preferences.core.ECommonsPreferencesCorePlugin.BUNDLE_ID;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -34,6 +36,7 @@
 import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
 import org.eclipse.core.runtime.preferences.IScopeContext;
 
+import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet;
 import org.eclipse.statet.jcommons.collections.CopyOnWriteList;
 import org.eclipse.statet.jcommons.collections.ImCollection;
 import org.eclipse.statet.jcommons.collections.ImCollections;
@@ -296,6 +299,8 @@
 	private volatile long minStamp;
 	private volatile long scheduledStamp;
 	
+	private final CopyOnWriteIdentityListSet<Runnable> resumeListeners= new CopyOnWriteIdentityListSet<>();
+	
 	private final Map<IScopeContext, ImList<NodeItem>> processMap= new HashMap<>();
 	private final ImListBuilder<?> processListBuilder= new ImListBuilder<>();
 	private final Event processEvent= new Event();
@@ -331,6 +336,18 @@
 		}
 	}
 	
+	@Override
+	public void addResumeListener(final Runnable listener) {
+		synchronized (this) {
+			if (!this.pauseIds.isEmpty()) {
+				this.resumeListeners.add(listener);
+				return;
+			}
+		}
+		
+		listener.run();
+	}
+	
 	private synchronized void onPreferenceChange() {
 		if (!this.pauseIds.isEmpty()) {
 			final long time= System.nanoTime() + MIN_WAIT_NS;
@@ -367,11 +384,6 @@
 	}
 	
 	@Override
-	public Job createResumeJob(final String key) {
-		return new NotifyJob(key);
-	}
-	
-	@Override
 	public boolean contains(final ISchedulingRule rule) {
 		return (rule == this);
 	}
@@ -507,7 +519,13 @@
 				}
 				
 				if (!event.isEmpty()) {
-					listener.getListener().onPreferenceChanged(event);
+					try {
+						listener.getListener().onPreferenceChanged(event);
+					}
+					catch (final Exception e) {
+						ECommonsPreferencesCorePlugin.log(new Status(IStatus.ERROR, BUNDLE_ID,
+								"An error occurred while notifying a preference set change listener.", e ));
+					}
 					
 					event.reset();
 				}
@@ -515,6 +533,16 @@
 		}
 		finally {
 			map.clear();
+			
+			for (final var listener : this.resumeListeners.clearToList()) {
+				try {
+					listener.run();
+				}
+				catch (final Exception e) {
+					ECommonsPreferencesCorePlugin.log(new Status(IStatus.ERROR, BUNDLE_ID,
+							"An error occurred while notifying a preference set resume listener.", e ));
+				}
+			}
 		}
 	}
 	
diff --git a/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/preferences/ui/ConfigurationBlockPreferencePage.java b/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/preferences/ui/ConfigurationBlockPreferencePage.java
index aeaedec..bd3b4ea 100644
--- a/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/preferences/ui/ConfigurationBlockPreferencePage.java
+++ b/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/preferences/ui/ConfigurationBlockPreferencePage.java
@@ -33,8 +33,9 @@
 import org.eclipse.statet.jcommons.lang.NonNullByDefault;
 import org.eclipse.statet.jcommons.lang.Nullable;
 
-import org.eclipse.statet.ecommons.preferences.core.PreferenceSetService;
 import org.eclipse.statet.ecommons.preferences.core.EPreferences;
+import org.eclipse.statet.ecommons.preferences.core.PreferenceSetService;
+import org.eclipse.statet.ecommons.preferences.core.util.ResumeJob;
 import org.eclipse.statet.ecommons.runtime.core.StatusChangeListener;
 import org.eclipse.statet.ecommons.ui.IOverlayStatus;
 import org.eclipse.statet.ecommons.ui.SharedUIResources;
@@ -155,7 +156,7 @@
 			finally {
 				if (resume) {
 					if (container != null) {
-						container.registerUpdateJob(preferenceSetService.createResumeJob(sourceId));
+						container.registerUpdateJob(new ResumeJob(preferenceSetService, sourceId));
 					}
 					else {
 						preferenceSetService.resume(sourceId);
diff --git a/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/preferences/ui/ManagedConfigurationBlock.java b/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/preferences/ui/ManagedConfigurationBlock.java
index 3b523b9..d25967f 100644
--- a/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/preferences/ui/ManagedConfigurationBlock.java
+++ b/ecommons/org.eclipse.statet.ecommons.uimisc/src/org/eclipse/statet/ecommons/preferences/ui/ManagedConfigurationBlock.java
@@ -52,6 +52,7 @@
 
 import org.eclipse.statet.ecommons.databinding.jface.DataBindingSupport;
 import org.eclipse.statet.ecommons.preferences.SettingsChangeNotifier;
+import org.eclipse.statet.ecommons.preferences.core.EPreferences;
 import org.eclipse.statet.ecommons.preferences.core.Preference;
 import org.eclipse.statet.ecommons.preferences.core.PreferenceSetService;
 import org.eclipse.statet.ecommons.preferences.core.PreferenceStore;
@@ -216,14 +217,10 @@
 					logSaveError(e);
 					return false;
 				}
-				if (doBuild) {
-					createRebuild().schedule();
-				}
 			}
-			else {
-				if (doBuild) {
-					getContainer().registerUpdateJob(createRebuild());
-				}
+			if (doBuild) {
+				final Job buildJob= createRebuild();
+				EPreferences.getPreferenceSetService().addResumeListener(buildJob::schedule);
 			}
 			final Set<String> groupIds= new HashSet<>();
 			for (final Preference<?> pref : changedPrefs) {