Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/target/SynchronizedTargetProvider.java')
-rw-r--r--bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/target/SynchronizedTargetProvider.java441
1 files changed, 441 insertions, 0 deletions
diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/target/SynchronizedTargetProvider.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/target/SynchronizedTargetProvider.java
new file mode 100644
index 000000000..4d2f1e80f
--- /dev/null
+++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/target/SynchronizedTargetProvider.java
@@ -0,0 +1,441 @@
+package org.eclipse.team.internal.core.target;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+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.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.team.core.*;
+import org.eclipse.team.internal.core.Policy;
+
+public abstract class SynchronizedTargetProvider extends TargetProvider {
+
+ /*
+ * Configuration serialization identifier.
+ */
+
+ private static final int CONFIG_FORMAT_VERSION = 2;
+
+ private final int depth = IResource.DEPTH_INFINITE;
+
+ /**
+ * These interfaces are to operations that can be performed on the array of resources,
+ * and on all resources identified by the depth parameter.
+ * @see execute(IOperation, IResource[], int, IProgressMonitor)
+ */
+ protected static interface IOperation {
+ }
+ protected static interface IIterativeOperation extends IOperation {
+ public IStatus visit(IResource resource, int depth, IProgressMonitor progress);
+ }
+ protected static interface IRecursiveOperation extends IOperation {
+ public IStatus visit(IResource resource, IProgressMonitor progress);
+ }
+
+ /**
+ * Create a new simple team provider initialized with the given state factory.
+ */
+ public SynchronizedTargetProvider() {
+ super();
+ }
+
+ /*************** State Factory ***************/
+
+ /**
+ * Answers the synchronizer.
+ */
+ final protected static ISynchronizer getSynchronizer() {
+ return ResourcesPlugin.getWorkspace().getSynchronizer();
+ }
+
+ /**
+ * Get the state descriptor for a given resource.
+ */
+ public ResourceState getState(IResource resource) {
+ // Create a new resource state with default values.
+ ResourceState state = newState(resource);
+ state.loadState();
+ return state;
+ }
+
+ /**
+ * Answers a new state based on an existing local resource.
+ */
+ abstract public ResourceState newState(IResource resource);
+
+ abstract public String getLocatorString(IResource resource);
+
+ /**
+ * Providers must override this method to configure instances based on the given
+ * properties map. Different providers will require different types of configuration,
+ * and therefore they will look for different keys in the properties table. If the provider
+ * cannot be configured with the values given a <code>TeamException</code> is
+ * thrown. Subclasses should override this method (and call <code>
+ * super.configureProvider(Properties)</code>).
+ */
+ abstract public void configure(Properties properties) throws TeamException;
+
+
+
+ /*************** Inherited Methods ***************/
+
+ /**
+ * Get the resource from the provider to the workspace, and remember the fetched
+ * state as the base state of the resource.
+ *
+ * @see ITeamProvider.get(IResource[], int, IProgressMonitor)
+ */
+ public void get(IResource[] resources, IProgressMonitor progress)
+ throws TeamException {
+ execute(new IIterativeOperation() {
+ public IStatus visit(IResource resource, int depth, IProgressMonitor progress) {
+ ResourceState state = getState(resource);
+ return new Symmetria().get(state, depth, progress);
+ }
+ }, resources, depth, progress);
+ }
+
+
+ /**
+ * Put the resources to the remote.
+ */
+ public void put(
+ IResource[] resources,
+ IProgressMonitor progress)
+ throws TeamException {
+
+ execute(new IRecursiveOperation() {
+ public IStatus visit(IResource resource, IProgressMonitor progress) {
+ // The resource state must be checked-out.
+ ResourceState state = getState(resource);
+ return state.checkin(progress);
+ }
+ }, resources, depth, progress);
+ }
+
+ /**
+ * Delete the corresponding remote resource.
+ * Note that deletes are always deep.
+ */
+ public void delete(IResource[] resources, IProgressMonitor progress)
+ throws TeamException {
+ execute(new IIterativeOperation() {
+ public IStatus visit(IResource resource, int depth, IProgressMonitor progress) {
+ ResourceState state = getState(resource);
+ return state.delete(progress);
+ }
+ }, resources, IResource.DEPTH_INFINITE, progress);
+ }
+
+ /**
+ * Answer if the local resource currently has a different timestamp to the
+ * base timestamp for this resource.
+ *
+ * @param resource the resource to test.
+ * @return <code>true</code> if the resource has a different modification
+ * timestamp, and <code>false</code> otherwise.
+ * @see ITeamSynch#isDirty(IResource)
+ */
+ public boolean isDirty(IResource resource) {
+ ResourceState state = getState(resource);
+ return state.isDirty(resource);
+ }
+
+ /**
+ * Answers true if the base identifier of the given resource is different to the
+ * current released state of the resource.
+ *
+ * @param resource the resource state to test.
+ * @return <code>true</code> if the resource base identifier is different to the
+ * current released state of the resource, and <code>false</code> otherwise.
+ * @see ITeamSynch#isOutOfDate(IResource)
+ */
+ public boolean isOutOfDate(IResource resource) {
+ ResourceState state = getState(resource);
+ return state.isOutOfDate();
+ }
+
+ /**
+ * Answer whether the resource has a corresponding remote resource in the provider.
+ *
+ * @param resource the resource state to test.
+ * @return <code>true</code> if the resource has a corresponding remote resource,
+ * and <code>false</code> otherwise.
+ * @see ITeamSynch#hasRemote(IResource)
+ */
+ public boolean hasRemote(IResource resource) {
+ ResourceState state = getState(resource);
+ return state.hasRemote();
+ }
+
+ /*
+ * @see ITeamProvider#refreshState(IResource[], int, IProgressMonitor)
+ */
+ public void refreshState(
+ IResource[] resources,
+ int depth,
+ IProgressMonitor progress)
+ throws TeamException {
+ }
+
+ public String getDecorationTextPostFix(IResource resource) {
+ return "";
+ }
+
+ public String getDecorationLocation(IResource resource) {
+ return getLocatorString(resource);
+ }
+
+
+ /**
+ * Perform the given operation on the array of resources, each to the
+ * specified depth. Throw an exception if a problem ocurs, otherwise
+ * remain silent.
+ */
+ protected void execute(
+ IOperation operation,
+ IResource[] resources,
+ int depth,
+ IProgressMonitor progress)
+ throws TeamException {
+
+ // Create an array to hold the status for each resource.
+ IStatus[] statuses = new IStatus[resources.length];
+
+ // Remember if a failure occurred in any resource, so we can throw an exception at the end.
+ boolean failureOccurred = false;
+
+ // For each resource in the local resources array.
+ for (int i = 0; i < resources.length; i++) {
+ if (operation instanceof IRecursiveOperation)
+ statuses[i] = execute((IRecursiveOperation)operation, resources[i], depth, progress);
+ else
+ statuses[i] = ((IIterativeOperation)operation).visit(resources[i], depth, progress);
+ failureOccurred = failureOccurred || (!statuses[i].isOK());
+ }
+
+ // Finally, if any problems occurred, throw the exeption with all the statuses,
+ // but if there were no problems exit silently.
+ if (failureOccurred)
+ throw new TeamException(
+ new MultiStatus(
+ TeamPlugin.ID,
+ IStatus.ERROR,
+ statuses,
+ Policy.bind("multiStatus.errorsOccurred"),
+ null));
+
+ // Cause all the resource changes to be broadcast to listeners.
+// TeamPlugin.getManager().broadcastResourceStateChanges(resources);
+ }
+
+ /**
+ * Perform the given operation on a resource to the given depth.
+ */
+ protected IStatus execute(
+ IRecursiveOperation operation,
+ IResource resource,
+ int depth,
+ IProgressMonitor progress) {
+
+ // Visit the given resource first.
+ IStatus status = operation.visit(resource, progress);
+
+ // If the resource is a file then the depth parameter is irrelevant.
+ if (resource.getType() == IResource.FILE)
+ return status;
+
+ // If we are not considering any members of the container then we are done.
+ if (depth == IResource.DEPTH_ZERO)
+ return status;
+
+ // If the operation was unsuccessful, do not attempt to go deep.
+ if (!status.isOK())
+ return status;
+
+ // If the container has no children then we are done.
+ IResource[] members = getMembers(resource);
+ if (members.length == 0)
+ return status;
+
+ // There are children and we are going deep, the response will be a multi-status.
+ MultiStatus multiStatus =
+ new MultiStatus(
+ status.getPlugin(),
+ status.getCode(),
+ status.getMessage(),
+ status.getException());
+
+ // The next level will be one less than the current level...
+ int childDepth =
+ (depth == IResource.DEPTH_ONE)
+ ? IResource.DEPTH_ZERO
+ : IResource.DEPTH_INFINITE;
+
+ // Collect the responses in the multistatus.
+ for (int i = 0; i < members.length; i++)
+ multiStatus.add(execute(operation, members[i], childDepth, progress));
+
+ return multiStatus;
+ }
+
+ /**
+ * Answers an array of local resource members for the given resource
+ * or an empty arrray if the resource has no members.
+ *
+ * @param resource the local resource whose members are required.
+ * @return an array of <code>IResource</code> or an empty array if
+ * the resource has no members.
+ */
+ protected IResource[] getMembers(IResource resource) {
+ if (resource.getType() != IResource.FILE) {
+ try {
+ return ((IContainer) resource).members();
+ } catch (CoreException exception) {
+ exception.printStackTrace();
+ throw new RuntimeException();
+ }
+ } //end-if
+ else
+ return new IResource[0];
+ }
+
+ /*
+ * @see IProjectNature#setProject()
+ */
+ public void setProject(IProject project) {
+ super.setProject(project);
+ try {
+ restoreConfiguration();
+ } catch (CoreException e) {
+ TeamPlugin.log(IStatus.ERROR, "Error configuring project", e);
+ } catch (IOException e) {
+ TeamPlugin.log(IStatus.ERROR, "Error configuring project", e);
+ }
+ }
+
+
+
+ /*************** Config Info Persisting ***************/
+
+ /*
+ * Retrieve configuration information for the receiver
+ * if previously configure, and reinstantiate that configuration.
+ */
+
+ public void restoreConfiguration() throws CoreException, IOException {
+ QualifiedName configKey = getIdentifier();
+ QualifiedName[] partners = getSynchronizer().getPartners();
+ boolean registered = false;
+
+ for (int i = 0; i < partners.length; i++) {
+ if(partners[i].equals(configKey))
+ registered = true;
+ }
+
+ if(registered) {
+ Properties properties = loadConfiguration();
+ if(properties == null) {
+ return;
+ }
+ storeConfiguration(properties);
+ }
+ }
+
+
+ /*
+ * This method is called once to configure the receiver after creation.
+ */
+ public void configure(Properties configuration, IProject project) throws IOException, CoreException, TeamException {
+ Assert.isNotNull(configuration);
+
+ setProject(project);
+
+ // Configure the receiver with the new config info.
+ configure(configuration);
+
+ // Store the new configuration for future.
+ storeConfiguration(configuration);
+ }
+
+ /*
+ * @see IProjectNature#deconfigure()
+ */
+ public void deconfigure() throws CoreException {
+ }
+
+ /**
+ * Associates the given configuration with the given project.
+ * Stores the configuration under the <code>getType()</code> key.
+ */
+ private void storeConfiguration(Properties configuration) throws IOException, CoreException {
+ // Remove any old configuration first.
+ QualifiedName configKey = getIdentifier();
+ getSynchronizer().flushSyncInfo(configKey, getProject(), IResource.DEPTH_INFINITE);
+
+ // Flatten the configuration to bytes.
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ byteStream.write(CONFIG_FORMAT_VERSION);
+ configuration.store(byteStream, null);
+ byteStream.close();
+ byte[] bytes = byteStream.toByteArray();
+
+ // Store the configuration persistently.
+ getSynchronizer().setSyncInfo(configKey, getProject(), bytes);
+ ResourcesPlugin.getWorkspace().save(false, null);
+ }
+
+
+ /**
+ * Loads a configuration serialized from a given project.
+ * Returns <code>null</code> if there is no serialized configuration or
+ * the configuration is invalid.
+ *
+ * @param project the project with an associated configuration.
+ * @return the loaded configuration, or <code>null</code> if there is
+ * no such configuration.
+ */
+ private Properties loadConfiguration() {
+ // The project must exist for us to get the configuration.
+ if (!getProject().exists())
+ return null;
+
+ try {
+ // Get the stored byte representation, if any.
+ QualifiedName configKey = getIdentifier();
+ byte[] bytes = getSynchronizer().getSyncInfo(configKey, getProject());
+ if ((bytes == null) || (bytes.length == 0))
+ return null;
+
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
+
+ // Check version identifier.
+ if (CONFIG_FORMAT_VERSION != inputStream.read())
+ return null;
+ // Read the properties from the stream.
+ Properties result = new Properties();
+ result.load(inputStream);
+ return result;
+ } catch (IOException e) {
+ return null;
+ } catch (CoreException e) {
+ e.printStackTrace();
+ throw new RuntimeException();
+ }
+ }
+
+
+ } \ No newline at end of file

Back to the top