KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > core > RepositoryProvider


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.team.core;
12
13 import java.net.URI JavaDoc;
14 import java.util.*;
15
16 import org.eclipse.core.filesystem.EFS;
17 import org.eclipse.core.filesystem.URIUtil;
18 import org.eclipse.core.resources.*;
19 import org.eclipse.core.resources.team.*;
20 import org.eclipse.core.runtime.*;
21 import org.eclipse.core.runtime.jobs.*;
22 import org.eclipse.osgi.util.NLS;
23 import org.eclipse.team.core.history.IFileHistoryProvider;
24 import org.eclipse.team.core.subscribers.Subscriber;
25 import org.eclipse.team.internal.core.*;
26
27 /**
28  * A concrete subclass of <code>RepositoryProvider</code> is created for each
29  * project that is associated with a repository provider. The lifecycle of these
30  * instances is is similar to that of the platform's 'nature' mechanism.
31  * <p>
32  * To create a repository provider and have it registered with the platform, a client
33  * must minimally:
34  * <ol>
35  * <li>extend <code>RepositoryProvider</code>
36  * <li>define a repository extension in <code>plugin.xml</code>.
37  * Here is an example extension point definition:
38  *
39  * <code>
40  * <br>&lt;extension point="org.eclipse.team.core.repository"&gt;
41  * <br>&nbsp;&lt;repository
42  * <br>&nbsp;&nbsp;class="org.eclipse.myprovider.MyRepositoryProvider"
43  * <br>&nbsp;&nbsp;id="org.eclipse.myprovider.myProviderID"&gt;
44  * <br>&nbsp;&lt;/repository&gt;
45  * <br>&lt;/extension&gt;
46  * </code>
47  * </ol></p>
48  * <p>
49  * Once a repository provider is registered with Team, then you
50  * can associate a repository provider with a project by invoking <code>RepositoryProvider.map()</code>.
51  * </p>
52  * @see RepositoryProvider#map(IProject, String)
53  *
54  * @since 2.0
55  */

