Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 64e9376ce7b5b0d958926eb308f6cbeaece7b4ec (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
/*******************************************************************************
 * Copyright (c) 2000, 2017 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.team.core.variants;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.team.core.Team;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.subscribers.ISubscriberChangeEvent;
import org.eclipse.team.core.subscribers.SubscriberChangeEvent;
import org.eclipse.team.internal.core.TeamPlugin;
import org.eclipse.team.internal.core.subscribers.ThreeWayBaseTree;

/**
 * A resource variant tree subscriber whose trees use an underlying
 * <code>ThreeWaySynchronizer</code> to store and manage the
 * synchronization state for the local workspace. Subclasses need to
 * provide a subclass of <code>ThreeWayRemoteTree</code> and a method
 * to create resource variant handles from the bytes cached in the
 * <code>ThreeWaySynchronizer</code>.
 *
 * @see ThreeWaySynchronizer
 * @see ThreeWayRemoteTree
 * @see CachedResourceVariant
 *
 * @since 3.0
 */
public abstract class ThreeWaySubscriber extends ResourceVariantTreeSubscriber implements ISynchronizerChangeListener {

	private ThreeWayResourceComparator comparator;
	private ThreeWayBaseTree baseTree;
	private ThreeWayRemoteTree remoteTree;
	private ThreeWaySynchronizer synchronizer;

	/**
	 * Create a three-way subscriber that uses the given synchronizer
	 * to manage the synchronization state of local resources
	 * and their variants
	 * @param synchronizer the three-way synchronizer for this subscriber
	 */
	protected ThreeWaySubscriber(ThreeWaySynchronizer synchronizer) {
		this.synchronizer = synchronizer;
		baseTree = new ThreeWayBaseTree(this);
		getSynchronizer().addListener(this);
	}

	@Override
	protected final IResourceVariantTree getBaseTree() {
		return baseTree;
	}

	@Override
	protected final IResourceVariantTree getRemoteTree() {
		if (remoteTree == null) {
			remoteTree = createRemoteTree();
		}
		return remoteTree;
	}

	@Override
	public final IResourceVariantComparator getResourceComparator() {
		if (comparator == null) {
			comparator = new ThreeWayResourceComparator(this.getSynchronizer());
		}
		return comparator;
	}

	@Override
	public void syncStateChanged(IResource[] resources) {
		fireTeamResourceChange(SubscriberChangeEvent.asSyncChangedDeltas(this, resources));
	}

	/**
	 * Returns <code>false</code> for resources that are not children
	 * of a subscriber root, are ignored by the subscriber's synchronizer
	 * or are ignored by the <code>Team.ignoreHist(IResource)</code>. Returns
	 * <code>true</code> otherwise.
	 * @see org.eclipse.team.core.subscribers.Subscriber#isSupervised(IResource)
	 */
	@Override
	public boolean isSupervised(IResource resource) throws TeamException {
		if (!isChildOfRoot(resource)) return false;
		if (getSynchronizer().isIgnored(resource)) return false;
		if (Team.isIgnoredHint(resource)) return false;
		return true;
	}

	/**
	 * Return the three-way synchronizer of this subscriber.
	 * @return the three-way synchronizer of this subscriber.
	 */
	public ThreeWaySynchronizer getSynchronizer() {
		return synchronizer;
	}

	/**
	 * Create the resource variant for the given local resource from the
	 * given bytes. The bytes are those that were previously returned
	 * from a call to <code>IResourceVariant#asBytes()</code>.
	 * @param resource the local resource
	 * @param bytes the bytes that identify a variant of the resource
	 * @return the resource variant handle recreated from the bytes
	 * @throws TeamException
	 */
	public abstract IResourceVariant getResourceVariant(IResource resource, byte[] bytes) throws TeamException;

	/**
	 * Create the three-way remote tree which provides access to the
	 * remote bytes in the three-way synchronizer. This method is invoked
	 * once when the remote tree is first accessed. The returned object is
	 * cached and reused on subsequent accesses.
	 * @return the remote tree
	 */
	protected abstract ThreeWayRemoteTree createRemoteTree();

	/**
	 * Convenience method that can be used by subclasses to notify listeners
	 * when a root is added or removed from the subscriber. The added
	 * parameter should be <code>true</code> if the root was added and <code>false</code>
	 * if it was removed.
	 * @param resource the added or removed root
	 * @param added <code>true</code> if the root was added and <code>false</code>
	 * if it was removed.
	 */
	protected void handleRootChanged(IResource resource, boolean added) {
		if (added) {
			rootAdded(resource);
		} else {
			rootRemoved(resource);
		}
	}

	private void rootAdded(IResource resource) {
		SubscriberChangeEvent delta = new SubscriberChangeEvent(this, ISubscriberChangeEvent.ROOT_ADDED, resource);
		fireTeamResourceChange(new SubscriberChangeEvent[] { delta });
	}

	private void rootRemoved(IResource resource) {
		try {
			getSynchronizer().flush(resource, IResource.DEPTH_INFINITE);
		} catch (TeamException e) {
			TeamPlugin.log(e);
		}
		SubscriberChangeEvent delta = new SubscriberChangeEvent(this, ISubscriberChangeEvent.ROOT_REMOVED, resource);
		fireTeamResourceChange(new SubscriberChangeEvent[] { delta });
	}

	private boolean isChildOfRoot(IResource resource) {
		IResource[] roots = roots();
		IPath fullPath = resource.getFullPath();
		for (int i = 0; i < roots.length; i++) {
			IResource root = roots[i];
			if (root.getFullPath().isPrefixOf(fullPath)) {
				return true;
			}
		}
		return false;
	}
}

Back to the top