KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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.internal.ccvs.ui.operations;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashSet JavaDoc;
15 import java.util.List JavaDoc;
16 import java.util.Set JavaDoc;
17
18 import org.eclipse.core.resources.*;
19 import org.eclipse.core.runtime.*;
20 import org.eclipse.core.runtime.jobs.ISchedulingRule;
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.ui.IWorkbenchPart;
33
34 /**
35  * This method checks out one or more remote folders from the same repository
36  * into an existing project or folder in the workspace. The target project
37  * must either be shared with the same repository or it must not be shared
38  * with any repository
39  */

40 public class CheckoutIntoOperation extends CheckoutOperation {
41
42     private boolean recursive;
43     private ICVSFolder localFolder;
44     private String JavaDoc localFolderName;
45
46     /**
47      * Constructor which takes a set of remote folders and the local folder into which the folders should be
48      * loaded.
49      */

50     public CheckoutIntoOperation(IWorkbenchPart part, ICVSRemoteFolder[] remoteFolders, IContainer localFolder, boolean recursive) {
51         super(part, remoteFolders);
52         this.recursive = recursive;
53         this.localFolder = CVSWorkspaceRoot.getCVSFolderFor(localFolder);
54     }
55
56     /**
57      * Constructor which takes a single remote folder and the target local folder.
58      */

59     public CheckoutIntoOperation(IWorkbenchPart part, ICVSRemoteFolder remoteFolder, IContainer localFolder, boolean recursive) {
60         this(part, new ICVSRemoteFolder[] { remoteFolder }, localFolder.getParent(), recursive);
61         this.localFolderName = localFolder.getName();
62     }
63     
64     /* (non-Javadoc)
65      * @see org.eclipse.team.internal.ccvs.ui.operations.CheckoutOperation#getTaskName()
66      */

67     protected String JavaDoc getTaskName() {
68         ICVSRemoteFolder[] remoteFolders = getRemoteFolders();
69         String JavaDoc localFolderName = ""; //$NON-NLS-1$
70
localFolderName = getLocalFolder().getIResource().getFullPath().toString();
71         return NLS.bind(CVSUIMessages.CheckoutIntoOperation_taskname, new String JavaDoc[] { new Integer JavaDoc(remoteFolders.length).toString(), localFolderName });
72     }
73
74     /**
75      * @return
76      */

77     public ICVSFolder getLocalFolder() {
78         return localFolder;
79     }
80     
81     /**
82      * @return
83      */

84     public boolean isRecursive() {
85         return recursive;
86     }
87     
88     /* (non-Javadoc)
89      * @see org.eclipse.team.internal.ccvs.ui.operations.CheckoutOperation#checkout(org.eclipse.team.internal.ccvs.core.ICVSRemoteFolder, org.eclipse.core.runtime.IProgressMonitor)
90      */

91     protected IStatus checkout(final ICVSRemoteFolder folder, IProgressMonitor monitor) throws CVSException {
92         final IStatus[] result = new IStatus[] { null };
93         try {
94             // Wrap in a workspace runnable to avoid auto-build.
95
// This is necessary because CVS has a POST_BUILD
96
// listener that will clear the sync info from
97
// orphaned (i.e. unmanaged) subtrees and we will
98
// purposely create some which we subsequently manage
99
// from their parent (see manageFolders())
100
ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() {
101                 public void run(IProgressMonitor monitor) throws CoreException {
102                     result[0] = checkout(folder, getLocalFolder(), isRecursive(), monitor);
103                 }
104             }, getSchedulingRule(), 0, monitor);
105         } catch (CoreException e) {
106             result[0] = CVSException.wrapException(e).getStatus();
107         }
108         return result[0];
109     }
110     
111     /* (non-Javadoc)
112      * @see org.eclipse.team.internal.ccvs.ui.operations.CheckoutOperation#checkout(org.eclipse.team.internal.ccvs.core.ICVSRemoteFolder[], org.eclipse.core.runtime.IProgressMonitor)
113      */

114     protected void checkout(final ICVSRemoteFolder[] folders, IProgressMonitor monitor) throws CVSException {
115         // Batch sync info changes with the CVS synchronizer to optimize cache writing
116
EclipseSynchronizer.getInstance().run(getSchedulingRule(), new ICVSRunnable() {
117             public void run(IProgressMonitor monitor) throws CVSException {
118                 monitor.beginTask(null, 100);
119                 try {
120                     // Obtain a scheduling rule on the projects were about to overwrite
121
CheckoutIntoOperation.super.checkout(folders, Policy.subMonitorFor(monitor, 90));
122                     refreshRoot(getLocalRoot(getLocalFolder()), Policy.subMonitorFor(monitor, 10));
123                 } finally {
124                     monitor.done();
125                 }
126             }
127         }, Policy.monitorFor(monitor));
128     }
129     
130     /*
131      * Prepare the local folders to receive the remote folders. If localFolderName is not null, then
132      * if will be the only target folder of the checkout. Otherwise, the remote folder
133      * could expand to multiple local folders witinb the given parent folder.
134      */

