Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Valenta2003-10-17 14:27:35 +0000
committerMichael Valenta2003-10-17 14:27:35 +0000
commit5e0750f3cb271c2f5a6d3211687899062757f130 (patch)
tree6096e5a9f78575b8cd8af209eb713178387c31ae
parent3e007070c9d866f3515029da805e5e597f256a22 (diff)
downloadeclipse.platform.team-5e0750f3cb271c2f5a6d3211687899062757f130.tar.gz
eclipse.platform.team-5e0750f3cb271c2f5a6d3211687899062757f130.tar.xz
eclipse.platform.team-5e0750f3cb271c2f5a6d3211687899062757f130.zip
45054: ConcurrentModificationException duing two checkouts
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java184
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java5
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSWorkspaceSubscriber.java3
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java9
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FileModificationManager.java3
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/KnownRepositories.java232
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceStateChangeListeners.java128
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java3
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/RepositoryProviderOperation.java1
-rw-r--r--tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/IsModifiedTests.java6
10 files changed, 403 insertions, 171 deletions
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java
index 0fb4c5c68..0ae33a9c2 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java
@@ -17,16 +17,11 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Properties;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
@@ -54,6 +49,7 @@ import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.core.resources.FileModificationManager;
import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
import org.eclipse.team.internal.ccvs.core.util.BuildCleanupListener;
+import org.eclipse.team.internal.ccvs.core.util.KnownRepositories;
import org.eclipse.team.internal.ccvs.core.util.SyncFileChangeListener;
import org.eclipse.team.internal.ccvs.core.util.Util;
@@ -116,8 +112,6 @@ public class CVSProviderPlugin extends Plugin {
private static final String REPOSITORIES_STATE_FILE = ".cvsProviderState"; //$NON-NLS-1$
// version numbers for the state file (a positive number indicates version 1)
private static final int REPOSITORIES_STATE_FILE_VERSION_2 = -1;
- private Map repositories = new HashMap();
- private List repositoryListeners = new ArrayList();
private static List decoratorEnablementListeners = new ArrayList();
private CVSWorkspaceSubscriber cvsWorkspaceSubscriber;
@@ -448,101 +442,16 @@ public class CVSProviderPlugin extends Plugin {
promptOnFolderDelete = prompt;
}
- private static List listeners = new ArrayList();
-
- /*
- * @see ITeamManager#addResourceStateChangeListener(IResourceStateChangeListener)
- */
- public static void addResourceStateChangeListener(IResourceStateChangeListener listener) {
- listeners.add(listener);
- }
-
- /*
- * @see ITeamManager#removeResourceStateChangeListener(IResourceStateChangeListener)
- */
- public static void removeResourceStateChangeListener(IResourceStateChangeListener listener) {
- listeners.remove(listener);
- }
-
- public static void broadcastSyncInfoChanges(final IResource[] resources) {
- for(Iterator it=listeners.iterator(); it.hasNext();) {
- final IResourceStateChangeListener listener = (IResourceStateChangeListener)it.next();
- ISafeRunnable code = new ISafeRunnable() {
- public void run() throws Exception {
- listener.resourceSyncInfoChanged(resources);
- }
- public void handleException(Throwable e) {
- // don't log the exception....it is already being logged in Platform#run
- }
- };
- Platform.run(code);
- }
- }
-
- public static void broadcastExternalSyncInfoChanges(final IResource[] resources) {
- for(Iterator it=listeners.iterator(); it.hasNext();) {
- final IResourceStateChangeListener listener = (IResourceStateChangeListener)it.next();
- ISafeRunnable code = new ISafeRunnable() {
- public void run() throws Exception {
- listener.externalSyncInfoChange(resources);
- }
- public void handleException(Throwable e) {
- // don't log the exception....it is already being logged in Platform#run
- }
- };
- Platform.run(code);
- }
- }
-
public static void broadcastDecoratorEnablementChanged(final boolean enabled) {
- for(Iterator it=decoratorEnablementListeners.iterator(); it.hasNext();) {
- final ICVSDecoratorEnablementListener listener = (ICVSDecoratorEnablementListener)it.next();
- ISafeRunnable code = new ISafeRunnable() {
- public void run() throws Exception {
- listener.decoratorEnablementChanged(enabled);
- }
- public void handleException(Throwable e) {
- // don't log the exception....it is already being logged in Platform#run
- }
- };
- Platform.run(code);
- }
- }
-
- public static void broadcastModificationStateChanges(final IResource[] resources) {
- for(Iterator it=listeners.iterator(); it.hasNext();) {
- final IResourceStateChangeListener listener = (IResourceStateChangeListener)it.next();
- ISafeRunnable code = new ISafeRunnable() {
- public void run() throws Exception {
- listener.resourceModified(resources);
- }
- public void handleException(Throwable e) {
- // don't log the exception....it is already being logged in Platform#run
- }
- };
- Platform.run(code);
+ ICVSDecoratorEnablementListener[] listeners;
+ synchronized(decoratorEnablementListeners) {
+ listeners = (ICVSDecoratorEnablementListener[]) decoratorEnablementListeners.toArray(new ICVSDecoratorEnablementListener[decoratorEnablementListeners.size()]);
}
- }
- protected static void broadcastProjectConfigured(final IProject project) {
- for(Iterator it=listeners.iterator(); it.hasNext();) {
- final IResourceStateChangeListener listener = (IResourceStateChangeListener)it.next();
+ for (int i = 0; i < listeners.length; i++) {
+ final ICVSDecoratorEnablementListener listener = listeners[i];
ISafeRunnable code = new ISafeRunnable() {
public void run() throws Exception {
- listener.projectConfigured(project);
- }
- public void handleException(Throwable e) {
- // don't log the exception....it is already being logged in Platform#run
- }
- };
- Platform.run(code);
- }
- }
- protected static void broadcastProjectDeconfigured(final IProject project) {
- for(Iterator it=listeners.iterator(); it.hasNext();) {
- final IResourceStateChangeListener listener = (IResourceStateChangeListener)it.next();
- ISafeRunnable code = new ISafeRunnable() {
- public void run() throws Exception {
- listener.projectDeconfigured(project);
+ listener.decoratorEnablementChanged(enabled);
}
public void handleException(Throwable e) {
// don't log the exception....it is already being logged in Platform#run
@@ -567,34 +476,13 @@ public class CVSProviderPlugin extends Plugin {
public void setReplaceUnmanaged(boolean replaceUnmanaged) {
this.replaceUnmanaged = replaceUnmanaged;
}
-
- /*
- * Add the repository location to the cahced locations
- */
- private void addToRepositoriesCache(ICVSRepositoryLocation repository) {
- repositories.put(repository.getLocation(), repository);
- Iterator it = repositoryListeners.iterator();
- while (it.hasNext()) {
- ICVSListener listener = (ICVSListener)it.next();
- listener.repositoryAdded(repository);
- }
- }
-
- private void removeFromRepositoriesCache(ICVSRepositoryLocation repository) {
- if (repositories.remove(repository.getLocation()) != null) {
- Iterator it = repositoryListeners.iterator();
- while (it.hasNext()) {
- ICVSListener listener = (ICVSListener)it.next();
- listener.repositoryRemoved(repository);
- }
- }
- }
+
/**
* Register to receive notification of repository creation and disposal
*/
public void addRepositoryListener(ICVSListener listener) {
- repositoryListeners.add(listener);
+ KnownRepositories.getInstance().addRepositoryListener(listener);
}
/**
@@ -603,21 +491,25 @@ public class CVSProviderPlugin extends Plugin {
* resource with CVS information.
*/
public void addDecoratorEnablementListener(ICVSDecoratorEnablementListener listener) {
- decoratorEnablementListeners.add(listener);
+ synchronized(decoratorEnablementListeners) {
+ decoratorEnablementListeners.add(listener);
+ }
}
/**
* De-register a listener
*/
public void removeRepositoryListener(ICVSListener listener) {
- repositoryListeners.remove(listener);
+ KnownRepositories.getInstance().removeRepositoryListener(listener);
}
/**
* De-register the decorator enablement listener.
*/
public void removeDecoratorEnablementListener(ICVSDecoratorEnablementListener listener) {
- decoratorEnablementListeners.remove(listener);
+ synchronized(decoratorEnablementListeners) {
+ decoratorEnablementListeners.remove(listener);
+ }
}
/**
@@ -639,16 +531,7 @@ public class CVSProviderPlugin extends Plugin {
* exists.
*/
public ICVSRepositoryLocation createRepository(Properties configuration) throws CVSException {
- // Create a new repository location
- CVSRepositoryLocation location = CVSRepositoryLocation.fromProperties(configuration);
-
- // Check the cache for an equivalent instance and if there is one, throw an exception
- CVSRepositoryLocation existingLocation = (CVSRepositoryLocation)repositories.get(location.getLocation());
- if (existingLocation != null) {
- throw new CVSException(new CVSStatus(CVSStatus.ERROR, Policy.bind("CVSProvider.alreadyExists"))); //$NON-NLS-1$
- }
-
- return location;
+ return KnownRepositories.getInstance().createRepository(configuration);
}
/**
@@ -656,15 +539,7 @@ public class CVSProviderPlugin extends Plugin {
* password caching accross platform invokations.
*/
public void addRepository(ICVSRepositoryLocation repository) throws CVSException {
- // Check the cache for an equivalent instance and if there is one, just update the cache
- CVSRepositoryLocation existingLocation = (CVSRepositoryLocation)repositories.get(repository.getLocation());
- if (existingLocation != null) {
- ((CVSRepositoryLocation)repository).updateCache();
- } else {
- // Cache the password and register the repository location
- addToRepositoriesCache(repository);
- ((CVSRepositoryLocation)repository).updateCache();
- }
+ KnownRepositories.getInstance().addRepository(repository);
saveState();
}
@@ -674,8 +549,7 @@ public class CVSProviderPlugin extends Plugin {
* Removes any cached information about the repository such as a remembered password.
*/
public void disposeRepository(ICVSRepositoryLocation repository) throws CVSException {
- ((CVSRepositoryLocation)repository).dispose();
- removeFromRepositoriesCache(repository);
+ KnownRepositories.getInstance().disposeRepository(repository);
}
/**
@@ -683,14 +557,14 @@ public class CVSProviderPlugin extends Plugin {
* The location string corresponds to the Strin returned by ICVSRepositoryLocation#getLocation()
*/
public boolean isKnownRepository(String location) {
- return repositories.get(location) != null;
+ return KnownRepositories.getInstance().isKnownRepository(location);
}
/**
* Return a list of the know repository locations
*/
public ICVSRepositoryLocation[] getKnownRepositories() {
- return (ICVSRepositoryLocation[])repositories.values().toArray(new ICVSRepositoryLocation[repositories.size()]);
+ return KnownRepositories.getInstance().getKnownRepositories();
}
/**
@@ -717,12 +591,7 @@ public class CVSProviderPlugin extends Plugin {
* of the location permanently. This means that it cannot be modified by the authenticator.
*/
public ICVSRepositoryLocation getRepository(String location) throws CVSException {
- ICVSRepositoryLocation repository = (ICVSRepositoryLocation)repositories.get(location);
- if (repository == null) {
- repository = CVSRepositoryLocation.fromString(location);
- addToRepositoriesCache(repository);
- }
- return repository;
+ return KnownRepositories.getInstance().getRepository(location);
}
private void loadState() {
@@ -805,11 +674,10 @@ public class CVSProviderPlugin extends Plugin {
// Write the repositories
dos.writeInt(REPOSITORIES_STATE_FILE_VERSION_2);
// Write out the repos
- Collection repos = repositories.values();
- dos.writeInt(repos.size());
- Iterator it = repos.iterator();
- while (it.hasNext()) {
- CVSRepositoryLocation root = (CVSRepositoryLocation)it.next();
+ ICVSRepositoryLocation[] repos = KnownRepositories.getInstance().getKnownRepositories();
+ dos.writeInt(repos.length);
+ for (int i = 0; i < repos.length; i++) {
+ CVSRepositoryLocation root = (CVSRepositoryLocation)repos[i];
dos.writeUTF(root.getLocation());
dos.writeUTF("unused"); // place holder for an additional configuration parameter //$NON-NLS-1$
}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java
index 3f83af788..e8188540f 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java
@@ -76,6 +76,7 @@ import org.eclipse.team.internal.ccvs.core.util.Assert;
import org.eclipse.team.internal.ccvs.core.util.MoveDeleteHook;
import org.eclipse.team.internal.ccvs.core.util.PrepareForReplaceVisitor;
import org.eclipse.team.internal.ccvs.core.util.ReplaceWithBaseVisitor;
+import org.eclipse.team.internal.ccvs.core.util.ResourceStateChangeListeners;
import org.eclipse.team.internal.ccvs.core.util.SyncFileWriter;
import org.eclipse.team.internal.core.streams.CRLFtoLFInputStream;
import org.eclipse.team.internal.core.streams.LFtoCRLFInputStream;
@@ -174,7 +175,7 @@ public class CVSTeamProvider extends RepositoryProvider {
}
public void deconfigured() {
- CVSProviderPlugin.broadcastProjectDeconfigured(getProject());
+ ResourceStateChangeListeners.getListener().projectDeconfigured(getProject());
}
/**
* @see IProjectNature#getProject()
@@ -1030,7 +1031,7 @@ public class CVSTeamProvider extends RepositoryProvider {
}
public void configureProject() throws CoreException {
- CVSProviderPlugin.broadcastProjectConfigured(getProject());
+ ResourceStateChangeListeners.getListener().projectConfigured(getProject());
}
/**
* Sets the keyword substitution mode for the specified resources.
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSWorkspaceSubscriber.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSWorkspaceSubscriber.java
index 51767a0d7..f73c23bbf 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSWorkspaceSubscriber.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSWorkspaceSubscriber.java
@@ -29,6 +29,7 @@ import org.eclipse.team.core.subscribers.SyncInfo;
import org.eclipse.team.core.subscribers.TeamDelta;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.core.syncinfo.OptimizedRemoteSynchronizer;
+import org.eclipse.team.internal.ccvs.core.util.ResourceStateChangeListeners;
/**
* CVSWorkspaceSubscriber
@@ -47,7 +48,7 @@ public class CVSWorkspaceSubscriber extends CVSSyncTreeSubscriber implements IRe
remoteSynchronizer = new OptimizedRemoteSynchronizer(REMOTE_RESOURCE_KEY);
// TODO: temporary proxy for CVS events
- CVSProviderPlugin.addResourceStateChangeListener(this);
+ ResourceStateChangeListeners.getListener().addResourceStateChangeListener(this);
}
/*
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java
index 32373d967..58fc4d91b 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java
@@ -53,6 +53,7 @@ import org.eclipse.team.internal.ccvs.core.syncinfo.ReentrantLock.IFlushOperatio
import org.eclipse.team.internal.ccvs.core.syncinfo.ReentrantLock.ThreadInfo;
import org.eclipse.team.internal.ccvs.core.util.Assert;
import org.eclipse.team.internal.ccvs.core.util.FileNameMatcher;
+import org.eclipse.team.internal.ccvs.core.util.ResourceStateChangeListeners;
import org.eclipse.team.internal.ccvs.core.util.SyncFileWriter;
/**
@@ -426,7 +427,7 @@ public class EclipseSynchronizer implements IFlushOperation {
// broadcast changes to unmanaged children - they are the only candidates for being ignored
List possibleIgnores = new ArrayList();
accumulateNonManagedChildren(folder, possibleIgnores);
- CVSProviderPlugin.broadcastSyncInfoChanges((IResource[])possibleIgnores.toArray(new IResource[possibleIgnores.size()]));
+ ResourceStateChangeListeners.getListener().resourceSyncInfoChanged((IResource[])possibleIgnores.toArray(new IResource[possibleIgnores.size()]));
} finally {
endOperation();
}
@@ -618,7 +619,7 @@ public class EclipseSynchronizer implements IFlushOperation {
endOperation();
}
if (!changed.isEmpty()) {
- CVSProviderPlugin.broadcastSyncInfoChanges(
+ ResourceStateChangeListeners.getListener().resourceSyncInfoChanged(
(IResource[]) changed.toArray(new IResource[changed.size()]));
}
} finally {
@@ -643,7 +644,7 @@ public class EclipseSynchronizer implements IFlushOperation {
changed.add(file);
}
}
- CVSProviderPlugin.broadcastExternalSyncInfoChanges(
+ ResourceStateChangeListeners.getListener().externalSyncInfoChange(
(IResource[]) changed.toArray(new IResource[changed.size()]));
}
@@ -981,7 +982,7 @@ public class EclipseSynchronizer implements IFlushOperation {
*/
void broadcastResourceStateChanges(IResource[] resources) {
if (resources.length > 0) {
- CVSProviderPlugin.broadcastSyncInfoChanges(resources);
+ ResourceStateChangeListeners.getListener().resourceSyncInfoChanged(resources);
}
}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FileModificationManager.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FileModificationManager.java
index 1250c5b25..ad71ba405 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FileModificationManager.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FileModificationManager.java
@@ -31,6 +31,7 @@ import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.internal.ccvs.core.ICVSFile;
+import org.eclipse.team.internal.ccvs.core.util.ResourceStateChangeListeners;
/**
* This class performs several functions related to determining the modified
@@ -98,7 +99,7 @@ public class FileModificationManager implements IResourceChangeListener, ISavePa
}
});
if (!modifiedResources.isEmpty()) {
- CVSProviderPlugin.broadcastModificationStateChanges(
+ ResourceStateChangeListeners.getListener().resourceModified(
(IResource[])modifiedResources.toArray(new IResource[modifiedResources.size()]));
modifiedResources.clear();
}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/KnownRepositories.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/KnownRepositories.java
new file mode 100644
index 000000000..818a7ec60
--- /dev/null
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/KnownRepositories.java
@@ -0,0 +1,232 @@
+/*******************************************************************************
+ * 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.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.team.internal.ccvs.core.CVSException;
+import org.eclipse.team.internal.ccvs.core.CVSStatus;
+import org.eclipse.team.internal.ccvs.core.ICVSListener;
+import org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation;
+import org.eclipse.team.internal.ccvs.core.Policy;
+import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation;
+
+/**
+ * This class keeps track of the CVS repository locations that are known to
+ * the CVS plugin.
+ */
+public class KnownRepositories {
+
+ private List repositoryListeners = new ArrayList();
+ private Map repositories = new HashMap();
+
+ private static KnownRepositories instance;
+
+ public static synchronized KnownRepositories getInstance() {
+ if (instance == null) {
+ instance = new KnownRepositories();
+ }
+ return instance;
+ }
+
+ /*
+ * Private class used to safely notify listeners of resouce sync info changes.
+ * Subclass override the notify(IResourceStateChangeListener) method to
+ * fire specific events inside an ISafeRunnable.
+ */
+ private abstract class Notification implements ISafeRunnable {
+ private ICVSListener listener;
+ public void handleException(Throwable exception) {
+ // don't log the exception....it is already being logged in Platform#run
+ }
+ public void run(ICVSListener listener) {
+ this.listener = listener;
+ Platform.run(this);
+ }
+ public void run() throws Exception {
+ notify(listener);
+ }
+ /**
+ * Subsclasses overide this method to send an event safely to a lsistener
+ * @param listener
+ */
+ protected abstract void notify(ICVSListener listener);
+ }
+
+ /**
+ * Register to receive notification of repository creation and disposal
+ */
+ public void addRepositoryListener(ICVSListener listener) {
+ synchronized(repositoryListeners) {
+ repositoryListeners.add(listener);
+ }
+ }
+
+ /**
+ * De-register a listener
+ */
+ public void removeRepositoryListener(ICVSListener listener) {
+ synchronized(repositoryListeners) {
+ repositoryListeners.remove(listener);
+ }
+ }
+
+ private ICVSListener[] getListeners() {
+ synchronized(repositoryListeners) {
+ return (ICVSListener[]) repositoryListeners.toArray(new ICVSListener[repositoryListeners.size()]);
+ }
+ }
+
+ private void fireNotification(Notification notification) {
+ // Get a snapshot of the listeners so the list doesn't change while we're firing
+ ICVSListener[] listeners = getListeners();
+ // Notify each listener in a safe manner (i.e. so their exceptions don't kill us)
+ for (int i = 0; i < listeners.length; i++) {
+ ICVSListener listener = listeners[i];
+ notification.run(listener);
+ }
+ }
+
+ /*
+ * Add the repository location to the cached locations and notify listeners
+ */
+ private void addToRepositoriesCache(final ICVSRepositoryLocation repository) {
+ repositories.put(repository.getLocation(), repository);
+ fireNotification(new Notification() {
+ public void notify(ICVSListener listener) {
+ listener.repositoryAdded(repository);
+ }
+ });
+ }
+
+ /*
+ * Remove the repository location from the cached locations and notify listeners
+ */
+ private void removeFromRepositoriesCache(final ICVSRepositoryLocation repository) {
+ if (repositories.remove(repository.getLocation()) != null) {
+ fireNotification(new Notification() {
+ public void notify(ICVSListener listener) {
+ listener.repositoryRemoved(repository);
+ }
+ });
+ }
+ }
+
+ /**
+ * Create a repository instance from the given properties.
+ * The supported properties are:
+ *
+ * connection The connection method to be used
+ * user The username for the connection
+ * password The password used for the connection (optional)
+ * host The host where the repository resides
+ * port The port to connect to (optional)
+ * root The server directory where the repository is located
+ *
+ * The created instance is not known by the provider and it's user information is not cached.
+ * The purpose of the created location is to allow connection validation before adding the
+ * location to the provider.
+ *
+ * This method will throw a CVSException if the location for the given configuration already
+ * exists.
+ */
+ public ICVSRepositoryLocation createRepository(Properties configuration) throws CVSException {
+ // Create a new repository location
+ CVSRepositoryLocation location = CVSRepositoryLocation.fromProperties(configuration);
+
+ // Check the cache for an equivalent instance and if there is one, throw an exception
+ CVSRepositoryLocation existingLocation = (CVSRepositoryLocation)repositories.get(location.getLocation());
+ if (existingLocation != null) {
+ throw new CVSException(new CVSStatus(CVSStatus.ERROR, Policy.bind("CVSProvider.alreadyExists"))); //$NON-NLS-1$
+ }
+
+ return location;
+ }
+
+ /**
+ * Add the repository to the receiver's list of known repositories. Doing this will enable
+ * password caching accross platform invokations.
+ */
+ public void addRepository(ICVSRepositoryLocation repository) throws CVSException {
+ // Check the cache for an equivalent instance and if there is one, just update the cache
+ CVSRepositoryLocation existingLocation = (CVSRepositoryLocation)repositories.get(repository.getLocation());
+ if (existingLocation != null) {
+ ((CVSRepositoryLocation)repository).updateCache();
+ } else {
+ // Cache the password and register the repository location
+ addToRepositoriesCache(repository);
+ ((CVSRepositoryLocation)repository).updateCache();
+ }
+ }
+
+ /**
+ * Dispose of the repository location
+ *
+ * Removes any cached information about the repository such as a remembered password.
+ */
+ public void disposeRepository(ICVSRepositoryLocation repository) throws CVSException {
+ ((CVSRepositoryLocation)repository).dispose();
+ removeFromRepositoriesCache(repository);
+ }
+
+ /**
+ * Answer whether the provided repository location is known by the provider or not.
+ * The location string corresponds to the Strin returned by ICVSRepositoryLocation#getLocation()
+ */
+ public boolean isKnownRepository(String location) {
+ return repositories.get(location) != null;
+ }
+
+ /**
+ * Return a list of the know repository locations
+ */
+ public ICVSRepositoryLocation[] getKnownRepositories() {
+ return (ICVSRepositoryLocation[])repositories.values().toArray(new ICVSRepositoryLocation[repositories.size()]);
+ }
+
+ /**
+ * Get the repository instance which matches the given String. The format of the String is
+ * the same as that returned by ICVSRepositoryLocation#getLocation().
+ * The format is:
+ *
+ * connection:user[:password]@host[#port]:root
+ *
+ * where [] indicates optional and the identier meanings are:
+ *
+ * connection The connection method to be used
+ * user The username for the connection
+ * password The password used for the connection (optional)
+ * host The host where the repository resides
+ * port The port to connect to (optional)
+ * root The server directory where the repository is located
+ *
+ * It is expected that the instance requested by using this method exists.
+ * If the repository location does not exist, it will be automatically created
+ * and cached with the provider.
+ *
+ * WARNING: Providing the password as part of the String will result in the password being part
+ * of the location permanently. This means that it cannot be modified by the authenticator.
+ */
+ public ICVSRepositoryLocation getRepository(String location) throws CVSException {
+ ICVSRepositoryLocation repository = (ICVSRepositoryLocation)repositories.get(location);
+ if (repository == null) {
+ repository = CVSRepositoryLocation.fromString(location);
+ addToRepositoriesCache(repository);
+ }
+ return repository;
+ }
+}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceStateChangeListeners.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceStateChangeListeners.java
new file mode 100644
index 000000000..f82af1cad
--- /dev/null
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceStateChangeListeners.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * 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.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.team.internal.ccvs.core.IResourceStateChangeListener;
+
+/**
+ * Class that manages the listeners of CVS sync change notification
+ */
+public class ResourceStateChangeListeners {
+
+ private static List listeners = new ArrayList();
+
+ private static ResourceStateChangeListeners instance;
+
+ public static synchronized ResourceStateChangeListeners getListener() {
+ if (instance == null) {
+ instance = new ResourceStateChangeListeners();
+ }
+ return instance;
+ }
+
+ /*
+ * Private class used to safely notify listeners of resouce sync info changes.
+ * Subclass override the notify(IResourceStateChangeListener) method to
+ * fire specific events inside an ISafeRunnable.
+ */
+ private abstract class Notification implements ISafeRunnable {
+ private IResourceStateChangeListener listener;
+ public void handleException(Throwable exception) {
+ // don't log the exception....it is already being logged in Platform#run
+ }
+ public void run(IResourceStateChangeListener listener) {
+ this.listener = listener;
+ Platform.run(this);
+ }
+ public void run() throws Exception {
+ notify(listener);
+ }
+ /**
+ * Subsclasses overide this method to send an event safely to a lsistener
+ * @param listener
+ */
+ protected abstract void notify(IResourceStateChangeListener listener);
+ }
+
+ private IResourceStateChangeListener[] getListeners() {
+ synchronized(listeners) {
+ return (IResourceStateChangeListener[]) listeners.toArray(new IResourceStateChangeListener[listeners.size()]);
+ }
+ }
+
+ private void fireNotification(Notification notification) {
+ // Get a snapshot of the listeners so the list doesn't change while we're firing
+ IResourceStateChangeListener[] listeners = getListeners();
+ // Notify each listener in a safe manner (i.e. so their exceptions don't kill us)
+ for (int i = 0; i < listeners.length; i++) {
+ IResourceStateChangeListener listener = listeners[i];
+ notification.run(listener);
+ }
+ }
+
+ public void addResourceStateChangeListener(IResourceStateChangeListener listener) {
+ synchronized(listeners) {
+ listeners.add(listener);
+ }
+ }
+
+ public void removeResourceStateChangeListener(IResourceStateChangeListener listener) {
+ synchronized(listeners) {
+ listeners.remove(listener);
+ }
+ }
+
+ public void resourceSyncInfoChanged(final IResource[] resources) {
+ fireNotification(new Notification() {
+ public void notify(IResourceStateChangeListener listener) {
+ listener.resourceSyncInfoChanged(resources);
+ }
+ });
+ }
+
+ public void externalSyncInfoChange(final IResource[] resources) {
+ fireNotification(new Notification() {
+ public void notify(IResourceStateChangeListener listener) {
+ listener.externalSyncInfoChange(resources);
+ }
+ });
+ }
+
+ public void resourceModified(final IResource[] resources) {
+ fireNotification(new Notification() {
+ public void notify(IResourceStateChangeListener listener) {
+ listener.resourceModified(resources);
+ }
+ });
+ }
+ public void projectConfigured(final IProject project) {
+ fireNotification(new Notification() {
+ public void notify(IResourceStateChangeListener listener) {
+ listener.projectConfigured(project);
+ }
+ });
+ }
+ public void projectDeconfigured(final IProject project) {
+ fireNotification(new Notification() {
+ public void notify(IResourceStateChangeListener listener) {
+ listener.projectDeconfigured(project);
+ }
+ });
+ }
+
+}
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java
index 74508cfe1..29ba7d1ab 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java
@@ -46,6 +46,7 @@ import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
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.ResourceStateChangeListeners;
import org.eclipse.team.internal.core.ExceptionCollector;
import org.eclipse.team.internal.ui.TeamUIPlugin;
import org.eclipse.team.ui.ISharedImages;
@@ -93,7 +94,7 @@ public class CVSLightweightDecorator
}
public CVSLightweightDecorator() {
- CVSProviderPlugin.addResourceStateChangeListener(this);
+ ResourceStateChangeListeners.getListener().addResourceStateChangeListener(this);
CVSProviderPlugin.broadcastDecoratorEnablementChanged(true /* enabled */);
exceptions = new ExceptionCollector(Policy.bind("CVSDecorator.exceptionMessage"), CVSUIPlugin.ID, IStatus.ERROR, CVSUIPlugin.getPlugin().getLog()); //$NON-NLS-1$
}
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/RepositoryProviderOperation.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/RepositoryProviderOperation.java
index 5b8f0715b..c4bcf15e1 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/RepositoryProviderOperation.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/operations/RepositoryProviderOperation.java
@@ -62,7 +62,6 @@ public abstract class RepositoryProviderOperation extends CVSOperation {
IResource[] providerResources = (IResource[])list.toArray(new IResource[list.size()]);
execute(provider, providerResources, subMonitor);
}
-
}
/*
diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/IsModifiedTests.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/IsModifiedTests.java
index f5c70779c..ca5382f2e 100644
--- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/IsModifiedTests.java
+++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/IsModifiedTests.java
@@ -31,7 +31,6 @@ import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.internal.ccvs.core.CVSException;
-import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.internal.ccvs.core.ICVSFile;
import org.eclipse.team.internal.ccvs.core.ICVSFolder;
import org.eclipse.team.internal.ccvs.core.ICVSResource;
@@ -40,6 +39,7 @@ import org.eclipse.team.internal.ccvs.core.IResourceStateChangeListener;
import org.eclipse.team.internal.ccvs.core.client.Command;
import org.eclipse.team.internal.ccvs.core.client.Update;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
+import org.eclipse.team.internal.ccvs.core.util.ResourceStateChangeListeners;
import org.eclipse.team.tests.ccvs.core.CVSTestSetup;
import org.eclipse.team.tests.ccvs.core.EclipseTest;
@@ -144,7 +144,7 @@ public class IsModifiedTests extends EclipseTest {
super.setUp();
previouslyModified.clear();
changedResources.clear();
- CVSProviderPlugin.addResourceStateChangeListener(listener);
+ ResourceStateChangeListeners.getListener().addResourceStateChangeListener(listener);
}
/**
@@ -153,7 +153,7 @@ public class IsModifiedTests extends EclipseTest {
protected void tearDown() throws Exception {
previouslyModified.clear();
changedResources.clear();
- CVSProviderPlugin.removeResourceStateChangeListener(listener);
+ ResourceStateChangeListeners.getListener().removeResourceStateChangeListener(listener);
super.tearDown();
}

Back to the top