56 public abstract class RepositoryProvider implements IProjectNature, IAdaptable {
57     
58     private final static String JavaDoc TEAM_SETID = "org.eclipse.team.repository-provider"; //$NON-NLS-1$
59

60     private final static List AllProviderTypeIds = initializeAllProviderTypes();
61     
62     // the project instance that this nature is assigned to
63
private IProject project;
64     
65     // lock to ensure that map/unmap and getProvider support concurrency
66
private static final ILock mappingLock = Job.getJobManager().newLock();
67     
68     // Session property used to identify projects that are not mapped
69
private static final Object JavaDoc NOT_MAPPED = new Object JavaDoc();
70     
71     /**
72      * Instantiate a new RepositoryProvider with concrete class by given providerID
73      * and associate it with project.
74      *
75      * @param project the project to be mapped
76      * @param id the ID of the provider to be mapped to the project
77      * @throws TeamException if
78      * <ul>
79      * <li>There is no provider by that ID.</li>
80      * <li>The project is already associated with a repository provider and that provider
81      * prevented its unmapping.</li>
82      * </ul>
83      * @see RepositoryProvider#unmap(IProject)
84      */

85     public static void map(IProject project, String JavaDoc id) throws TeamException {
86         ISchedulingRule rule = ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(project);
87         try {
88             // Obtain a scheduling rule on the project before obtaining the
89
// mappingLock. This is required because a caller of getProvider
90
// may hold a scheduling rule before getProvider is invoked but
91
// getProvider itself does not (and can not) obtain a scheduling rule.
92
// Thus, the locking order is always scheduling rule followed by
93
// mappingLock.
94
Job.getJobManager().beginRule(rule, null);
95             try {
96                 mappingLock.acquire();
97                 RepositoryProvider existingProvider = null;
98     
99                 if(project.getPersistentProperty(TeamPlugin.PROVIDER_PROP_KEY) != null)
100                     existingProvider = getProvider(project); // get the real one, not the nature one
101

102                 //if we already have a provider, and its the same ID, we're ok
103
//if the ID's differ, unmap the existing.
104
if(existingProvider != null) {
105                     if(existingProvider.getID().equals(id))
106                         return; //nothing to do
107
else
108                         unmap(project);
109                 }
110                 
111                 // Create the provider as a session property before adding the persistent
112
// property to ensure that the provider can be instantiated
113
RepositoryProvider provider = mapNewProvider(project, id);
114     
115                 //mark it with the persistent ID for filtering
116
try {
117                     project.setPersistentProperty(TeamPlugin.PROVIDER_PROP_KEY, id);
118                 } catch (CoreException outer) {
119                     // couldn't set the persistent property so clear the session property
120
try {
121                         project.setSessionProperty(TeamPlugin.PROVIDER_PROP_KEY, null);
122                     } catch (CoreException inner) {
123                         // something is seriously wrong
124
TeamPlugin.log(IStatus.ERROR, NLS.bind(Messages.RepositoryProvider_couldNotClearAfterError, new String JavaDoc[] { project.getName(), id }), inner);
125                     }
126                     throw outer;
127                 }
128                 
129                 provider.configure();
130                 
131                 //adding the nature would've caused project description delta, so trigger one
132
project.touch(null);
133                 
134                 // Set the rule factory for the provider after the touch
135
// so the touch does not fail due to incompatible modify rules
136
TeamHookDispatcher.setProviderRuleFactory(project, provider.getRuleFactory());
137                 
138                 // Notify any listeners
139
RepositoryProviderManager.getInstance().providerMapped(provider);
140             } finally {
141                 mappingLock.release();
142             }
143         } catch (CoreException e) {
144             throw TeamPlugin.wrapException(e);
145         } finally {
146             Job.getJobManager().endRule(rule);
147         }
148     }
149
150     /*
151      * Instantiate the provider denoted by ID and store it in the session property.
152      * Return the new provider instance. If a TeamException is thrown, it is
153      * guaranteed that the session property will not be set.
154      *
155      * @param project
156      * @param id
157      * @return RepositoryProvider
158      * @throws TeamException we can't instantiate the provider, or if the set
159      * session property fails from core
160      */

161     private static RepositoryProvider mapNewProvider(final IProject project, final String JavaDoc id) throws TeamException {
162         final RepositoryProvider provider = newProvider(id); // instantiate via extension point
163

164         if(provider == null)
165             throw new TeamException(NLS.bind(Messages.RepositoryProvider_couldNotInstantiateProvider, new String JavaDoc[] { project.getName(), id }));
166         
167         // validate that either the provider supports linked resources or the project has no linked resources
168
if (!provider.canHandleLinkedResourceURI()) {
169             try {
170                 project.accept(new IResourceProxyVisitor() {
171                     public boolean visit(IResourceProxy proxy) throws CoreException {
172                         if (proxy.isLinked()) {
173                             if (!provider.canHandleLinkedResources() ||
174                                     proxy.requestFullPath().segmentCount() > 2 ||
175                                     !EFS.SCHEME_FILE.equals(proxy.requestResource().getLocationURI().getScheme()))
176                                 throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, IResourceStatus.LINKING_NOT_ALLOWED, NLS.bind(Messages.RepositoryProvider_linkedURIsExist, new String JavaDoc[] { project.getName(), id }), null));
177                         }
178                         return true;
179                     }
180                 }, IResource.NONE);
181             } catch (CoreException e) {
182                 if (e instanceof TeamException) {
183                     TeamException te = (TeamException) e;
184                     throw te;
185                 }
186                 throw new TeamException(e);
187             }
188         }
189         if (!provider.canHandleLinkedResources()) {
190             try {
191                 IResource[] members = project.members();
192                 for (int i = 0; i < members.length; i++) {
193                     IResource resource = members[i];
194                     if (resource.isLinked()) {
195                         throw new TeamException(new Status(IStatus.ERROR, TeamPlugin.ID, IResourceStatus.LINKING_NOT_ALLOWED, NLS.bind(Messages.RepositoryProvider_linkedResourcesExist, new String JavaDoc[] { project.getName(), id }), null));
196                     }
197                 }
198             } catch (CoreException e) {
199                 throw TeamPlugin.wrapException(e);
200             }
201         }
202         
203         //store provider instance as session property
204
try {
205             project.setSessionProperty(TeamPlugin.PROVIDER_PROP_KEY, provider);
206             provider.setProject(project);
207         } catch (CoreException e) {
208             throw TeamPlugin.wrapException(e);
209         }
210         return provider;
211     }
212
213     private static RepositoryProvider mapExistingProvider(IProject project, String JavaDoc id) throws TeamException {
214         try {
215             // Obtain the mapping lock before creating the instance so we can make sure
216
// that a disconnect is not happening at the same time
217
mappingLock.acquire();
218             try {
219                 // Ensure that the persistent property is still set
220
// (i.e. an unmap may have come in since we checked it last
221
String JavaDoc currentId = project.getPersistentProperty(TeamPlugin.PROVIDER_PROP_KEY);
222                 if (currentId == null) {
223                     // The provider has been unmapped
224
return null;
225                 }
226                 if (!currentId.equals(id)) {
227                     // A provider has been disconnected and another connected
228
// Since mapping creates the session property, we
229
// can just return it
230
return lookupProviderProp(project);
231                 }
232             } catch (CoreException e) {
233                 throw TeamPlugin.wrapException(e);
234             }
235             return mapNewProvider(project, id);
236         } finally {
237             mappingLock.release();
238         }
239     }
240     /**
241      * Disassociates project with the repository provider its currently mapped to.
242      * @param project
243      * @throws TeamException The project isn't associated with any repository provider.
244      */

