blob: f94fd897257d78317debe9b7e4274604ecdfd1fa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.core.subscribers;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.jobs.ILock;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.team.internal.core.Policy;
/**
* A change set manager that batches change event notification.
*/
public class BatchingChangeSetManager extends ChangeSetManager {
private ILock lock = Job.getJobManager().newLock();
public static class CollectorChangeEvent {
Set<ChangeSet> added = new HashSet<>();
Set<ChangeSet> removed = new HashSet<>();
Map<ChangeSet, IPath[]> changed = new HashMap<>();
private final BatchingChangeSetManager collector;
public CollectorChangeEvent(BatchingChangeSetManager collector) {
this.collector = collector;
}
private void setAdded(ChangeSet set) {
added.add(set);
removed.remove(set);
}
private void setRemoved(ChangeSet set) {
added.remove(set);
removed.add(set);
// Do not clear the changes list since clients may want to know what resources
// were changed before the set was removed
}
private void changed(ChangeSet changeSet, IPath[] allAffectedResources) {
if (added.contains(changeSet))
return;
IPath[] paths = changed.get(changeSet);
if (paths == null) {
changed.put(changeSet, allAffectedResources);
} else {
Set<IPath> allPaths = new HashSet<>();
for (int i = 0; i < paths.length; i++) {
IPath path = paths[i];
allPaths.add(path);
}
for (int i = 0; i < allAffectedResources.length; i++) {
IPath path = allAffectedResources[i];
allPaths.add(path);
}
changed.put(changeSet, allPaths.toArray(new IPath[allPaths.size()]));
}
}
public boolean isEmpty() {
return changed.isEmpty() && added.isEmpty() && removed.isEmpty();
}
public ChangeSet[] getAddedSets() {
return added.toArray(new ChangeSet[added.size()]);
}
public ChangeSet[] getRemovedSets() {
return removed.toArray(new ChangeSet[removed.size()]);
}
public ChangeSet[] getChangedSets() {
return changed.keySet().toArray(new ChangeSet[changed.size()]);
}
public IPath[] getChangesFor(ChangeSet set) {
return changed.get(set);
}
public BatchingChangeSetManager getSource() {
return collector;
}
}
public static interface IChangeSetCollectorChangeListener {
public void changeSetChanges(CollectorChangeEvent event, IProgressMonitor monitor);
}
private CollectorChangeEvent changes = new CollectorChangeEvent(this);
public void beginInput() {
lock.acquire();
}
public void endInput(IProgressMonitor monitor) {
try {
if (lock.getDepth() == 1) {
// Remain locked while firing the events so the handlers
// can expect the set to remain constant while they process the events
fireChanges(Policy.monitorFor(monitor));
}
} finally {
lock.release();
}
}
private void fireChanges(final IProgressMonitor monitor) {
if (changes.isEmpty()) {
return;
}
final CollectorChangeEvent event = changes;
changes = new CollectorChangeEvent(this);
Object[] listeners = getListeners();
for (int i = 0; i < listeners.length; i++) {
final IChangeSetChangeListener listener = (IChangeSetChangeListener)listeners[i];
if (listener instanceof IChangeSetCollectorChangeListener) {
final IChangeSetCollectorChangeListener csccl = (IChangeSetCollectorChangeListener) listener;
SafeRunner.run(new ISafeRunnable() {
@Override
public void handleException(Throwable exception) {
// Exceptions are logged by the platform
}
@Override
public void run() throws Exception {
csccl.changeSetChanges(event, monitor);
}
});
}
}
}
@Override
public void add(ChangeSet set) {
try {
beginInput();
super.add(set);
changes.setAdded(set);
} finally {
endInput(null);
}
}
@Override
public void remove(ChangeSet set) {
try {
beginInput();
super.remove(set);
changes.setRemoved(set);
} finally {
endInput(null);
}
}
@Override
protected void fireResourcesChangedEvent(ChangeSet changeSet, IPath[] allAffectedResources) {
super.fireResourcesChangedEvent(changeSet, allAffectedResources);
try {
beginInput();
changes.changed(changeSet, allAffectedResources);
} finally {
endInput(null);
}
}
@Override
protected void initializeSets() {
// Nothing to do
}
}