Skip to main content
summaryrefslogtreecommitdiffstats
blob: 330e5aa319ff6f4278304f78c670b0f6d2d7ac83 (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
/*******************************************************************************
 * Copyright (c) 2014, 2015 Obeo and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Obeo - initial API and implementation
 *     Alexandra Buzila - Fixes for Bug 462938
 *******************************************************************************/
package org.eclipse.emf.compare.ide.ui.internal.logical.resolver;

import com.google.common.eventbus.EventBus;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.compare.ide.ui.logical.AbstractModelResolver;
import org.eclipse.emf.compare.ide.ui.logical.IModelResolver;
import org.eclipse.emf.compare.ide.ui.logical.IStorageProviderAccessor;
import org.eclipse.emf.compare.ide.ui.logical.SynchronizationModel;
import org.eclipse.emf.compare.ide.utils.StorageTraversal;
import org.eclipse.emf.compare.internal.utils.Graph;
import org.eclipse.emf.compare.internal.utils.ReadOnlyGraph;

/**
 * This implementation of an {@link IModelResolver} will look up all of the models located in a set container
 * level of the "starting point" (by default, the containing project) to construct the graph of dependencies
 * between these models.
 * <p>
 * Once this graph is created for the "local" resource, the right and origin (if any) resources will be
 * inferred from the same traversal of resources, though this time expanded with a "top-down" approach : load
 * all models of the traversal from the remote side, then resolve their containment tree to check whether
 * there are other remote resources in the logical model that do not (or "that no longer) exist locally and
 * thus couldn't be discovered in the first resolution phase. <b>Note</b> that this will be looped in order to
 * determine whether the resource is really inexistent locally, or if on the contrary, it is a new dependency
 * that's been added remotely; in which case we need to start from the local resolution again : the local
 * resource may have changed locally and depend on other again.
 * </p>
 * <p>
 * All model loading will happen concurrently. At first, a distinct thread will be launched to resolve every
 * model discovered in the container we're browsing. Then, each thread can and will launch separate threads to
 * resolve the set of dependencies discovered "under" the model they are in charge of resolving.
 * </p>
 * <p>
 * No model will be loaded twice, since this will be aware of what models have already been resolved, thus
 * ignoring duplicate resolving demands.
 * </p>
 * 
 * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
 */
public class ThreadedModelResolver extends AbstractModelResolver {

	private IResolutionContext context;

	/**
	 * Convert the dependency graph to its read-only version.
	 * 
	 * @return a read-only version of the dependency graph associated to this model resolver.
	 */
	public ReadOnlyGraph<URI> getDependencyGraph() {
		return ReadOnlyGraph.toReadOnlyGraph(context.getGraph());
	}

	/**
	 * {@inheritDoc} When initialized, the ThreadedModelResolver will:
	 * <ol>
	 * <li>install a listener on the workspace to keep track of modified resources</li>
	 * <li>Register its {@link #graphUpdater} to its {@link #eventBus}</li>
	 * <li>initialize its {@link #scheduler}</li>
	 * </ol>
	 */
	@Override
	public void initialize() {
		super.initialize();
		EventBus eventBus = new EventBus();
		Graph<URI> graph = new Graph<URI>();
		this.context = createContext(eventBus, graph);
		context.initialize();
	}

	/** {@inheritDoc} */
	@Override
	public void dispose() {
		context.dispose();
		super.dispose();
	}

	/**
	 * For testing purposes, this method is protected.
	 * 
	 * @param eventBus
	 * @param graph
	 * @return The resolution context to use.
	 */
	protected DefaultResolutionContext createContext(EventBus eventBus, Graph<URI> graph) {
		return new DefaultResolutionContext(eventBus, graph,
				new DependencyGraphUpdater<URI>(graph, eventBus), new ResourceComputationScheduler<URI>(),
				new ModelResourceListener());
	}

	/** {@inheritDoc} */
	public boolean canResolve(IStorage sourceStorage) {
		return true;
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * Note that no two threads will be able to resolve models at once : all three "resolve*" methods will
	 * lock internally to prevent multiple resolutions at once. Though this shouldn't happen unless the user
	 * calls multiple comparisons one after the other in quick succession, we use this locking to prevent
	 * potential unforeseen interactions.
	 * </p>
	 */
	public StorageTraversal resolveLocalModel(final IResource start, final IProgressMonitor monitor)
			throws InterruptedException {
		LocalModelResolution comp = new LocalModelResolution(context, monitor);
		return comp.run(start);
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * Note that no two threads will be able to resolve models at once : all three "resolve*" methods will
	 * lock internally to prevent multiple resolutions at once. Though this shouldn't happen unless the user
	 * calls multiple comparisons one after the other in quick succession, we use this locking to prevent
	 * potential unforeseen interactions.
	 * </p>
	 */
	public SynchronizationModel resolveLocalModels(IResource left, IResource right, IResource origin,
			IProgressMonitor monitor) throws InterruptedException {
		LocalModelsResolution comp = new LocalModelsResolution(context, left, right, origin, monitor);
		return comp.run();
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * Note that no two threads will be able to resolve models at once : all three "resolve*" methods will
	 * lock internally to prevent multiple resolutions at once. Though this shouldn't happen unless the user
	 * calls multiple comparisons one after the other in quick succession, we use this locking to prevent
	 * potential unforeseen interactions.
	 * </p>
	 */
	public SynchronizationModel resolveModels(final IStorageProviderAccessor storageAccessor,
			final IStorage left, final IStorage right, final IStorage origin, final IProgressMonitor monitor)
			throws InterruptedException {
		ModelsResolution comp = new ModelsResolution(context, monitor, storageAccessor, left, right, origin);
		return comp.run();
	}
}

Back to the top