135     private ICVSFolder[] prepareLocalFolders(Session session, ICVSRemoteFolder remoteFolder, ICVSFolder parentFolder, String JavaDoc localFolderName, IProgressMonitor monitor) throws CVSException {
136         Set JavaDoc targetFolderSet = new HashSet JavaDoc();
137         monitor.beginTask(null, 30);
138         if (localFolderName == null) {
139             
140             // Determine which local folders will be afected
141
IStatus status = Request.EXPAND_MODULES.execute(session, new String JavaDoc[] { remoteFolder.getRepositoryRelativePath()}, Policy.subMonitorFor(monitor, 10));
142             if (status.getCode() == CVSStatus.SERVER_ERROR) {
143                 addError(status);
144                 return null;
145             }
146             
147             // Convert the module expansions to target folders
148
String JavaDoc[] expansions = session.getModuleExpansions();
149             for (int j = 0; j < expansions.length; j++) {
150                 String JavaDoc childPath = new Path(null, expansions[j]).segment(0);
151                 ICVSResource resource = parentFolder.getChild(childPath);
152                 if (resource != null && !resource.isFolder()) {
153                     // The target folder conflicts with an existing file
154
addError(new CVSStatus(IStatus.ERROR, NLS.bind(CVSUIMessages.CheckoutIntoOperation_targetIsFile, new String JavaDoc[] { remoteFolder.getName(), resource.getIResource().getFullPath().toString() })));
155                     return null;
156                 }
157                 targetFolderSet.add(parentFolder.getFolder(childPath));
158             }
159             
160         } else {
161             targetFolderSet.add(parentFolder.getFolder(localFolderName));
162         }
163         
164         final ICVSFolder[] targetFolders = (ICVSFolder[]) targetFolderSet.toArray(new ICVSFolder[targetFolderSet.size()]);
165         
166         // Ensure that the checkout will not conflict with existing resources
167
IStatus status = validateTargetFolders(remoteFolder, targetFolders, Policy.subMonitorFor(monitor, 10));
168         if (!status.isOK()) {
169             addError(status);
170             return null;
171         }
172         
173         // Prepare the target projects to receive resources
174
status = scrubFolders(remoteFolder, targetFolders, Policy.subMonitorFor(monitor, 10));
175         // return the target projects if the scrub succeeded
176
if (status.isOK()) {
177             return targetFolders;
178         } else {
179             addError(status);
180             return null;
181         }
182     }
183     
184     /*
185      * Ensure that the new folders will not conflict with existing folders (even those that are pruned).
186      */

187     private IStatus validateTargetFolders(ICVSRemoteFolder remoteFolder, ICVSFolder[] targetFolders, IProgressMonitor monitor) throws CVSException {
188         for (int i = 0; i < targetFolders.length; i++) {
189             ICVSFolder targetFolder = targetFolders[i];
190             FolderSyncInfo localInfo = targetFolder.getFolderSyncInfo();
191             FolderSyncInfo remoteInfo = remoteFolder.getFolderSyncInfo();
192             
193             if (!remoteInfo.isSameMapping(localInfo)) {
194                 if (localInfo != null ) {
195                     if (isRemoteChildOfParent(targetFolder)) {
196                         // if the local folder is child of it's parent remotely (i.e. path of child is parent/child)
197
// then the remote cannot be loaded.
198
String JavaDoc message;
199                         if (targetFolder.exists()) {
200                             message = NLS.bind(CVSUIMessages.CheckoutIntoOperation_targetIsFolder, new String JavaDoc[] { remoteFolder.getName(), targetFolder.getIResource().getFullPath().toString() });
201                         } else {
202                             message = NLS.bind(CVSUIMessages.CheckoutIntoOperation_targetIsPrunedFolder, new String JavaDoc[] { remoteFolder.getName(), targetFolder.getFolderSyncInfo().getRepository() });
203                         }
204                         return new CVSStatus(IStatus.ERROR, message);
205                     }
206                 }
207                 // Verify that no other folders in the local workspace are mapped to the remote folder
208
IStatus status = validateUniqueMapping(remoteFolder, targetFolder, Policy.subMonitorFor(monitor, 10));
209                 if (!status.isOK()) return status;
210             }
211         }
212         return OK;
213     }
214
215     /*
216      * Return true if the given local folder is a direct descendant of it's local parent in
217      * the repository as well
218      */

