Adding support for persistant properties
diff --git a/bundles/org.eclipse.team.core/plugin.properties b/bundles/org.eclipse.team.core/plugin.properties
index 30766f0..539fdfd 100644
--- a/bundles/org.eclipse.team.core/plugin.properties
+++ b/bundles/org.eclipse.team.core/plugin.properties
@@ -3,4 +3,5 @@
 FileTypesRegistry=File Types Registry
 GlobalIgnoreRegistry=Global Ignore Registry
 TeamProjectSets=Team Project Sets
-Targets=Target Provider and Location Factories
\ No newline at end of file
+Targets=Target Provider and Location Factories
+Repository=Repository Provider Factories
\ No newline at end of file
diff --git a/bundles/org.eclipse.team.core/plugin.xml b/bundles/org.eclipse.team.core/plugin.xml
index 194ebe0..f8fa850 100644
--- a/bundles/org.eclipse.team.core/plugin.xml
+++ b/bundles/org.eclipse.team.core/plugin.xml
@@ -20,6 +20,7 @@
 <extension-point id="fileTypes" name="%FileTypesRegistry"/>
 <extension-point id="ignore" name="%GlobalIgnoreRegistry"/>
 <extension-point id="projectSets" name="%TeamProjectSets"/>
+<extension-point id="repository" name="%Repository"/>
 <extension-point id="targets" name="%Targets"/>
 
 <!-- Define common known file types -->
diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/RepositoryProvider.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/RepositoryProvider.java
index f8ec745..509d698 100644
--- a/bundles/org.eclipse.team.core/src/org/eclipse/team/core/RepositoryProvider.java
+++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/core/RepositoryProvider.java
@@ -22,7 +22,12 @@
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.resources.team.IMoveDeleteHook;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
 import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.QualifiedName;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.team.internal.core.*;
 import org.eclipse.team.internal.core.Policy;
@@ -66,16 +71,118 @@
 	
 	private final static String TEAM_SETID = "org.eclipse.team.repository-provider"; //$NON-NLS-1$
 	
+	private final static QualifiedName PROVIDER_PROP_KEY = 
+		new QualifiedName("org.eclipse.team.core", "repository");  //$NON-NLS-1$  //$NON-NLS-2$
+
+	private final static List AllProviderTypeIds = initializeAllProviderTypes();
+	
 	// the project instance that this nature is assigned to
 	private IProject project;	
 	
 	/**
+	 * Instantiate a new RepositoryProvider with concrete class by given providerID
+	 * and associate it with project.
+	 * @throws TeamException
+	 * <ul>
+	 * <li>There is no provider by that ID.</li>
+	 * <li>The project is already associated with a repository provider.</li>
+	 * </ul>
+	 * @see unmap(IProject)
+	 */
+	public static void map(IProject project, String id) throws TeamException {
+		try {
+			RepositoryProvider existingProvider = null;
+
+			if(project.getPersistentProperty(PROVIDER_PROP_KEY) != null)
+				existingProvider = getProvider(project);	// get the real one, not the nature one
+			
+			//if we already have a provider, and its the same ID, we're ok
+			//if the ID's differ, unmap the existing.
+			if(existingProvider != null) {
+				if(existingProvider.getID().equals(id))
+					return;	//nothing to do
+				else
+					unmap(project);
+			}
+			
+			RepositoryProvider provider = mapNewProvider(project, id);
+			project.setPersistentProperty(PROVIDER_PROP_KEY, id);
+			
+			try {	
+				provider.configureProject();	//xxx not sure if needed since they control with wiz page and can configure all they want
+			} catch (CoreException e) {
+				project.setPersistentProperty(PROVIDER_PROP_KEY, null);
+				throw e;
+			}
+			//and mark it with the persistent ID for filtering and session persistence
+		} catch (CoreException e) {
+			throw TeamPlugin.wrapException(e);
+		}
+	}	
+
+	/*
+	 * Instantiate the provider denoted by ID and store it in the session property.
+	 * Return the new provider instance.
+	 * @throws TeamException if the we can't instantiate the provider,
+	 * or if the set session property fails from core
+	 */
+	private static RepositoryProvider mapNewProvider(IProject project, String id) throws TeamException {
+		RepositoryProvider provider = newProvider(id); 	// instantiate via extension point
+
+		if(provider == null)
+			throw new TeamException(Policy.bind("RepositoryProvider.couldNotInstantiateProvider", project.getName(), id));
+			
+		provider.setProject(project);
+		//store provider instance as session property
+		try {
+			project.setSessionProperty(PROVIDER_PROP_KEY, provider);
+		} catch (CoreException e) {
+			throw TeamPlugin.wrapException(e);
+		}
+		return provider;
+	}	
+
+	/**
+	 * Disassoociates project with the repository provider its currently mapped to.
+	 * @throws TeamException The project isn't associated with any repository provider.
+	 */
+	public static void unmap(IProject project) throws TeamException {
+		try{
+			boolean hasProviderAssociated = project.getPersistentProperty(PROVIDER_PROP_KEY) != null;
+			
+			//If you tried to remove a non-existance nature it would fail, so we need to as well with the persistent prop
+			if(! hasProviderAssociated)
+				throw new TeamException(Policy.bind("RepositoryProvider.No_Provider_Registered", project.getName())); //$NON-NLS-1$
+
+			//This will instantiate one if it didn't already exist,
+			//which is ok since we need to call deconfigure() on it for proper lifecycle
+			getProvider(project).deconfigure();
+							
+			project.setSessionProperty(PROVIDER_PROP_KEY, null);
+			project.setPersistentProperty(PROVIDER_PROP_KEY, null);
+			
+			//removing the nature would've caused project description delta, so trigger one
+			project.setDescription(project.getDescription(), null);	
+		} catch (CoreException e) {
+			throw TeamPlugin.wrapException(e);
+		}
+	}	
+	
+	/*
+	 * Return the provider mapped to project, or null if none;
+	 */
+	private static RepositoryProvider lookupProviderProp(IProject project) throws CoreException {
+		return (RepositoryProvider) project.getSessionProperty(PROVIDER_PROP_KEY);
+	}	
+
+
+	/**
 	 * Default constructor required for the resources plugin to instantiate this class from
 	 * the nature extension definition.
 	 */
 	public RepositoryProvider() {
 	}
