Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.team.core/src/org/eclipse/team/core/variants/ThreeWaySynchronizer.java')
-rw-r--r--bundles/org.eclipse.team.core/src/org/eclipse/team/core/variants/ThreeWaySynchronizer.java519
1 files changed, 0 insertions, 519 deletions
diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/variants/ThreeWaySynchronizer.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/variants/ThreeWaySynchronizer.java
deleted file mode 100644
index 0e05c9019..000000000
--- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/variants/ThreeWaySynchronizer.java
+++ /dev/null
@@ -1,519 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
- * Contributors:
- * IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.team.core.variants;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-import org.eclipse.core.resources.IContainer;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IWorkspaceRunnable;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.ISafeRunnable;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.core.runtime.QualifiedName;
-import org.eclipse.core.runtime.jobs.ILock;
-import org.eclipse.core.runtime.jobs.ISchedulingRule;
-import org.eclipse.team.core.TeamException;
-import org.eclipse.team.internal.core.Assert;
-import org.eclipse.team.internal.core.Policy;
-import org.eclipse.team.internal.core.subscribers.BatchingLock;
-import org.eclipse.team.internal.core.subscribers.SyncByteConverter;
-import org.eclipse.team.internal.core.subscribers.BatchingLock.IFlushOperation;
-import org.eclipse.team.internal.core.subscribers.BatchingLock.ThreadInfo;
-
-/**
- * This class manages the synchronization between local resources and their
- * corresponding resource variants. It provides the following:
- * <ul>
- * <li>Three way synchronization (set base, set remote, ignored)
- * <li>Resource traversal (members)
- * <li>Change events and event batching (run)
- * <li>Thread-safety
- * </ul>
- *
- * @since 3.0
- */
-public class ThreeWaySynchronizer implements IFlushOperation {
-
- private static final byte[] IGNORED_BYTES = "i".getBytes(); //$NON-NLS-1$
-
- private ILock lock = Platform.getJobManager().newLock();
- private BatchingLock batchingLock = new BatchingLock();
- private ResourceVariantByteStore cache;
- private Set listeners = new HashSet();
-
- /**
- * Create a three-way synchronizer that uses a persistant
- * byte store with the given qualified name as its unique
- * identifier.
- * @param name the unique identifier for the persistant store
- */
- public ThreeWaySynchronizer(QualifiedName name) {
- this(new PersistantResourceVariantByteStore(name));
- }
-
- /**
- * Create a three-way synchronizer that uses the given byte store
- * as its underlying byte cache.
- * @param store the byte store this synchronizer uses to cache its bytes
- */
- public ThreeWaySynchronizer(ResourceVariantByteStore store) {
- cache = store;
- }
-
- /**
- * Adds a listener to this synchronizer. Listeners will be notified
- * when the synchronization state of a resource changes. Listeners
- * are not notified when files are modified locally. Clients can
- * make use of the <code>IResource</code> delta mechanism if they
- * need to know about local modifications.
- * Has no effect if an identical listener is already registered.
- * <p>
- * Team resource change listeners are informed about state changes
- * that affect the resources supervised by this subscriber.</p>
- *
- * @param listener a synchronizer change listener
- */
- public void addListener(ISynchronizerChangeListener listener) {
- synchronized (listeners) {
- listeners.add(listener);
- }
- }
-
- /**
- * Removes a listener previously registered with this synchronizer.
- * Has no affect if an identical listener is not registered.
- *
- * @param listener a synchronizer change listener
- */
- public void removeListener(ISynchronizerChangeListener listener) {
- synchronized (listeners) {
- listeners.remove(listener);
- }
- }
-
- /**
- * Return the base bytes that are cached for the given resource
- * or <code>null</code> if no base is cached. The returned bytes
- * should uniquely identify the resource variant that is the base
- * for the given local resource.
- *
- * @param resource the resource
- * @return the base bytes cached with the resource or <code>null</code>
- * @throws TeamException
- */
- public byte[] getBaseBytes(IResource resource) throws TeamException {
- try {
- beginOperation();
- byte[] syncBytes = internalGetSyncBytes(resource);
- if (syncBytes == null) return null;
- byte[] baseBytes = getSlot(syncBytes, 1);
- if (baseBytes == null || baseBytes.length == 0) return null;
- return baseBytes;
- } finally {
- endOperation();
- }
- }
-
- /**
- * Set the base bytes for the given resource. The provided bytes
- * should encode enough information to uniquely identify
- * (and possibly recreate) the resource variant that is the base
- * for the given local resource. In essence, setting the base
- * bytes is equivalent to marking the file as in-sync. As such,
- * setting the base bytes will also set the remote bytes and mark
- * the file as clean (i.e. having no outgoing changes).
- *
- * @param resource the resource
- * @param baseBytes the base bytes that identify the base resource variant
- * @throws TeamException
- */
- public void setBaseBytes(IResource resource, byte[] baseBytes) throws TeamException {
- Assert.isNotNull(baseBytes);
- ISchedulingRule rule = null;
- try {
- rule = beginBatching(resource, null);
- try {
- beginOperation();
- String base = new String(baseBytes);
- String[] slots = new String[] {
- new Long(resource.getModificationStamp()).toString(),
- base,
- base
- };
- byte[] syncBytes = toBytes(slots);
- internalSetSyncBytes(resource, syncBytes);
- batchingLock.resourceChanged(resource);
- } finally {
- endOperation();
- }
- } finally {
- if (rule != null) endBatching(rule, null);
- }
- }
-
- /**
- * Return whether the local resource has been modified since the last time
- * the base bytes were set. This method will return <code>false</code>
- * for ignored resources and <code>true</code> for non-existant resources
- * that have base bytes cached.
- * @param resource the resource
- * @return <code>true</code> if the resource has been modified since the
- * last time the base bytes were set.
- * @throws TeamException
- */
- public boolean isLocallyModified(IResource resource) throws TeamException {
- return ((internalGetSyncBytes(resource) == null && ! isIgnored(resource)) ||
- (getLocalTimestamp(resource) != resource.getModificationStamp()) ||
- (getBaseBytes(resource) != null && !resource.exists()));
- }
-
- /**
- * Return the remote bytes that are cached for the given resource
- * or <code>null</code> if no remote is cached. The returned bytes
- * should uniquely identify the resource variant that is the remote
- * for the given local resource.
- *
- * @param resource the resource
- * @return the remote bytes cached with the resource or <code>null</code>
- * @throws TeamException
- */
- public byte[] getRemoteBytes(IResource resource) throws TeamException {
- try {
- beginOperation();
- byte[] syncBytes = internalGetSyncBytes(resource);
- if (syncBytes == null) return null;
- byte[] remoteBytes = getSlot(syncBytes, 2);
- if (remoteBytes == null || remoteBytes.length == 0) return null;
- return remoteBytes;
- } finally {
- endOperation();
- }
- }
-
- /**
- * Set the remote bytes for the given resource. The provided bytes
- * should encode enough information to uniquely identify
- * (and possibly recreate) the resource variant that is the remote
- * for the given local resource. If the remote for a resource
- * no longer exists, <code>removeRemoteBytes(IResource)</code>
- * should be called.
- *
- * @param resource the resource
- * @param remoteBytes the base bytes that identify the remote resource variant
- * @return <code>true</code> if the remote bytes changed as a result of the set
- * @throws TeamException
- */
- public boolean setRemoteBytes(IResource resource, byte[] remoteBytes) throws TeamException {
- Assert.isNotNull(remoteBytes);
- ISchedulingRule rule = null;
- try {
- rule = beginBatching(resource, null);
- try {
- beginOperation();
- byte[] syncBytes = internalGetSyncBytes(resource);
- if (syncBytes == null) {
- String[] slots = new String[] {
- "", //$NON-NLS-1$
- "", //$NON-NLS-1$
- new String(remoteBytes)
- };
- syncBytes = toBytes(slots);
- } else {
- byte[] currentRemote = getSlot(syncBytes, 2);
- if (equals(remoteBytes, currentRemote)) return false;
- syncBytes = setSlot(syncBytes, 2, remoteBytes);
- }
- internalSetSyncBytes(resource, syncBytes);
- batchingLock.resourceChanged(resource);
- return true;
- } finally {
- endOperation();
- }
- } finally {
- if (rule != null) endBatching(rule, null);
- }
- }
-
- /**
- * Remove the remote bytes associated with the resource. This is typically
- * done when the corresponding remote resource variant no longer exists.
- * @param resource the resource
- * @return <code>true</code> if the remote bytes changed as a result of the removal
- * @throws TeamException
- */
- public boolean removeRemoteBytes(IResource resource) throws TeamException {
- ISchedulingRule rule = null;
- try {
- rule = beginBatching(resource, null);
- try {
- beginOperation();
- byte[] syncBytes = internalGetSyncBytes(resource);
- if (syncBytes != null) {
- String currentRemote = new String(getSlot(syncBytes, 2));
- if (currentRemote.length() == 0) return false;
- syncBytes = setSlot(syncBytes, 2, new byte[0]);
- internalSetSyncBytes(resource, syncBytes);
- batchingLock.resourceChanged(resource);
- return true;
- }
- return false;
- } finally {
- endOperation();
- }
- } finally {
- if (rule != null) endBatching(rule, null);
- }
- }
-
- /**
- * Return whether the given resource has sync bytes in the synchronizer.
- * @param resource the local resource
- * @return whether there are sync bytes cached for the local resources.
- */
- public boolean hasSyncBytes(IResource resource) throws TeamException {
- return internalGetSyncBytes(resource) != null;
- }
-
- /**
- * Returns whether the resource has been marked as ignored
- * using <code>setIgnored(IResource)</code>.
- * @param resource the resource
- * @return <code>true</code> if the resource is ignored.
- * @throws TeamException
- */
- public boolean isIgnored(IResource resource) throws TeamException {
- byte[] bytes = cache.getBytes(resource);
- return (bytes != null && equals(bytes, IGNORED_BYTES));
- }
-
- /**
- * Mark the resource as being ignored. Ignored resources
- * are not returned by the <code>members</code> method,
- * are never dirty (see <code>isLocallyModified</code>) and
- * do not have base or remote bytes cahced for them.
- * @param resource the resource to be ignored
- * @throws TeamException
- */
- public void setIgnored(IResource resource) throws TeamException {
- internalSetSyncBytes(resource, IGNORED_BYTES);
- }
-
- /**
- * Return the members of the local resource that either have sync bytes
- * or exist locally and are not ignored.
- * @param resource the local resource
- * @return the children of the local resource that have cached sync bytes
- * or are not ignored
- * @throws TeamException
- */
- public IResource[] members(IResource resource) throws TeamException {
- if (resource.getType() == IResource.FILE) {
- return new IResource[0];
- }
- try {
- Set potentialChildren = new HashSet();
- IContainer container = (IContainer)resource;
- if (container.exists()) {
- potentialChildren.addAll(Arrays.asList(container.members()));
- }
- potentialChildren.addAll(Arrays.asList(cache.members(resource)));
- List result = new ArrayList();
- for (Iterator iter = potentialChildren.iterator(); iter.hasNext();) {
- IResource child = (IResource) iter.next();
- if (child.exists() || hasSyncBytes(child)) {
- result.add(child);
- }
- }
- return (IResource[]) result.toArray(new IResource[result.size()]);
- } catch (CoreException e) {
- throw TeamException.asTeamException(e);
- }
- }
-
- /**
- * Flush any cached bytes for the given resource to the depth specified.
- * @param resource the resource
- * @param depth the depth of the flush (one of <code>IResource.DEPTH_ZERO</code>,
- * <code>IResource.DEPTH_ONE</code>, or <code>IResource.DEPTH_INFINITE</code>)
- * @throws TeamException
- */
- public void flush(IResource resource, int depth) throws TeamException {
- ISchedulingRule rule = null;
- try {
- rule = beginBatching(resource, null);
- try {
- beginOperation();
- if (cache.flushBytes(resource, depth)) {
- batchingLock.resourceChanged(resource);
- }
- } finally {
- endOperation();
- }
- } finally {
- if (rule != null) endBatching(rule, null);
- }
- }
-
- /**
- * Perform multiple sync state modifications and fire only a single change notification
- * at the end.
- * @param resourceRule the scheduling rule that encompasses all modifications
- * @param runnable the runnable that performs the sync state modifications
- * @param monitor a progress monitor
- * @throws TeamException
- */
- public void run(IResource resourceRule, IWorkspaceRunnable runnable, IProgressMonitor monitor) throws TeamException {
- monitor = Policy.monitorFor(monitor);
- monitor.beginTask(null, 100);
- ISchedulingRule rule = beginBatching(resourceRule, Policy.subMonitorFor(monitor, 10));
- try {
- cache.run(resourceRule, runnable, Policy.subMonitorFor(monitor, 80));
- } catch (CoreException e) {
- throw TeamException.asTeamException(e);
- } finally {
- if (rule != null) endBatching(rule, Policy.subMonitorFor(monitor, 10));
- monitor.done();
- }
- }
-
- /* (non-Javadoc)
- *
- * Callback which is invoked when the batching resource lock is released
- * or when a flush is requested (see beginBatching(IResource)).
- *
- * @see org.eclipse.team.internal.ftp.deployment.BatchingLock.IFlushOperation#flush(org.eclipse.team.internal.ftp.deployment.BatchingLock.ThreadInfo, org.eclipse.core.runtime.IProgressMonitor)
- */
- public void flush(ThreadInfo info, IProgressMonitor monitor) throws TeamException {
- if (info != null && !info.isEmpty()) {
- broadcastSyncChanges(info.getChangedResources());
- }
- }
-
- private void broadcastSyncChanges(final IResource[] resources) {
- ISynchronizerChangeListener[] allListeners;
- // Copy the listener list so we're not calling client code while synchronized
- synchronized(listeners) {
- allListeners = (ISynchronizerChangeListener[]) listeners.toArray(new ISynchronizerChangeListener[listeners.size()]);
- }
- // Notify the listeners safely so all will receive notification
- for (int i = 0; i < allListeners.length; i++) {
- final ISynchronizerChangeListener listener = allListeners[i];
- Platform.run(new ISafeRunnable() {
- public void handleException(Throwable exception) {
- // don't log the exception....it is already being logged in Platform#run
- }
- public void run() throws Exception {
- listener.syncStateChanged(resources);
-
- }
- });
- }
- }
-
- /*
- * Return the cached sync bytes for the given resource.
- * The value <code>null</code> is returned if there is no
- * cached bytes or if the resource is ignored.
- */
- private byte[] internalGetSyncBytes(IResource resource) throws TeamException {
- byte[] bytes = cache.getBytes(resource);
- if (bytes != null && equals(bytes, IGNORED_BYTES)) return null;
- return bytes;
- }
-
- /*
- * Set the cached sync bytes
- */
- private boolean internalSetSyncBytes(IResource resource, byte[] syncBytes) throws TeamException {
- return cache.setBytes(resource, syncBytes);
- }
-
- private byte[] getSlot(byte[] syncBytes, int i) {
- return SyncByteConverter.getSlot(syncBytes, i, false);
- }
-
- private byte[] setSlot(byte[] syncBytes, int i, byte[] insertBytes) throws TeamException {
- return SyncByteConverter.setSlot(syncBytes, i, insertBytes);
- }
-
- private byte[] toBytes(String[] slots) {
- return SyncByteConverter.toBytes(slots);
- }
-
- private long getLocalTimestamp(IResource resource) throws TeamException {
- try {
- beginOperation();
- byte[] syncBytes = internalGetSyncBytes(resource);
- if (syncBytes == null) return 0;
- byte[] bytes = getSlot(syncBytes, 0);
- if (bytes == null || bytes.length == 0) return 0;
- return Long.parseLong(new String(bytes));
- } finally {
- endOperation();
- }
- }
-
- private boolean equals(byte[] syncBytes, byte[] oldBytes) {
- if (syncBytes.length != oldBytes.length) return false;
- for (int i = 0; i < oldBytes.length; i++) {
- if (oldBytes[i] != syncBytes[i]) return false;
- }
- return true;
- }
-
- /*
- * Begin an access to the internal data structures of the synchronizer
- */
- private void beginOperation() {
- // Do not try to acquire the lock if the resources tree is locked
- // The reason for this is that during the resource delta phase (i.e. when the tree is locked)
- // the workspace lock is held. If we obtain our lock, there is
- // a chance of dealock. It is OK if we don't as we are still protected
- // by scheduling rules and the workspace lock.
- if (ResourcesPlugin.getWorkspace().isTreeLocked()) return;
- lock.acquire();
- }
-
- /*
- * End an access to the internal data structures of the synchronizer
- */
- private void endOperation() {
- // See beginOperation() for a description of why the lock is not obtained when the tree is locked
- if (ResourcesPlugin.getWorkspace().isTreeLocked()) return;
- lock.release();
- }
-
- /*
- * Begins a batch of operations in order to batch event changes.
- * The provided scheduling rule indicates the resources
- * that the resources affected by the operation while the returned scheduling rule
- * is the rule obtained by the lock. It may differ from the provided rule.
- */
- private ISchedulingRule beginBatching(ISchedulingRule resourceRule, IProgressMonitor monitor) {
- return batchingLock.acquire(resourceRule, this /* IFlushOperation */, monitor);
- }
-
- /*
- * Ends a batch of operations. The provided rule must be the one that was returned
- * by the corresponding call to beginBatching.
- */
- private void endBatching(ISchedulingRule rule, IProgressMonitor monitor) throws TeamException {
- batchingLock.release(rule, monitor);
- }
-}

Back to the top