blob: 89d4f015b096ef89fd3cfffdd694ffcd3687b0c8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 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.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 if an error occurs
*/
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 (IResource root : roots) {
if (root.getFullPath().isPrefixOf(fullPath)) {
return true;
}
}
return false;
}
}