-	
+
 	/**
 	 * Configures the nature for the given project. This method is called after <code>setProject</code>
 	 * and before the nature is added to the project. If an exception is generated during configuration
@@ -99,7 +206,7 @@
 			configureProject();
 		} catch(CoreException e) {
 			try {
-				Team.removeNatureFromProject(getProject(), getID(), null);
+				RepositoryProvider.unmap(getProject());
 			} catch(TeamException e2) {
 				throw new CoreException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind("RepositoryProvider_Error_removing_nature_from_project___1") + getID(), e2)); //$NON-NLS-1$
 			}
@@ -151,7 +258,7 @@
 	 * @return a string description of this provider
 	 */
 	public String toString() {
-		return getProject().getName() + ":" + getID(); //$NON-NLS-1$
+		return Policy.bind("RepositoryProvider.toString", getProject().getName(), getID());   //$NON-NLS-1$
 	}
 	
 	/**
@@ -162,6 +269,10 @@
 	final public static String[] getAllProviderTypeIds() {
 		IProjectNatureDescriptor[] desc = ResourcesPlugin.getWorkspace().getNatureDescriptors();
 		List teamSet = new ArrayList();
+		
+		teamSet.addAll(AllProviderTypeIds);	// add in all the ones we know via extension point
+		
+		//fall back to old method of nature ID to find any for backwards compatibility
 		for (int i = 0; i < desc.length; i++) {
 			String[] setIds = desc[i].getNatureSetIds();
 			for (int j = 0; j < setIds.length; j++) {
@@ -183,8 +294,34 @@
 	 * @return the repository provider associated with the project
 	 */
 	final public static RepositoryProvider getProvider(IProject project) {
-		try {
+		try {					
 			if(project.isAccessible()) {
+				
+				//-----------------------------
+				//First check if we are using the persistent property to tag the project with provider
+
+				//
+				String id = project.getPersistentProperty(PROVIDER_PROP_KEY);
+				RepositoryProvider provider = lookupProviderProp(project);  //throws core, we will reuse the catching already here
+
+				//If we have the session but not the persistent, we have a problem
+				//because we somehow got only halfway through mapping before
+				if(id == null && provider != null) {
+					TeamPlugin.log(IStatus.ERROR, Policy.bind("RepositoryProvider.propertyMismatch", project.getName()), null);
+					project.setSessionProperty(PROVIDER_PROP_KEY, null); //clears it
+					return null;
+				}
+				
+				if(provider != null)
+					return provider;
+					
+				//check if it has the ID as a persistent property, if yes then instantiate provider
+				if(id != null)
+					return mapNewProvider(project, id);
+				
+				//Couldn't find using new method, fall back to lookup using natures for backwards compatibility
+				//-----------------------------
+								
 				IProjectDescription projectDesc = project.getDescription();
 				String[] natureIds = projectDesc.getNatureIds();
 				IWorkspace workspace = ResourcesPlugin.getWorkspace();
@@ -204,7 +341,9 @@
 				}
 			}
 		} catch(CoreException e) {
-			TeamPlugin.log(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Policy.bind(""), e)); //$NON-NLS-1$
+			TeamPlugin.log(e.getStatus());
+		} catch(TeamException e) {
+			TeamPlugin.log(e.getStatus());
 		}
 		return null;
 	}