219     private boolean isRemoteChildOfParent(ICVSFolder targetFolder) throws CVSException {
220         FolderSyncInfo localInfo = targetFolder.getFolderSyncInfo();
221         if (localInfo == null) return false;
222         FolderSyncInfo parentInfo = targetFolder.getParent().getFolderSyncInfo();
223         if (parentInfo == null) return false;
224         IPath childPath = new Path(null, localInfo.getRepository());
225         IPath parentPath = new Path(null, parentInfo.getRepository());
226         return parentPath.isPrefixOf(childPath);
227     }
228
229     /**
230      * @param targetFolder
231      * @return
232      */

233     private IContainer getLocalRoot(ICVSFolder targetFolder) throws CVSException {
234         return targetFolder.getIResource().getProject();
235     }
236
237     /*
238      * Ensure that there is no equivalent mapping alreay in the local workspace
239      */

240     private IStatus validateUniqueMapping(final ICVSRemoteFolder remoteFolder, final ICVSFolder targetFolder, IProgressMonitor iProgressMonitor) throws CVSException {
241         
242         final IContainer root = getLocalRoot(targetFolder);
243         final FolderSyncInfo remoteInfo = remoteFolder.getFolderSyncInfo();
244         if (remoteInfo.equals(FolderSyncInfo.VIRTUAL_DIRECTORY)) {
245             // We can't really check the mapping ahead of time
246
// so we'll let the operation continue
247
return OK;
248         }
249         ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(root);
250         try {
251             cvsFolder.accept(new ICVSResourceVisitor() {
252                 public void visitFile(ICVSFile file) throws CVSException {
253                     // do nothing
254
}
255                 public void visitFolder(ICVSFolder folder) throws CVSException {
256                     if (!folder.isCVSFolder()) return;
257                     IResource resource = folder.getIResource();
258                     if (resource == null) return;
259                     FolderSyncInfo info = folder.getFolderSyncInfo();
260                     if (info.isSameMapping(remoteInfo)) {
261                         throw new CVSException(NLS.bind(CVSUIMessages.CheckoutIntoOperation_mappingAlreadyExists, (new Object JavaDoc[] {
262                             remoteFolder.getName(),
263                             targetFolder.getIResource().getFullPath().toString(),
264                             resource.getFullPath().toString()
265                         })));
266                     }
267                     folder.acceptChildren(this);
268                 }
269             });
270         } catch (CVSException e) {
271             return e.getStatus();
272         }
273         return OK;
274     }
275     
276     /*
277      * Purge the local contents of the given folders
278      */

