package org.eclipse.team.core.subscribers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.mapping.ModelProvider;
import org.eclipse.core.resources.mapping.RemoteResourceMappingContext;
import org.eclipse.core.resources.mapping.ResourceMapping;
import org.eclipse.core.resources.mapping.ResourceTraversal;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.team.core.mapping.ISynchronizationScopeManager;
import org.eclipse.team.core.mapping.ISynchronizationScopeParticipant;
import org.eclipse.team.core.mapping.ISynchronizationScopeParticipantFactory;
import org.eclipse.team.core.mapping.provider.SynchronizationScopeManager;
public class SubscriberScopeManager extends SynchronizationScopeManager implements ISubscriberChangeListener {
private final Subscriber subscriber;
private Map<ModelProvider, ISynchronizationScopeParticipant> participants = new HashMap<>();
public SubscriberScopeManager(String name, ResourceMapping[] inputMappings, Subscriber subscriber, boolean consultModels) {
this(name, inputMappings, subscriber, SubscriberResourceMappingContext.createContext(subscriber), consultModels);
}
public SubscriberScopeManager(String name, ResourceMapping[] inputMappings, Subscriber subscriber, RemoteResourceMappingContext context, boolean consultModels) {
super(name, inputMappings, context, consultModels);
this.subscriber = subscriber;
}
protected Subscriber getSubscriber() {
return subscriber;
}
@Override
public void dispose() {
for (Iterator iter = participants.values().iterator(); iter.hasNext();) {
ISynchronizationScopeParticipant p = (ISynchronizationScopeParticipant) iter.next();
p.dispose();
}
super.dispose();
}
@Override
public void initialize(IProgressMonitor monitor) throws CoreException {
ResourcesPlugin.getWorkspace().run((IWorkspaceRunnable) monitor1 -> {
SubscriberScopeManager.super.initialize(monitor1);
hookupParticipants();
getSubscriber().addListener(SubscriberScopeManager.this);
}, getSchedulingRule(), IResource.NONE, monitor);
}
@Override
public ResourceTraversal[] refresh(final ResourceMapping[] mappings, IProgressMonitor monitor) throws CoreException {
final List<ResourceTraversal[]> result = new ArrayList<>(1);
ResourcesPlugin.getWorkspace().run((IWorkspaceRunnable) monitor1 -> {
result.add(SubscriberScopeManager.super.refresh(mappings, monitor1));
hookupParticipants();
}, getSchedulingRule(), IResource.NONE, monitor);
if (result.isEmpty())
return new ResourceTraversal[0];
return result.get(0);
}
void hookupParticipants() {
ModelProvider[] providers = getScope().getModelProviders();
for (int i = 0; i < providers.length; i++) {
ModelProvider provider = providers[i];
if (!participants.containsKey(provider)) {
ISynchronizationScopeParticipant p = createParticipant(provider);
if (p != null) {
participants.put(provider, p);
}
}
}
}
private ISynchronizationScopeParticipant createParticipant(ModelProvider provider) {
Object factoryObject = provider.getAdapter(ISynchronizationScopeParticipantFactory.class);
if (factoryObject instanceof ISynchronizationScopeParticipantFactory) {
ISynchronizationScopeParticipantFactory factory = (ISynchronizationScopeParticipantFactory) factoryObject;
return factory.createParticipant(provider, this.getScope());
}
return null;
}
@Override
public void subscriberResourceChanged(ISubscriberChangeEvent[] deltas) {
List<IResource> changedResources = new ArrayList<>();
List<IProject> changedProjects = new ArrayList<>();
for (int i = 0; i < deltas.length; i++) {
ISubscriberChangeEvent event = deltas[i];
if ((event.getFlags() & (ISubscriberChangeEvent.ROOT_ADDED | ISubscriberChangeEvent.ROOT_REMOVED)) != 0) {
changedProjects.add(event.getResource().getProject());
}
if ((event.getFlags() & ISubscriberChangeEvent.SYNC_CHANGED) != 0) {
changedResources.add(event.getResource());
}
}
fireChange(changedResources.toArray(new IResource[changedResources.size()]), changedProjects.toArray(new IProject[changedProjects.size()]));
}
private void fireChange(final IResource[] resources, final IProject[] projects) {
final Set<ResourceMapping> result = new HashSet<>();
ISynchronizationScopeParticipant[] handlers = participants.values().toArray(new ISynchronizationScopeParticipant[participants.size()]);
for (int i = 0; i < handlers.length; i++) {
final ISynchronizationScopeParticipant participant = handlers[i];
SafeRunner.run(new ISafeRunnable() {
@Override
public void run() throws Exception {
ResourceMapping[] mappings = participant.handleContextChange(SubscriberScopeManager.this.getScope(), resources, projects);
for (int j = 0; j < mappings.length; j++) {
ResourceMapping mapping = mappings[j];
result.add(mapping);
}
}
@Override
public void handleException(Throwable exception) {
}
});
}
if (!result.isEmpty()) {
refresh(result.toArray(new ResourceMapping[result.size()]));
}
}
}