@@ -221,9 +360,27 @@
 	final public static RepositoryProvider getProvider(IProject project, String id) {
 		try {
 			if(project.isAccessible()) {
+				String existingID = project.getPersistentProperty(PROVIDER_PROP_KEY);
+
+				if(id.equals(existingID)) {
+					//if the IDs are the same then they were previously mapped
+					//see if we already instantiated one
+					RepositoryProvider provider = lookupProviderProp(project);  //throws core, we will reuse the catching already here
+					if(provider != null)
+						return provider;
+					//otherwise instantiate and map a new one					
+					return mapNewProvider(project, id);
+				}
+					
+				//couldn't find using new method, fall back to lookup using natures for backwards compatibility
+				//-----------------------------
+
 				// if the nature id given is not in the team set then return
 				// null.
 				IProjectNatureDescriptor desc = ResourcesPlugin.getWorkspace().getNatureDescriptor(id);
+				if(desc == null) //for backwards compat., may not have any nature by that ID
+					return null;
+					
 				String[] setIds = desc.getNatureSetIds();
 				for (int i = 0; i < setIds.length; i++) {
 					if(setIds[i].equals(TEAM_SETID)) {
@@ -231,9 +388,11 @@
 					}			
 				}
 			}
-		} catch(CoreException ex) {
+		} catch(CoreException e) {
 			// would happen if provider nature id is not registered with the resources plugin
-			TeamPlugin.log(new Status(IStatus.WARNING, TeamPlugin.ID, 0, Policy.bind("RepositoryProviderTypeRepositoryProvider_not_registered_as_a_nature_id___3") + id, ex)); //$NON-NLS-1$
+			TeamPlugin.log(new Status(IStatus.WARNING, TeamPlugin.ID, 0, Policy.bind("RepositoryProviderTypeRepositoryProvider_not_registered_as_a_nature_id___3", id), e)); //$NON-NLS-1$
+		} catch(TeamException e) {
+			TeamPlugin.log(e.getStatus());
 		}
 		return null;
 	}
@@ -264,4 +423,68 @@
 	public void setProject(IProject project) {
 		this.project = project;
 	}
+	
+	private static List initializeAllProviderTypes() {
+		List allIDs = new ArrayList();
+		
+		TeamPlugin plugin = TeamPlugin.getPlugin();
+		if (plugin != null) {
+			IExtensionPoint extension = plugin.getDescriptor().getExtensionPoint(TeamPlugin.REPOSITORY_EXTENSION);
+			if (extension != null) {
+				IExtension[] extensions =  extension.getExtensions();
+				for (int i = 0; i < extensions.length; i++) {
+					IConfigurationElement [] configElements = extensions[i].getConfigurationElements();
+					for (int j = 0; j < configElements.length; j++) {
+						String extensionId = configElements[j].getAttribute("id"); //$NON-NLS-1$
+						allIDs.add(extensionId);
+					}
+				}
+			}
+		}
+		return allIDs;
+	}
+
+	private static RepositoryProvider newProvider(String id) {
+		TeamPlugin plugin = TeamPlugin.getPlugin();
+		if (plugin != null) {
+			IExtensionPoint extension = plugin.getDescriptor().getExtensionPoint(TeamPlugin.REPOSITORY_EXTENSION);
+			if (extension != null) {
+				IExtension[] extensions =  extension.getExtensions();
+				for (int i = 0; i < extensions.length; i++) {
+					IConfigurationElement [] configElements = extensions[i].getConfigurationElements();
+					for (int j = 0; j < configElements.length; j++) {
+						String extensionId = configElements[j].getAttribute("id"); //$NON-NLS-1$
+						if (extensionId != null && extensionId.equals(id)) {
+							try {
+								return (RepositoryProvider) configElements[j].createExecutableExtension("class"); //$NON-NLS-1$
+							} catch (CoreException e) {
+								TeamPlugin.log(e.getStatus());
+								return null;
+							}
+						}
+					}
+				}
+			}		
+		}
+		return null;
+	}	
+	
+	/*
+	 * Convert a project that are using natures to mark them as Team projects
+	 * to instead use persistent properties. Optionally remove the nature from the project.
+	 * Do nothing if the project has no Team nature.
+	 * Assume that the same ID is used for both the nature and the persistent property.
+	 */
+	public static void convertNatureToProperty(IProject project, boolean removeNature) throws TeamException {
+		RepositoryProvider provider = RepositoryProvider.getProvider(project);
+		if(provider == null)
+			return;
+			
+		String providerId = provider.getID();	
+		
+		RepositoryProvider.map(project, providerId);
+		if(removeNature) {
+			Team.removeNatureFromProject(project, providerId, new NullProgressMonitor());
+		}
+	}
 }
diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/TeamPlugin.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/TeamPlugin.java
index e5c69b1..9f0785f 100644
--- a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/TeamPlugin.java
+++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/TeamPlugin.java
@@ -45,6 +45,8 @@
 	// The id of the project set extension point
 	public static final String PROJECT_SET_EXTENSION = "projectSets"; //$NON-NLS-1$
 	// The id of the targets extension point
+	public static final String REPOSITORY_EXTENSION = "repository"; //$NON-NLS-1$
+	// The id of the targets extension point
 	public static final String TARGETS_EXTENSION = "targets"; //$NON-NLS-1$
 
 
diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/messages.properties b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/messages.properties
index 0e99a25..f1df48b 100644
--- a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/messages.properties
+++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/messages.properties
@@ -27,9 +27,11 @@
 RepositoryProvider_Too_many_providers_associated_with_project___2=Too many providers associated with project: 
 RepositoryProviderTypeduplicate_provider_found_in_plugin.xml___1=duplicate provider found in plugin.xml: 
 RepositoryProviderTypeRepositoryProvider_assigned_to_the_project_must_be_a_subclass_of_RepositoryProvider___2=RepositoryProvider assigned to the project must be a subclass of RepositoryProvider: 
-RepositoryProviderTypeRepositoryProvider_not_registered_as_a_nature_id___3=RepositoryProvider not registered as a nature id: 
-
+RepositoryProviderTypeRepositoryProvider_not_registered_as_a_nature_id___3=RepositoryProvider not registered as a nature id: {1}. 
 RepositoryProvider_providerTypeIdNotRegistered=Error configuring the RepositoryProvider the nature id is not registered as a valid RepositoryProviderType id.
+RepositoryProvider.couldNotInstantiateProvider=Could not instantiate provider {1} for project {0}.
+RepositoryProvider.No_Provider_Registered=No provider registered for {0}.
+RepositoryProvider.propertyMismatch=Inconsistent session/persistent property state looking up provider {1}.
 
 TeamPlugin_setting_global_ignore_7=setting global ignore
 TeamPlugin_renaming_21=renaming
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/NatureToPropertyAction.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/NatureToPropertyAction.java
new file mode 100644
index 0000000..8d8fbdb
--- /dev/null
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/NatureToPropertyAction.java
@@ -0,0 +1,51 @@
+package org.eclipse.team.internal.ui;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.team.core.RepositoryProvider;
+import org.eclipse.team.core.TeamException;
+import org.eclipse.team.internal.ui.actions.TeamAction;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+
+/**
+ * @author Administrator
+ *
+ * To change this generated comment edit the template variable "typecomment":
+ * Window>Preferences>Java>Templates.
+ * To enable and disable the creation of type comments go to
+ * Window>Preferences>Java>Code Generation.
+ */
+public class NatureToPropertyAction extends TeamAction {
+
+	/**
+	 * @see org.eclipse.team.internal.ui.actions.TeamAction#isEnabled()
+	 */
+	protected boolean isEnabled() throws TeamException {
+		return true;
+	}
+
+	/**
+	 * @see org.eclipse.ui.IActionDelegate#run(IAction)
+	 */
+	public void run(IAction action) {
+		run(new WorkspaceModifyOperation() {
+			public void execute(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException {
+				try {
+					IProject[] projects = getSelectedProjects();
+					for (int i = 0; i < projects.length; i++) {
+						RepositoryProvider.convertNatureToProperty(projects[i], true);
+					}
+				} catch (TeamException e) {
+					throw new InvocationTargetException(e);
+				} finally {
+					monitor.done();
+				}
+			}
+		}, Policy.bind("NatureToPropertyAction.label"), this.PROGRESS_DIALOG);  //$NON-NLS-1$
+	}
+
+}
+
diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/messages.properties b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/messages.properties
index 0cc4034..83065d1 100644
--- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/messages.properties
+++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/internal/ui/messages.properties
@@ -124,6 +124,8 @@
 TeamPreferencePage.General_settings_for_Team_support_1=General settings for Team support
 TeamPreferencePage.&Use_Incoming/Outgoing_mode_when_synchronizing_2=&Use Incoming/Outgoing mode when synchronizing
 
+NatureToPropertyAction.label=Convert Nature
+
 ###############################################
 # Target Management Messages
 ###############################################