245     public static void unmap(IProject project) throws TeamException {
246         ISchedulingRule rule = ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(project);
247         try{
248             // See the map(IProject, String) method for a description of lock ordering
249
Job.getJobManager().beginRule(rule, null);
250             try {
251                 mappingLock.acquire();
252                 String JavaDoc id = project.getPersistentProperty(TeamPlugin.PROVIDER_PROP_KEY);
253                 
254                 //If you tried to remove a non-existant nature it would fail, so we need to as well with the persistent prop
255
if(id == null) {
256                     throw new TeamException(NLS.bind(Messages.RepositoryProvider_No_Provider_Registered, new String JavaDoc[] { project.getName() }));
257                 }
258                 
259                 //This will instantiate one if it didn't already exist,
260
//which is ok since we need to call deconfigure() on it for proper lifecycle
261
RepositoryProvider provider = getProvider(project);
262                 if (provider == null) {
263                     // There is a persistent property but the provider cannot be obtained.
264
// The reason could be that the provider's plugin is no longer available.
265
// Better log it just in case this is unexpected.
266
TeamPlugin.log(IStatus.ERROR, NLS.bind(Messages.RepositoryProvider_couldNotInstantiateProvider, new String JavaDoc[] { project.getName(), id }), null);
267                 }
268     
269                 if (provider != null) provider.deconfigure();
270                                 
271                 project.setSessionProperty(TeamPlugin.PROVIDER_PROP_KEY, null);
272                 project.setPersistentProperty(TeamPlugin.PROVIDER_PROP_KEY, null);
273                 
274                 if (provider != null) provider.deconfigured();
275                 
276                 //removing the nature would've caused project description delta, so trigger one
277
project.touch(null);
278                 
279                 // Change the rule factory after the touch in order to
280
// avoid rule incompatibility
281
TeamHookDispatcher.setProviderRuleFactory(project, null);
282                 
283                 // Notify any listeners
284
RepositoryProviderManager.getInstance().providerUnmapped(project);
285             } finally {
286                 mappingLock.release();
287             }
288         } catch (CoreException e) {
289             throw TeamPlugin.wrapException(e);
290         } finally {
291             Job.getJobManager().endRule(rule);
292         }
293     }
294     
295     /*
296      * Return the provider mapped to project, or null if none;
297      */

298     private static RepositoryProvider lookupProviderProp(IProject project) throws CoreException {
299         Object JavaDoc provider = project.getSessionProperty(TeamPlugin.PROVIDER_PROP_KEY);
300         if (provider instanceof RepositoryProvider) {
301             return (RepositoryProvider) provider;
302         }
303         return null;
304     }
305
306
307     /**
308      * Default constructor required for the resources plugin to instantiate this class from
309      * the nature extension definition.
310      */

311     public RepositoryProvider() {
312     }
313
314     /**
315      * Configures the provider for the given project. This method is called after <code>setProject</code>.
316      * If an exception is generated during configuration
317      * of the project, the provider will not be assigned to the project.
318      *
319      * @throws CoreException if the configuration fails.
320      */

321     abstract public void configureProject() throws CoreException;
322     
323     /**
324      * Configures the nature for the given project. This is called by <code>RepositoryProvider.map()</code>
325      * the first time a provider is mapped to a project. It is not intended to be called by clients.
326      *
327      * @throws CoreException if this method fails. If the configuration fails the provider will not be
328      * associated with the project.
329      *
330      * @see RepositoryProvider#configureProject()
331      */

