blob: 2b155a989d3149fcdde3c70b65c59ee625aadcc5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 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.internal.ccvs.core.resources;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ISynchronizer;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.CVSStatus;
import org.eclipse.team.internal.ccvs.core.ICVSFolder;
import org.eclipse.team.internal.ccvs.core.ICVSResource;
import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
import org.eclipse.team.internal.ccvs.core.util.Util;
import org.eclipse.team.internal.ccvs.core.Policy;
/**
* This cache uses session properties to hold the bytes representing the sync
* info
*/
/*package*/ class SynchronizerSyncInfoCache extends SyncInfoCache {
public SynchronizerSyncInfoCache() {
getWorkspaceSynchronizer().add(FOLDER_SYNC_KEY);
getWorkspaceSynchronizer().add(RESOURCE_SYNC_KEY);
}
/**
* Return the Eclipse Workspace Synchronizer (from org.eclipse.core.resources)
*/
private ISynchronizer getWorkspaceSynchronizer() {
return ResourcesPlugin.getWorkspace().getSynchronizer();
}
/*package*/ void flush(IProject project) throws CVSException {
purgeCache(project, true);
}
/**
* Method flush.
* @param folder
*/
/*package*/ void flush(IFolder folder) throws CVSException {
purgeCache(folder, false);
}
/**
* Returns the folder sync info for the container; null if none.
* Folder must exist and must not be the workspace root.
* The folder sync info for the container MUST ALREADY BE CACHED.
*
* @param container the container
* @return the folder sync info for the folder, or null if none.
* @see #cacheFolderSync
*/
FolderSyncInfo getCachedFolderSync(IContainer container) throws CVSException {
try {
byte[] bytes = getWorkspaceSynchronizer().getSyncInfo(FOLDER_SYNC_KEY, container);
if (bytes == null) return null;
return FolderSyncInfo.getFolderSyncInfo(bytes);
} catch (CoreException e) {
throw CVSException.wrapException(e);
}
}
/**
* Sets the folder sync info for the container; if null, deletes it.
* Folder must exist and must not be the workspace root.
* The folder sync info for the container need not have previously been
* cached.
*
* @param container the container
* @param info the new folder sync info
*/
void setCachedFolderSync(IContainer container, FolderSyncInfo info, boolean canModifyWorkspace) throws CVSException {
try {
if (info == null) {
if (container.exists() || container.isPhantom()) {
getWorkspaceSynchronizer().flushSyncInfo(FOLDER_SYNC_KEY, container, IResource.DEPTH_ZERO);
}
} else {
getWorkspaceSynchronizer().setSyncInfo(FOLDER_SYNC_KEY, container, info.getBytes());
}
} catch (CoreException e) {
throw CVSException.wrapException(e);
}
}
/**
* @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#getCachedSyncBytes(org.eclipse.core.resources.IResource)
*/
byte[] getCachedSyncBytes(IResource resource) throws CVSException {
try {
byte[] bytes = getWorkspaceSynchronizer().getSyncInfo(RESOURCE_SYNC_KEY, resource);
if (bytes != null && resource.getType() == IResource.FILE) {
if (ResourceSyncInfo.isAddition(bytes)) {
// The local file has been deleted but was an addition
// Therefore, ignoe the sync bytes
bytes = null;
} else if (!ResourceSyncInfo.isDeletion(bytes)) {
// Ensure the bytes indicate an outgoing deletion
bytes = ResourceSyncInfo.convertToDeletion(bytes);
}
}
return bytes;
} catch (CoreException e) {
throw CVSException.wrapException(e);
}
}
/**
* @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#setCachedSyncBytes(org.eclipse.core.resources.IResource, byte[])
*/
void setCachedSyncBytes(IResource resource, byte[] syncBytes, boolean canModifyWorkspace) throws CVSException {
byte[] oldBytes = getCachedSyncBytes(resource);
try {
if (syncBytes == null) {
if (oldBytes != null && (resource.exists() || resource.isPhantom())) {
checkCanModifyWorkspace(resource, canModifyWorkspace);
getWorkspaceSynchronizer().flushSyncInfo(RESOURCE_SYNC_KEY, resource, IResource.DEPTH_ZERO);
}
} else {
// ensure that the sync info is not already set to the same thing.
// We do this to avoid causing a resource delta when the sync info is
// initially loaded (i.e. the synchronizer has it and so does the Entries file
// Ignore the
if (oldBytes == null
|| !Util.equals(
ResourceSyncInfo.convertToDeletion(syncBytes),
ResourceSyncInfo.convertToDeletion(oldBytes))) {
checkCanModifyWorkspace(resource, canModifyWorkspace);
getWorkspaceSynchronizer().setSyncInfo(RESOURCE_SYNC_KEY, resource, syncBytes);
}
}
} catch (CoreException e) {
throw CVSException.wrapException(e);
}
}
/*
* If we are not able to modify the workspace, throw an exception indicating this
* condition. The client requesting the cache should read the individual sync info
* directly.
*/
private void checkCanModifyWorkspace(IResource resource, boolean canModifyWorkspace) throws CVSException {
if (!canModifyWorkspace) {
throw new CVSException(IStatus.WARNING, CVSStatus.FAILED_TO_CACHE_SYNC_INFO, Policy.bind("SynchronizerSyncInfoCache.0", resource.getFullPath().toString())); //$NON-NLS-1$
}
}
/* (non-Javadoc)
* @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#getDirtyIndicator(org.eclipse.core.resources.IResource)
*/
String getDirtyIndicator(IResource resource) throws CVSException {
if (resource.getType() == IResource.FILE) {
// a phantom file is dirty if it was managed before it was deleted
return getCachedSyncBytes(resource) != null ?
IS_DIRTY_INDICATOR :
NOT_DIRTY_INDICATOR;
} else {
return calculateDirtyCountForPhantomFolder((IContainer)resource);
}
}
/* (non-Javadoc)
* @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#setDirtyIndicator(org.eclipse.core.resources.IResource, java.lang.String)
*/
void setDirtyIndicator(IResource resource, String indicator) throws CVSException {
// We don't cache the dirty count for folders because it would cause
// resource delta's in the decorator thread and possible deadlock.
}
/*package*/ void flushDirtyCache(IResource container) throws CVSException {
}
/*package*/ boolean isSyncInfoLoaded(IContainer parent) throws CVSException {
return true;
}
/**
* @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#isResourceSyncInfoCached(org.eclipse.core.resources.IContainer)
*/
boolean isResourceSyncInfoCached(IContainer container) throws CVSException {
// the sync info is always cahced when using the synchronizer
return true;
}
/**
* @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#setResourceSyncInfoCached(org.eclipse.core.resources.IContainer)
*/
void setResourceSyncInfoCached(IContainer container) throws CVSException {
// do nothing
}
/**
* @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#isFolderSyncInfoCached(org.eclipse.core.resources.IContainer)
*/
boolean isFolderSyncInfoCached(IContainer container) throws CVSException {
return true;
}
/* (non-Javadoc)
* @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#isDirtyCacheFlushed(org.eclipse.core.resources.IContainer)
*/
boolean isDirtyCacheFlushed(IContainer resource) throws CVSException {
return false;
}
/*
* Calculate the dirty count for the given phantom folder, performing any
* necessary calculations on the childen as well
*/
private String calculateDirtyCountForPhantomFolder(IContainer parent) throws CVSException {
ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(parent);
if(getCachedFolderSync(parent) == null) {
return NOT_DIRTY_INDICATOR;
}
String indicator = NOT_DIRTY_INDICATOR;
ICVSResource[] children = cvsFolder.members(ICVSFolder.MANAGED_MEMBERS | ICVSFolder.PHANTOM_MEMBERS);
for (int i = 0; i < children.length; i++) {
ICVSResource resource = children[i];
// keep looking into phantom folders until a managed phantom file
// is found.
if (resource.isFolder()) {
indicator = calculateDirtyCountForPhantomFolder((IContainer)resource.getIResource());
} else {
// Any non-existant managed files are dirty (outgoing deletion)
indicator = IS_DIRTY_INDICATOR;
break;
}
}
return indicator;
}
/**
* @param root
* @param deep
*/
public void purgeCache(IContainer root, boolean deep) throws CVSException {
int depth = deep ? IResource.DEPTH_INFINITE : IResource.DEPTH_ZERO;
try {
if (root.exists() || root.isPhantom()) {
getWorkspaceSynchronizer().flushSyncInfo(RESOURCE_SYNC_KEY, root, depth);
}
if (root.exists() || root.isPhantom()) {
getWorkspaceSynchronizer().flushSyncInfo(FOLDER_SYNC_KEY, root, depth);
}
} catch (CoreException e) {
throw CVSException.wrapException(e);
}
}
}