KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > ccvs > ui > operations > CheckoutProjectOperation


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  * Philippe Ombredanne - bug 84808
11  *******************************************************************************/

12 package org.eclipse.team.internal.ccvs.ui.operations;
13
14 import java.io.File JavaDoc;
15 import java.io.IOException JavaDoc;
16 import java.util.*;
17
18 import org.eclipse.core.resources.*;
19 import org.eclipse.core.runtime.*;
20 import org.eclipse.core.runtime.jobs.*;
21 import org.eclipse.osgi.util.NLS;
22 import org.eclipse.team.core.RepositoryProvider;
23 import org.eclipse.team.core.TeamException;
24 import org.eclipse.team.internal.ccvs.core.*;
25 import org.eclipse.team.internal.ccvs.core.client.*;
26 import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption;
27 import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
28 import org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer;
29 import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
30 import org.eclipse.team.internal.ccvs.ui.*;
31 import org.eclipse.team.internal.ccvs.ui.Policy;
32 import org.eclipse.team.internal.ui.wizards.WorkingSetsDialog;
33 import org.eclipse.ui.*;
34 /**
35  * This class acts as an abstract class for checkout operations.
36  * It provides a few common methods.
37  */

38 public abstract class CheckoutProjectOperation extends CheckoutOperation {
39
40     private String JavaDoc targetLocation;
41
42     public CheckoutProjectOperation(IWorkbenchPart part, ICVSRemoteFolder[] remoteFolders, String JavaDoc targetLocation) {
43         super(part, remoteFolders);
44         this.targetLocation = targetLocation;
45     }
46     
47     /**
48      * Create and open the project, using a custom location if there is one.
49      *
50      * @param project
51      * @param monitor
52      * @throws CVSException
53      */

54     protected void createAndOpenProject(IProject project, IProgressMonitor monitor) throws CVSException {
55         try {
56             monitor.beginTask(null, 5);
57             IProjectDescription desc = getDescriptionFor(project);
58             if (project.exists()) {
59                 if (desc != null) {
60                     project.move(desc, true, Policy.subMonitorFor(monitor, 3));
61                 }
62             } else {
63                 if (desc == null) {
64                     // create in default location
65
project.create(Policy.subMonitorFor(monitor, 3));
66                 } else {
67                     // create in some other location
68
project.create(desc, Policy.subMonitorFor(monitor, 3));
69                 }
70             }
71             if (!project.isOpen()) {
72                 project.open(Policy.subMonitorFor(monitor, 2));
73             }
74         } catch (CoreException e) {
75             throw CVSException.wrapException(e);
76         } finally {
77             monitor.done();
78         }
79     }
80     
81     protected IProjectDescription getDescriptionFor(IProject project) {
82         if (targetLocation == null) return null;
83         String JavaDoc projectName = project.getName();
84         IProjectDescription description = ResourcesPlugin.getWorkspace().newProjectDescription(projectName);
85         description.setLocation(getTargetLocationFor(project));
86         return description;
87     }
88     
89     /**
90      * Return the target location where the given project should be located or
91      * null if the default location should be used.
92      *
93      * @param project
94      */

95     protected IPath getTargetLocationFor(IProject project) {
96         if (targetLocation == null) return null;
97         return new Path(targetLocation);
98     }
99
100     protected String JavaDoc getRemoteModuleName(ICVSRemoteFolder resource) {
101         String JavaDoc moduleName;
102         if (resource.isDefinedModule()) {
103             moduleName = resource.getName();
104         } else {
105             moduleName = resource.getRepositoryRelativePath();
106         }
107         return moduleName;
108     }
109
110     protected IStatus checkout(final ICVSRemoteFolder resource, IProject project, IProgressMonitor pm) throws CVSException {
111         // Get the location and the workspace root
112
ICVSFolder root = CVSWorkspaceRoot.getCVSFolderFor(ResourcesPlugin.getWorkspace().getRoot());
113         ICVSRepositoryLocation repository = resource.getRepository();
114         // Open a connection session to the repository
115
final Session session = new Session(repository, root);
116         pm.beginTask(null, 100);
117         Policy.checkCanceled(pm);
118         session.open(Policy.subMonitorFor(pm, 5), false /* read-only */);
119         try {
120             
121             // Check to see if the entire repo is being checked out.
122
if (project == null && resource.getName().equals(".")) { //$NON-NLS-1$
123
// No project was specified but we need on for this to work
124
String JavaDoc name = new Path(null, resource.getRepository().getRootDirectory()).lastSegment();
125                 project = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
126             }
127             
128             // Check to see if using remote metafile project description name is preferred
129
if (project == null
130                     && CVSUIPlugin.getPlugin().isUseProjectNameOnCheckout()
131                     && resource instanceof RemoteProjectFolder) {
132                 RemoteProjectFolder rpf = (RemoteProjectFolder) resource;
133                 if (rpf.hasProjectName())
134                 {
135                     // no project was specified but we need to attempt the creation of one
136
// based on the metafile project name
137
project = ResourcesPlugin.getWorkspace().getRoot().getProject(rpf.getProjectName());
138                 }
139             }
140             
141             // Determine the local target projects (either the project provider or the module expansions)
142
// Note: Module expansions can be run over the same connection as a checkout
143
final IProject[] targetProjects = determineProjects(session, resource, project, Policy.subMonitorFor(pm, 5));
144             if (targetProjects == null) {
145                 // An error occurred and was recorded so return it
146
return getLastError();
147             } else if (targetProjects.length == 0) {
148                 return OK;
149             }
150             
151             final boolean sendModuleName = project != null;
152             final IStatus[] result = new IStatus[] { null };
153             final ISchedulingRule schedulingRule = getSchedulingRule(targetProjects);
154             if (schedulingRule instanceof IResource && ((IResource)schedulingRule).getType() == IResource.ROOT) {
155                 // One of the projects is mapped to a provider that locks the workspace.
156
// Just return the workspace root rule
157
try {
158                     Job.getJobManager().beginRule(schedulingRule, pm);
159                     // Still use the projects as the inner rule so we get the proper batching of sync info write
160
EclipseSynchronizer.getInstance().run(MultiRule.combine(targetProjects), new ICVSRunnable() {
161                         public void run(IProgressMonitor monitor) throws CVSException {
162                             result[0] = performCheckout(session, resource, targetProjects, sendModuleName, monitor);
163                         }
164                     }, Policy.subMonitorFor(pm, 90));
165                 } finally {
166                     Job.getJobManager().endRule(schedulingRule);
167                 }
168             } else {
169                 EclipseSynchronizer.getInstance().run(schedulingRule, new ICVSRunnable() {
170                     public void run(IProgressMonitor monitor) throws CVSException {
171                         result[0] = performCheckout(session, resource, targetProjects, sendModuleName, monitor);
172                     }
173                 }, Policy.subMonitorFor(pm, 90));
174             }
175             String JavaDoc wsName = getWorkingSetName();
176             if (wsName != null){
177                 createWorkingSet(wsName, targetProjects);
178             }
179             return result[0];
180         } catch (CVSException e) {
181             // An exception occurred either during the module-expansion or checkout
182
// Since we were able to make a connection, return the status so the
183
// checkout of any other modules can proceed
184
return new CVSStatus(e.getStatus().getSeverity(), NLS.bind(CVSUIMessages.CheckoutProjectOperation_1, new String JavaDoc[] {resource.getRepositoryRelativePath(), e.getMessage()}), e);
185         } finally {
186             session.close();
187             pm.done();
188         }
189     }
190
191     private ISchedulingRule getSchedulingRule(IProject[] projects) {
192         if (projects.length == 1) {
193             return ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(projects[0]);
194         } else {
195             Set rules = new HashSet();
196             for (int i = 0; i < projects.length; i++) {
197                 ISchedulingRule modifyRule = ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(projects[i]);
198                 if (modifyRule instanceof IResource && ((IResource)modifyRule).getType() == IResource.ROOT) {
199                     // One of the projects is mapped to a provider that locks the workspace.
200
// Just return the workspace root rule
201
return modifyRule;
202                 }
203                 rules.add(modifyRule);
204             }
205             return new MultiRule((ISchedulingRule[]) rules.toArray(new ISchedulingRule[rules.size()]));
206         }
207     }
208
209     /* private */ IStatus performCheckout(Session session, ICVSRemoteFolder resource, IProject[] targetProjects, boolean sendModuleName, IProgressMonitor pm) throws CVSException {
210         // Set the task name of the progress monitor to let the user know
211
// which project we're on. Don't use subTask since that will be
212
// changed when the checkout command is run.
213
String JavaDoc taskName;
214         if (targetProjects.length == 1) {
215             taskName = NLS.bind(CVSUIMessages.CheckoutProjectOperation_8, new String JavaDoc[] { resource.getName(), targetProjects[0].getName() });
216         } else {
217             taskName = NLS.bind(CVSUIMessages.CheckoutProjectOperation_9, new String JavaDoc[] { resource.getName(), String.valueOf(targetProjects.length) });
218         }
219         pm.beginTask(taskName, 100);
220         pm.setTaskName(taskName);
221         Policy.checkCanceled(pm);
222         try {
223             // Scrub the local contents if requested
224
if (performScrubProjects()) {
225                 IStatus result = scrubProjects(resource, targetProjects, Policy.subMonitorFor(pm, 9));
226                 if (!result.isOK()) {
227                     return result;
228                 }
229             }
230                 
231             // Determine if t
232
// in which case we'll use -d to flatten the directory structure.
233
// Only flatten the directory structure if the folder is not a root folder
234
IProject project = null;
235             if (targetProjects.length == 1) {
236                 if (sendModuleName) {
237                     project = targetProjects[0];
238                 } else if (targetProjects[0].getName().equals(resource.getName())) {
239                     // The target project has the same name as the remote folder.
240
// If the repository relative path has multiple segments
241
// we will want to flatten the directory structure
242
String JavaDoc path = resource.getRepositoryRelativePath();
243                     if (!path.equals(FolderSyncInfo.VIRTUAL_DIRECTORY)
244                             && new Path(null, path).segmentCount() > 1) {
245                         project = targetProjects[0];
246                     }
247                 }
248             }
249             
250             try {
251                 // Build the local options
252
List localOptions = new ArrayList();
253                 // Add the option to load into the target project if one was supplied
254
if (project != null) {
255                     localOptions.add(Checkout.makeDirectoryNameOption(project.getName()));
256                 }
257                 // Prune empty directories if pruning enabled
258
if (CVSProviderPlugin.getPlugin().getPruneEmptyDirectories())
259                     localOptions.add(Command.PRUNE_EMPTY_DIRECTORIES);
260                 // Add the options related to the CVSTag
261
CVSTag tag = resource.getTag();
262                 if (tag == null) {
263                     // A null tag in a remote resource indicates HEAD
264
tag = CVSTag.DEFAULT;
265                 }
266                 localOptions.add(Update.makeTagOption(tag));
267                 if (!isRecursive())
268                     localOptions.add(Command.DO_NOT_RECURSE);
269                 
270                 // Perform the checkout
271
IStatus status = Command.CHECKOUT.execute(session,
272                     Command.NO_GLOBAL_OPTIONS,
273                     (LocalOption[])localOptions.toArray(new LocalOption[localOptions.size()]),
274                     new String JavaDoc[]{getRemoteModuleName(resource)},
275                     null,
276                     Policy.subMonitorFor(pm, 90));
277                 return status;
278             } finally {
279                 // Map the projects if they have CVS meta infomation even if a failure occurred
280
refreshProjects(targetProjects, Policy.subMonitorFor(pm, 1));
281             }
282         } finally {
283             pm.done();
284         }
285     }
286
287     protected boolean isRecursive() {
288         return true;
289     }
290
291     /*
292      * Determine the workspace project(s) that will be affected by the checkout.
293      * If project is not null, then it will be the only target project of the checkout.
294      * Otherwise, the remote folder could expand to multiple projects.
295      *
296      * If the remote resource is a folder which is not a root folder (i.e. a/b/c),
297      * then the target project will be the last segment (i.e. c).
298      */

299     private IProject[] determineProjects(Session session, final ICVSRemoteFolder remoteFolder, IProject project, IProgressMonitor pm) throws CVSException {
300             
301         Set targetProjectSet = new HashSet();
302         String JavaDoc moduleName = getRemoteModuleName(remoteFolder);
303         if (project == null) {
304             
305             // Fetch the module expansions
306
Policy.checkCanceled(pm);
307             IStatus status = Request.EXPAND_MODULES.execute(session, new String JavaDoc[] {moduleName}, pm);
308             if (status.getCode() == CVSStatus.SERVER_ERROR) {
309                 collectStatus(status);
310                 return null;
311             }
312             
313             // Convert the module expansions to local projects
314
String JavaDoc[] expansions = session.getModuleExpansions();
315             if (expansions.length == 1 && expansions[0].equals(moduleName)) {
316                 // For a remote folder, use the last segment as the project to be created
317
String JavaDoc lastSegment = new Path(null, expansions[0]).lastSegment();
318                 // if using metafile project name is preferred, use it
319
if (CVSUIPlugin.getPlugin().isUseProjectNameOnCheckout() && remoteFolder instanceof RemoteProjectFolder) {
320                     RemoteProjectFolder rpf = (RemoteProjectFolder) remoteFolder;
321                     if (rpf.hasProjectName()) {
322                         lastSegment = rpf.getProjectName();
323                     }
324                 }
325                 targetProjectSet.add(ResourcesPlugin.getWorkspace().getRoot().getProject(lastSegment));
326             } else {
327                 for (int j = 0; j < expansions.length; j++) {
328                     targetProjectSet.add(ResourcesPlugin.getWorkspace().getRoot().getProject(new Path(null, expansions[j]).segment(0)));
329                 }
330             }
331             
332         } else {
333             targetProjectSet.add(project);
334         }
335         
336         // Return the local projects affected by the checkout
337
IProject[] targetProjects = (IProject[]) targetProjectSet.toArray(new IProject[targetProjectSet.size()]);
338         return targetProjects;
339     }
340
341     /**
342      * Return true if the target projects should be scrubbed before the checkout occurs.
343      * Default is to scrub the projects. Can be overridden by subclasses.
344      */

345     protected boolean performScrubProjects() {
346         return true;
347     }
348
349     /*
350      * This method is invoked to scrub the local projects that are the check out target of
351      * a single remote module.
352      */

353     private IStatus scrubProjects(ICVSRemoteFolder remoteFolder, IProject[] projects, IProgressMonitor monitor) throws CVSException {
354         if (projects == null) {
355             monitor.done();
356             return OK;
357         }
358         // Prompt first before any work is done
359
if (projects.length > 1) {
360             setInvolvesMultipleResources(true);
361         }
362         for (int i=0;i<projects.length;i++) {
363             IProject project = projects[i];
364             Policy.checkCanceled(monitor);
365             if (needsPromptForOverwrite(project) && !promptToOverwrite(remoteFolder, project)) {
366                 // User said no to this project but not no to all
367
return new CVSStatus(IStatus.INFO, IStatus.CANCEL, NLS.bind(CVSUIMessages.CheckoutProjectOperation_0, new String JavaDoc[] { remoteFolder.getRepositoryRelativePath() }), remoteFolder);
368             }
369         }
370         // Create the projects and remove any previous content
371
monitor.beginTask(null, projects.length * 100);
372         for (int i=0;i<projects.length;i++) {
373             IProject project = projects[i];
374             createAndOpenProject(project, Policy.subMonitorFor(monitor, 10));
375             scrubProject(project, Policy.subMonitorFor(monitor, 90));
376         }
377         monitor.done();
378         return OK;
379     }
380
381     private void scrubProject(IProject project, IProgressMonitor monitor) throws CVSException {
382         try {
383             // unmap the project from any previous repository provider
384
if (RepositoryProvider.getProvider(project) != null)
385                 RepositoryProvider.unmap(project);
386             // We do not want to delete the project to avoid a project deletion delta
387
// We do not want to delete the .project to avoid core exceptions
388
IResource[] children = project.members(IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS);
389             Policy.checkCanceled(monitor);
390             monitor.beginTask(null, 100 + children.length * 100);
391             monitor.subTask(NLS.bind(CVSUIMessages.CheckoutOperation_scrubbingProject, new String JavaDoc[] { project.getName() })); //
392
try {
393                 for (int j = 0; j < children.length; j++) {
394                     if ( ! children[j].getName().equals(".project")) {//$NON-NLS-1$
395
children[j].delete(true /*force*/, Policy.subMonitorFor(monitor, 100));
396                     }
397                 }
398                 // Make sure there is no sync info cached for the project since
399
// a reader thread may have caused it to be loaded since the unmap.
400
EclipseSynchronizer.getInstance().flush(project, true, Policy.subMonitorFor(monitor, 100));
401             } finally {
402                 monitor.done();
403             }
404         } catch (TeamException e) {
405             throw CVSException.wrapException(e);
406         } catch (CoreException e) {
407             throw CVSException.wrapException(e);
408         }
409     }
410
411     protected boolean needsPromptForOverwrite(IProject project) {
412                 
413         // First, check the description location
414
IProjectDescription desc = getDescriptionFor(project);
415         if (desc != null) {
416             File JavaDoc localLocation = desc.getLocation().toFile();
417             if (localLocation.exists()) return true;
418         }
419                 
420         // Next, check if the resource itself exists
421
if (project.exists()) return true;
422                 
423         // Finally, check if the location in the workspace exists;
424
File JavaDoc localLocation = getFileLocation(project);
425         if (localLocation.exists()) return true;
426                 
427         // The target doesn't exist
428
return false;
429     }
430     
431     protected File JavaDoc getFileLocation(IProject project) {
432         return new File JavaDoc(project.getParent().getLocation().toFile(), project.getName());
433     }
434     
435     private boolean promptToOverwrite(ICVSRemoteFolder remoteFolder, IProject project) {
436         // First, if the project exists in the workspace, prompt
437
if (project.exists()) {
438             if (!promptToOverwrite(
439                     CVSUIMessages.CheckoutOperation_confirmOverwrite,
440                     NLS.bind(CVSUIMessages.CheckoutOperation_thisResourceExists, new String JavaDoc[] { project.getName(), getRemoteModuleName(remoteFolder) }),
441                     project)) {
442                 return false;
443             }
444         }
445         // Even if the project exists, check the target location
446
IPath path = getTargetLocationFor(project);
447         File JavaDoc localLocation = null;
448         if (path == null) {
449             try {
450                 // There is no custom location. However, still prompt
451
// if the project directory in the workspace directory
452
// would be overwritten.
453
if (!project.exists() || !project.isOpen() || project.getDescription().getLocation() != null) {
454                     localLocation = getFileLocation(project);
455                 }
456             } catch (CoreException e) {
457                 CVSUIPlugin.log(e);
458             }
459         } else {
460             localLocation = path.toFile();
461         }
462         if (localLocation != null && localLocation.exists()) {
463             try {
464                 return (promptToOverwrite(
465                         CVSUIMessages.CheckoutOperation_confirmOverwrite,
466                         NLS.bind(CVSUIMessages.CheckoutOperation_thisExternalFileExists, new String JavaDoc[] { localLocation.getCanonicalPath(), getRemoteModuleName(remoteFolder) }),
467                         project));
468             } catch (IOException JavaDoc e) {
469                 CVSUIPlugin.log(CVSException.wrapException(e));
470             }
471         }
472         return true;
473     }
474     
475     /*
476      * Bring the provied projects into the workspace
477      */

478     private void refreshProjects(IProject[] projects, IProgressMonitor monitor) throws CVSException {
479         monitor.beginTask(null, projects.length * 100);
480         try {
481             for (int i = 0; i < projects.length; i++) {
482                 IProject project = projects[i];
483                 // Register the project with Team
484
try {
485                     monitor.subTask(NLS.bind(CVSUIMessages.CheckoutOperation_refreshingProject, new String JavaDoc[] { project.getName() }));
486                     ICVSFolder folder = CVSWorkspaceRoot.getCVSFolderFor(project);
487                     if (folder.isCVSFolder()) {
488                         RepositoryProvider.map(project, CVSProviderPlugin.getTypeId());
489                     }
490                 } catch (TeamException e) {
491                     throw CVSException.wrapException(e);
492                 }
493                 CVSTeamProvider provider = (CVSTeamProvider)RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId());
494                 if (provider != null) {
495                     provider.setWatchEditEnabled(CVSProviderPlugin.getPlugin().isWatchEditEnabled());
496                 }
497             }
498         } finally {
499             monitor.done();
500         }
501     }
502
503     protected String JavaDoc getTaskName() {
504         ICVSRemoteFolder[] remoteFolders = getRemoteFolders();
505         if (remoteFolders.length == 1) {
506             return NLS.bind(CVSUIMessages.CheckoutSingleProjectOperation_taskname, new String JavaDoc[] { remoteFolders[0].getName() });
507         } else {
508             return NLS.bind(CVSUIMessages.CheckoutMultipleProjectsOperation_taskName, new String JavaDoc[] { new Integer JavaDoc(remoteFolders.length).toString() });
509         }
510     }
511     
512     /* private */ void createWorkingSet(String JavaDoc workingSetName, IProject[] projects) {
513         IWorkingSetManager manager = CVSUIPlugin.getPlugin().getWorkbench().getWorkingSetManager();
514         IWorkingSet oldSet = manager.getWorkingSet(workingSetName);
515         if (oldSet == null) {
516             IWorkingSet newSet = manager.createWorkingSet(workingSetName, projects);
517             newSet.setId(WorkingSetsDialog.resourceWorkingSetId);
518             manager.addWorkingSet(newSet);
519         } else {
520             //don't overwrite the old elements
521
IAdaptable[] tempElements = oldSet.getElements();
522             IAdaptable[] adaptedProjects = oldSet.adaptElements(projects);
523             IAdaptable[] finalElementList = new IAdaptable[tempElements.length + adaptedProjects.length];
524             System.arraycopy(tempElements, 0, finalElementList, 0, tempElements.length);
525             System.arraycopy(adaptedProjects, 0,finalElementList, tempElements.length, adaptedProjects.length);
526             oldSet.setElements(finalElementList);
527         }
528     }
529     
530     /*
531      * Returns the name of the working set to add the checked out projects to or null for none
532      */

533     protected String JavaDoc getWorkingSetName(){
534         return null;
535     }
536     
537 }
538
Popular Tags