279     private IStatus scrubFolders(ICVSRemoteFolder remoteFolder, ICVSFolder[] targetFolders, IProgressMonitor monitor) throws CVSException {
280         monitor.beginTask(null, 100 * targetFolders.length);
281         
282         // Prompt first before any work is done
283
if (targetFolders.length > 1) {
284             setInvolvesMultipleResources(true);
285         }
286         for (int i=0;i<targetFolders.length;i++) {
287             ICVSFolder targetFolder = targetFolders[i];
288             if (needsPromptForOverwrite(targetFolder, Policy.subMonitorFor(monitor, 50)) && !promptToOverwrite(targetFolder)) {
289                 return new CVSStatus(IStatus.INFO, NLS.bind(CVSUIMessages.CheckoutIntoOperation_cancelled, new String JavaDoc[] { remoteFolder.getName() }));
290             }
291         }
292         
293         for (int i = 0; i < targetFolders.length; i++) {
294             IStatus status = scrubFolder(targetFolders[i], Policy.subMonitorFor(monitor, 50));
295             if (!status.isOK()) return status;
296         }
297         monitor.done();
298         return OK;
299     }
300
301     private boolean needsPromptForOverwrite(ICVSFolder targetFolder, IProgressMonitor monitor) throws CVSException {
302         return targetFolder.isModified(monitor);
303     }
304
305     private boolean promptToOverwrite(ICVSFolder folder) {
306         return promptToOverwrite(
307             CVSUIMessages.CheckoutOperation_confirmOverwrite,
308             NLS.bind(CVSUIMessages.CheckoutIntoOperation_overwriteMessage, new String JavaDoc[] { folder.getName() }),
309             folder.getIResource());
310     }
311     
312     private IStatus scrubFolder(ICVSFolder folder, IProgressMonitor monitor) throws CVSException {
313         if (folder.exists() || folder.isCVSFolder()) {
314             // Unmanage first so we don't get outgoing deletions
315
folder.unmanage(Policy.subMonitorFor(monitor, 50));
316             if (folder.exists()) folder.delete();
317         }
318         return OK;
319     }
320
321     /* private */ IStatus checkout(final ICVSRemoteFolder remoteFolder, ICVSFolder parentFolder, boolean recurse, IProgressMonitor monitor) throws CVSException {
322         // Open a connection session to the repository
323
monitor.beginTask(null, 100);
324         ICVSRepositoryLocation repository = remoteFolder.getRepository();
325         Session session = new Session(repository, parentFolder);
326         try {
327             session.open(Policy.subMonitorFor(monitor, 5), false /* read-only */);
328             
329             // Determine which local folders will be affected
330
String JavaDoc localName = localFolderName;
331             if (localName == null) {
332                 IPath path = new Path(null, remoteFolder.getRepositoryRelativePath());
333                 if (path.segmentCount() > 1) {
334                     localName = path.lastSegment();
335                 }
336             }
337             ICVSFolder[] targetFolders = prepareLocalFolders(session, remoteFolder, parentFolder, localName, Policy.subMonitorFor(monitor, 5));
338             if (targetFolders == null) {
339                 // an error occured and has been added to the operation's error list
340
return getLastError();
341             }
342             
343             // Add recurse option
344
List JavaDoc localOptions = new ArrayList JavaDoc();
345             if (!recurse)
346                 localOptions.add(Command.DO_NOT_RECURSE);
347             if (localName != null) {
348                 localOptions.add(Checkout.makeDirectoryNameOption(localName));
349             }
350             
351             // Prune empty directories if pruning enabled
352
if (CVSProviderPlugin.getPlugin().getPruneEmptyDirectories())
353                 localOptions.add(Command.PRUNE_EMPTY_DIRECTORIES);
354             // Add the options related to the CVSTag
355
CVSTag tag = remoteFolder.getTag();
356             if (tag == null) {
357                 // A null tag in a remote resource indicates HEAD
358
tag = CVSTag.DEFAULT;
359             }
360             localOptions.add(Update.makeTagOption(tag));
361             
362             // Perform the checkout
363
IStatus status = Command.CHECKOUT.execute(session,
364                 Command.NO_GLOBAL_OPTIONS,
365                 (LocalOption[])localOptions.toArray(new LocalOption[localOptions.size()]),
366                 new String JavaDoc[] { remoteFolder.getRepositoryRelativePath() },
367                 null,
368                 Policy.subMonitorFor(monitor, 80));
369             if (!status.isOK()) {
370                 return status;
371             }
372             
373             manageFolders(targetFolders, repository.getLocation(false));
374             
375             return OK;
376             
377         } finally {
378             session.close();
379         }
380     }
381
382     private void manageFolders(ICVSFolder[] targetFolders, String JavaDoc root) throws CVSException {
383         for (int i = 0; i < targetFolders.length; i++) {
384             manageFolder(targetFolders[i], root);
385         }
386     }
387     
388     private static void manageFolder(ICVSFolder folder, String JavaDoc root) throws CVSException {
389         // Ensure that the parent is a CVS folder
390
ICVSFolder parent = folder.getParent();
391         if (!parent.isCVSFolder()) {
392             parent.setFolderSyncInfo(new FolderSyncInfo(FolderSyncInfo.VIRTUAL_DIRECTORY, root, CVSTag.DEFAULT, true));
393             IResource resource = parent.getIResource();
394             if (resource.getType() != IResource.PROJECT) {
395                 manageFolder(parent, root);
396             }
397         }
398         // reset the folder sync info so it will be managed by it's parent
399
folder.setFolderSyncInfo(folder.getFolderSyncInfo());
400     }
401
402     /*
403      * Bring the provided projects into the workspace
404      */

405     private static void refreshRoot(IContainer root, IProgressMonitor monitor) throws CVSException {
406             try {
407                 IProject project = root.getProject();
408                 CVSTeamProvider provider = (CVSTeamProvider)RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId());
409                 if (provider == null) {
410                     ICVSFolder folder = CVSWorkspaceRoot.getCVSFolderFor(project);
411                     if (folder.isCVSFolder()) {
412                         // Register the project with Team
413
RepositoryProvider.map(project, CVSProviderPlugin.getTypeId());
414                         
415                         // TODO: This should be somewhere else
416
provider = (CVSTeamProvider)RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId());
417                         provider.setWatchEditEnabled(CVSProviderPlugin.getPlugin().isWatchEditEnabled());
418                     }
419                 }
420             } catch (TeamException e) {
421                 throw CVSException.wrapException(e);
422             }
423     }
424     
425     /* (non-Javadoc)
426      * @see org.eclipse.team.internal.ccvs.ui.operations.CVSOperation#getSchedulingRule()
427      */

428     protected ISchedulingRule getSchedulingRule() {
429         //use the modfiy rule for the time being
430
//TODO: Just lock the project not the entire workspace (so can't use modifyRule)
431
//since the project already exists
432
IProject tempProject = getLocalFolder().getIResource().getProject();
433          IResourceRuleFactory ruleFactory = ResourcesPlugin.getWorkspace().getRuleFactory();
434          return ruleFactory.modifyRule(tempProject);
435     }
436
437 }
438
Popular Tags