332     final public void configure() throws CoreException {
333         try {
334             configureProject();
335         } catch(CoreException e) {
336             try {
337                 RepositoryProvider.unmap(getProject());
338             } catch(TeamException e2) {
339                 throw new CoreException(new Status(IStatus.ERROR, TeamPlugin.ID, 0, Messages.RepositoryProvider_Error_removing_nature_from_project___1 + getID(), e2));
340             }
341             throw e;
342         }
343     }
344
345     /**
346      * Method deconfigured is invoked after a provider has been unmaped. The
347      * project will no longer have the provider associated with it when this
348      * method is invoked. It is a last chance for the provider to clean up.
349      */

350     protected void deconfigured() {
351     }
352     
353     /**
354      * Answer the id of this provider instance. The id should be the repository provider's
355      * id as defined in the provider plugin's plugin.xml.
356      *
357      * @return the nature id of this provider
358      */

359     abstract public String JavaDoc getID();
360
361     /**
362      * Returns an <code>IFileModificationValidator</code> for pre-checking operations
363      * that modify the contents of files.
364      * Returns <code>null</code> if the provider does not wish to participate in
365      * file modification validation.
366      * @return an <code>IFileModificationValidator</code> for pre-checking operations
367      * that modify the contents of files
368      *
369      * @see org.eclipse.core.resources.IFileModificationValidator
370      * @deprecated use {@link #getFileModificationValidator2()}
371      */

372     public IFileModificationValidator getFileModificationValidator() {
373         return null;
374     }
375     
376     /**
377      * Returns a {@link FileModificationValidator} for pre-checking operations
378      * that modify the contents of files. Returns <code>null</code> if the
379      * provider does not wish to participate in file modification validation. By
380      * default, this method wraps the old validator returned from
381      * {@link #getFileModificationValidator()}. Subclasses that which to remain
382      * backwards compatible while providing this new API should override
383      * {@link #getFileModificationValidator2()} to return a subclass of
384      * {@link FileModificationValidator} and should return the same
385      * validator from {@link #getFileModificationValidator()}.
386      * <p>
387      * This method is not intended to be called by clients. Clients should
388      * use the {@link IWorkspace#validateEdit(IFile[], Object)} method instead.
389      *
390      * @return an <code>FileModificationValidator</code> for pre-checking
391      * operations that modify the contents of files
392      *
393      * @see FileModificationValidator
394      * @see IWorkspace#validateEdit(IFile[], Object)
395      * @since 3.3
396      */

397     public FileModificationValidator getFileModificationValidator2() {
398         final IFileModificationValidator fileModificationValidator = getFileModificationValidator();
399         if (fileModificationValidator == null)
400             return null;
401         return new FileModificationValidator() {
402             public IStatus validateSave(IFile file) {
403                 return fileModificationValidator.validateSave(file);
404             }
405             public IStatus validateEdit(IFile[] files,
406                     FileModificationValidationContext context) {
407                 // Extract the shell from the context in order to invoke the old API
408
Object JavaDoc shell;
409                 if (context == null)
410                     shell = null;
411                 else
412                     shell = context.getShell();
413                 return fileModificationValidator.validateEdit(files, shell);
414             }
415         };
416     }
417     
418     /**
419      * Returns an <code>IFileHistoryProvider</code> which can be used to access
420      * file histories. By default, returns <code>null</code>. Subclasses may override.
421      * @return an <code>IFileHistoryProvider</code> which can be used to access
422      * file histories.
423      * @since 3.2
424      */

425     public IFileHistoryProvider getFileHistoryProvider(){
426        return null;
427     }
428     
429     /**
430      * Returns an <code>IMoveDeleteHook</code> for handling moves and deletes
431      * that occur within projects managed by the provider. This allows providers
432      * to control how moves and deletes occur and includes the ability to prevent them.
433      * <p>
434      * Returning <code>null</code> signals that the default move and delete behavior is desired.
435      * @return an <code>IMoveDeleteHook</code> for handling moves and deletes
436      * that occur within projects managed by the provider
437      *
438      * @see org.eclipse.core.resources.team.IMoveDeleteHook
439      */

