Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 68d5548822c4d1e8f464c10821fa1502da463eba (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*******************************************************************************
 * 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.core.subscribers;

import java.util.*;

import org.eclipse.core.resources.*;
import org.eclipse.core.resources.mapping.*;
import org.eclipse.core.runtime.*;
import org.eclipse.team.core.mapping.*;
import org.eclipse.team.core.mapping.provider.SynchronizationScopeManager;

/**
 * A {@link ISynchronizationScopeManager} that uses a {@link Subscriber} to provide
 * a {@link RemoteResourceMappingContext} and to notify participants when the
 * remote state of resources change.
 * @since 3.2
 */
public class SubscriberScopeManager extends SynchronizationScopeManager implements ISubscriberChangeListener {

	private final Subscriber subscriber;
	private Map<ModelProvider, ISynchronizationScopeParticipant> participants = new HashMap<>();

	/**
	 * Create a manager for the given subscriber and input.
	 * @param name a human readable name for the scope
	 * @param inputMappings the input mappings
	 * @param subscriber the subscriber
	 * @param consultModels whether models should be consulted when calculating the scope
	 */
	public SubscriberScopeManager(String name, ResourceMapping[] inputMappings, Subscriber subscriber, boolean consultModels) {
		this(name, inputMappings, subscriber, SubscriberResourceMappingContext.createContext(subscriber), consultModels);
	}

	/**
	 * Create a manager for the given subscriber and input.
	 * @param name a human readable name for the scope
	 * @param inputMappings the input mappings
	 * @param subscriber the subscriber
	 * @param context a remote resource mapping context for the subscriber
	 * @param consultModels whether models should be consulted when calculating the scope
	 */
	public SubscriberScopeManager(String name, ResourceMapping[] inputMappings, Subscriber subscriber, RemoteResourceMappingContext context, boolean consultModels) {
		super(name, inputMappings, context, consultModels);
		this.subscriber = subscriber;
	}

	/**
	 * Return the subscriber for this manager.
	 * @return the subscriber for this manager
	 */
	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);
	}

	/*
	 * Hook up the participants for the participating models.
	 * This is done to ensure that future local and remote changes to
	 * resources will update the resources contained in the scope
	 * appropriately
	 */
	/* private */ 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);
				}
			}
		}
	}

	/*
	 * Obtain a participant through the factory which is obtained using IAdaptable
	 */
	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) {
					// Handled by platform
				}
			});
		}
		if (!result.isEmpty()) {
			refresh(result.toArray(new ResourceMapping[result.size()]));
		}
	}

}

Back to the top