440     public IMoveDeleteHook getMoveDeleteHook() {
441         return null;
442     }
443     
444     /**
445      * Returns a brief description of this provider. The exact details of the
446      * representation are unspecified and subject to change, but the following
447      * may be regarded as typical:
448      *
449      * "SampleProject:org.eclipse.team.cvs.provider"
450      *
451      * @return a string description of this provider
452      */

453     public String JavaDoc toString() {
454         return NLS.bind(Messages.RepositoryProvider_toString, new String JavaDoc[] { getProject().getName(), getID() });
455     }
456     
457     /**
458      * Returns all known (registered) RepositoryProvider ids.
459      *
460      * @return an array of registered repository provider ids.
461      */

462     final public static String JavaDoc[] getAllProviderTypeIds() {
463         IProjectNatureDescriptor[] desc = ResourcesPlugin.getWorkspace().getNatureDescriptors();
464         Set teamSet = new HashSet();
465         
466         teamSet.addAll(AllProviderTypeIds); // add in all the ones we know via extension point
467

468         //fall back to old method of nature ID to find any for backwards compatibility
469
for (int i = 0; i < desc.length; i++) {
470             String JavaDoc[] setIds = desc[i].getNatureSetIds();
471             for (int j = 0; j < setIds.length; j++) {
472                 if(setIds[j].equals(TEAM_SETID)) {
473                     teamSet.add(desc[i].getNatureId());
474                 }
475             }
476         }
477         return (String JavaDoc[]) teamSet.toArray(new String JavaDoc[teamSet.size()]);
478     }
479     
480     /**
481      * Returns the provider for a given IProject or <code>null</code> if a provider is not associated with
482      * the project or if the project is closed or does not exist. This method should be called if the caller
483      * is looking for <b>any</b> repository provider. Otherwise call <code>getProvider(project, id)</code>
484      * to look for a specific repository provider type.
485      * </p>
486      * @param project the project to query for a provider
487      * @return the repository provider associated with the project
488      */

489     final public static RepositoryProvider getProvider(IProject project) {
490         try {
491             if(project.isAccessible()) {
492                 
493                 //-----------------------------
494
//First, look for the session property
495
RepositoryProvider provider = lookupProviderProp(project);
496                 if(provider != null)
497                     return provider;
498                 // Do a quick check to see it the project is known to be unshared.
499
// This is done to avoid accessing the persistent property store
500
if (isMarkedAsUnshared(project))
501                     return null;
502                 
503                 // -----------------------------
504
//Next, check if it has the ID as a persistent property, if yes then instantiate provider
505
String JavaDoc id = project.getPersistentProperty(TeamPlugin.PROVIDER_PROP_KEY);
506                 if(id != null)
507                     return mapExistingProvider(project, id);
508                 
509                 //Couldn't find using new method, fall back to lookup using natures for backwards compatibility
510
//-----------------------------
511
IProjectDescription projectDesc = project.getDescription();
512                 String JavaDoc[] natureIds = projectDesc.getNatureIds();
513                 IWorkspace workspace = ResourcesPlugin.getWorkspace();
514                 // for every nature id on this project, find it's natures sets and check if it is
515
// in the team set.
516
for (int i = 0; i < natureIds.length; i++) {
517                     IProjectNatureDescriptor desc = workspace.getNatureDescriptor(natureIds[i]);
518                     // The descriptor can be null if the nature doesn't exist
519
if (desc != null) {
520                         String JavaDoc[] setIds = desc.getNatureSetIds();
521                         for (int j = 0; j < setIds.length; j++) {
522                             if(setIds[j].equals(TEAM_SETID)) {
523                                 return getProvider(project, natureIds[i]);
524                             }
525                         }
526                     }
527                 }
528             }
529         } catch(CoreException e) {
530             if (!isAcceptableException(e)) {
531                 TeamPlugin.log(e);
532             }
533         }
534         markAsUnshared(project);
535         return null;
536     }
537     
538     /*
539      * Return whether the given exception is acceptable during a getProvider().
540      * If the exception is acceptable, it is assumed that there is no provider
541      * on the project.
542      */

543     private static boolean isAcceptableException(CoreException e) {
544         return e.getStatus().getCode() == IResourceStatus.RESOURCE_NOT_FOUND;
545     }
546
547     /**
548      * Returns a provider of type with the given id if associated with the given project
549      * or <code>null</code> if the project is not associated with a provider of that type
550      * or the nature id is that of a non-team repository provider nature.
551      *
552      * @param project the project to query for a provider
553      * @param id the repository provider id
554      * @return the repository provider
555      */

556     final public static RepositoryProvider getProvider(IProject project, String JavaDoc id) {
557         try {
558             if(project.isAccessible()) {
559                 // Look for an existing provider first to avoid accessing persistent properties
560
RepositoryProvider provider = lookupProviderProp(project); //throws core, we will reuse the catching already here
561
if(provider != null) {
562                     if (provider.getID().equals(id)) {
563                         return provider;
564                     } else {
565                         return null;
566                     }
567                 }
568                 // Do a quick check to see it the project is known to be unshared.
569
// This is done to avoid accessing the persistent property store
570
if (isMarkedAsUnshared(project))
571                     return null;
572                 
573                 // There isn't one so check the persistent property
574
String JavaDoc existingID = project.getPersistentProperty(TeamPlugin.PROVIDER_PROP_KEY);
575                 if(id.equals(existingID)) {
576                     // The ids are equal so instantiate and return
577
RepositoryProvider newProvider = mapExistingProvider(project, id);
578                     if (newProvider!= null && newProvider.getID().equals(id)) {
579                         return newProvider;
580                     } else {
581                         // The id changed before we could create the desired provider
582
return null;
583                     }
584                 }
585                     
586                 //couldn't find using new method, fall back to lookup using natures for backwards compatibility
587
//-----------------------------
588

589                 // if the nature id given is not in the team set then return
590
// null.
591
IProjectNatureDescriptor desc = ResourcesPlugin.getWorkspace().getNatureDescriptor(id);
592                 if(desc == null) //for backwards compatibility, may not have any nature by that ID
593
return null;
594                     
595                 String JavaDoc[] setIds = desc.getNatureSetIds();
596                 for (int i = 0; i < setIds.length; i++) {
597                     if(setIds[i].equals(TEAM_SETID)) {
598                         return (RepositoryProvider)project.getNature(id);
599                     }
600                 }
601             }
602         } catch(CoreException e) {
603             if (!isAcceptableException(e)) {
604                 TeamPlugin.log(e);
605             }
606         }
607         markAsUnshared(project);
608         return null;
609     }
610     
611     /**
612      * Returns whether the given project is shared or not. This is a lightweight
613      * method in that it will not instantiate a provider instance (as
614      * <code>getProvider</code> would) if one is not already instantiated.
615      *
616      * Note that IProject.touch() generates a project description delta. This, in combination
617      * with isShared() can be used to be notified of sharing/unsharing of projects.
618      *
619      * @param project the project being tested.
620      * @return boolean
621      *
622      * @see #getProvider(IProject)
623      *
624      * @since 2.1
625      */

626     public static boolean isShared(IProject project) {
627         if (!project.isAccessible()) return false;
628         try {
629             if (lookupProviderProp(project) != null) return true;
630             // Do a quick check to see it the project is known to be unshared.
631
// This is done to avoid accessing the persistent property store
632
if (isMarkedAsUnshared(project))
633                 return false;
634             boolean shared = project.getPersistentProperty(TeamPlugin.PROVIDER_PROP_KEY) != null;
635             if (!shared)
636                 markAsUnshared(project);
637             return shared;
638         } catch (CoreException e) {
639             TeamPlugin.log(e);
640             return false;
641         }
642     }
643     
644     private static boolean isMarkedAsUnshared(IProject project) {
645         try {
646             return project.getSessionProperty(TeamPlugin.PROVIDER_PROP_KEY) == NOT_MAPPED;
647         } catch (CoreException e) {
648             return false;
649         }
650     }
651
652     private static void markAsUnshared(IProject project) {
653         try {
654             project.setSessionProperty(TeamPlugin.PROVIDER_PROP_KEY, NOT_MAPPED);
655         } catch (CoreException e) {
656             // Just ignore the error as this is just an optimization
657
}
658     }
659
660     /*
661      * @see IProjectNature#getProject()
662      */

663     public IProject getProject() {
664         return project;
665     }
666
667     /*
668      * @see IProjectNature#setProject(IProject)
669      */

670     public void setProject(IProject project) {
671         this.project = project;
672     }
673     
674     private static List initializeAllProviderTypes() {
675         List allIDs = new ArrayList();
676         
677         TeamPlugin plugin = TeamPlugin.getPlugin();
678         if (plugin != null) {
679             IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(TeamPlugin.ID, TeamPlugin.REPOSITORY_EXTENSION);
680             if (extension != null) {
681                 IExtension[] extensions = extension.getExtensions();
682                 for (int i = 0; i < extensions.length; i++) {
683                     IConfigurationElement [] configElements = extensions[i].getConfigurationElements();
684                     for (int j = 0; j < configElements.length; j++) {
685                         String JavaDoc extensionId = configElements[j].getAttribute("id"); //$NON-NLS-1$
686
allIDs.add(extensionId);
687                     }
688                 }
689             }
690         }
691         return allIDs;
692     }
693
694     private static RepositoryProvider newProvider(String JavaDoc id) {
695         TeamPlugin plugin = TeamPlugin.getPlugin();
696         if (plugin != null) {
697             IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(TeamPlugin.ID, TeamPlugin.REPOSITORY_EXTENSION);
698             if (extension != null) {
699                 IExtension[] extensions = extension.getExtensions();
700                 for (int i = 0; i < extensions.length; i++) {
701                     IConfigurationElement [] configElements = extensions[i].getConfigurationElements();
702                     for (int j = 0; j < configElements.length; j++) {
703                         String JavaDoc extensionId = configElements[j].getAttribute("id"); //$NON-NLS-1$
704
if (extensionId != null && extensionId.equals(id)) {
705                             try {
706                                 return (RepositoryProvider) configElements[j].createExecutableExtension("class"); //$NON-NLS-1$
707
} catch (CoreException e) {
708                                 TeamPlugin.log(e);
709                             } catch (ClassCastException JavaDoc e) {
710                                 String JavaDoc className = configElements[j].getAttribute("class"); //$NON-NLS-1$
711
TeamPlugin.log(IStatus.ERROR, NLS.bind(Messages.RepositoryProvider_invalidClass, new String JavaDoc[] { id, className }), e);
712                             }
713                             return null;
714                         }
715                     }
716                 }
717             }
718         }
719         return null;
720     }
721     
722     /**
723      * Method validateCreateLink is invoked by the Platform Core TeamHook when a
724      * linked resource is about to be added to the provider's project. It should
725      * not be called by other clients and it should not need to be overridden by
726      * subclasses (although it is possible to do so in special cases).
727      * Subclasses can indicate that they support linked resources by overriding
728      * the <code>canHandleLinkedResources()</code> method.
729      *
730      * @param resource see <code>org.eclipse.core.resources.team.TeamHook</code>
731      * @param updateFlags see <code>org.eclipse.core.resources.team.TeamHook</code>
732      * @param location see <code>org.eclipse.core.resources.team.TeamHook</code>
733      * @return IStatus see <code>org.eclipse.core.resources.team.TeamHook</code>
734      *
735      * @see RepositoryProvider#canHandleLinkedResources()
736      *
737      * @deprecated see {@link #validateCreateLink(IResource, int, URI) } instead
738      * @since 2.1
739      */

740     public IStatus validateCreateLink(IResource resource, int updateFlags, IPath location) {
741         if (canHandleLinkedResources()) {
742             return Team.OK_STATUS;
743         } else {
744             return new Status(IStatus.ERROR, TeamPlugin.ID, IResourceStatus.LINKING_NOT_ALLOWED, NLS.bind(Messages.RepositoryProvider_linkedResourcesNotSupported, new String JavaDoc[] { getProject().getName(), getID() }), null);
745         }
746     }
747     
748     /**
749      * Method validateCreateLink is invoked by the Platform Core TeamHook when a
750      * linked resource is about to be added to the provider's project. It should
751      * not be called by other clients and it should not need to be overridden by
752      * subclasses (although it is possible to do so in special cases).
753      * Subclasses can indicate that they support linked resources by overriding
754      * the <code>canHandleLinkedResourcesAtArbitraryDepth()</code> method.
755      *
756      * @param resource see <code>org.eclipse.core.resources.team.TeamHook</code>
757      * @param updateFlags see <code>org.eclipse.core.resources.team.TeamHook</code>
758      * @param location see <code>org.eclipse.core.resources.team.TeamHook</code>
759      * @return IStatus see <code>org.eclipse.core.resources.team.TeamHook</code>
760      *
761      * @see RepositoryProvider#canHandleLinkedResourceURI()
762      *
763      * @since 3.2
764      */

765     public IStatus validateCreateLink(IResource resource, int updateFlags, URI JavaDoc location) {
766         if (resource.getProjectRelativePath().segmentCount() == 1 && EFS.SCHEME_FILE.equals(location.getScheme())) {
767             // This is compatible with the old style link so invoke the old
768
// validateLink
769
return validateCreateLink(resource, updateFlags, URIUtil.toPath(location));
770         }
771         if (canHandleLinkedResourceURI()) {
772             return Team.OK_STATUS;
773         } else {
774             return new Status(IStatus.ERROR, TeamPlugin.ID, IResourceStatus.LINKING_NOT_ALLOWED, NLS.bind(Messages.RepositoryProvider_linkedURIsNotSupported, new String JavaDoc[] { getProject().getName(), getID() }), null);
775         }
776     }
777     
778     /**
779      * Method canHandleLinkedResources should be overridden by subclasses who
780      * support linked resources. At a minimum, supporting linked resources
781      * requires changes to the move/delete hook
782      * {@link org.eclipse.core.resources.team.IMoveDeleteHook}. This method is
783      * called after the RepositoryProvider is instantiated but before
784      * <code>setProject()</code> is invoked so it will not have access to any
785      * state determined from the <code>setProject()</code> method.
786      * @return boolean
787      *
788      * @see org.eclipse.core.resources.team.IMoveDeleteHook
789      *
790      * @since 2.1
791      *
792      * @deprecated see {@link #canHandleLinkedResourceURI() }
793      */

794     public boolean canHandleLinkedResources() {
795         return canHandleLinkedResourceURI();
796     }
797     
798     /**
799      * Return whether this repository provider can handle linked resources that
800      * are located via a URI (i.e. may not be on the local file system) or occur
801      * at an arbitrary depth in the project. This should be overridden by
802      * subclasses who support linked resources at arbitrary depth and/or in
803      * non-local file systems. This is not enabled by default since linked
804      * resources previously only occurred at the root of a project but now can
805      * occur anywhere within a project. This method is called after the
806      * RepositoryProvider is instantiated but before <code>setProject()</code>
807      * is invoked so it will not have access to any state determined from the
808      * <code>setProject()</code> method.
809      *
810      * @return whether this repository provider can handle linked resources that
811      * are located via a URI or occur at an arbitrary depth in the
812      * project
813      *
814      * @see #validateCreateLink(IResource, int, URI)
815      *
816      * @since 3.2
817      */

818     public boolean canHandleLinkedResourceURI() {
819         return false;
820     }
821     
822     
823     /* (non-Javadoc)
824      * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
825      */

826     public Object JavaDoc getAdapter(Class JavaDoc adapter) {
827         return null;
828     }
829
830     /**
831      * Return the resource rule factory for this provider. This factory
832      * will be used to determine the scheduling rules that are to be obtained
833      * when performing various resource operations (e.g. move, copy, delete, etc.)
834      * on the resources in the project the provider is mapped to.
835      * <p>
836      * By default, the factory returned by this method is pessimistic and
837      * obtains the workspace lock for all operations that could result in a
838      * callback to the provider (either through the <code>IMoveDeleteHook</code>
839      * or <code>IFileModificationValidator</code>). This is done to ensure that
840      * older providers are not broken. However, providers should override this
841      * method and provide a subclass of {@link org.eclipse.core.resources.team.ResourceRuleFactory}
842      * that provides rules of a more optimistic granularity (e.g. project
843      * or lower).
844      * @return the rule factory for this provider
845      * @since 3.0
846      * @see org.eclipse.core.resources.team.ResourceRuleFactory
847      */

848     public IResourceRuleFactory getRuleFactory() {
849         return new PessimisticResourceRuleFactory();
850     }
851     
852     /**
853      * Return a {@link Subscriber} that describes the synchronization state
854      * of the resources contained in the project associated with this
855      * provider. The subscriber is obtained from the {@link RepositoryProviderType}
856      * associated with a provider and is thus shared for all providers of the
857      * same type.
858      * @return a subscriber that provides resource synchronization state or <code>null</code>
859      * @since 3.2
860      */

861     public final Subscriber getSubscriber() {
862         RepositoryProviderType type = RepositoryProviderType.getProviderType(getID());
863         if (type != null)
864             return type.getSubscriber();
865         return null;
866     }
867 }
868
Popular Tags