KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > ccvs > ui > subscriber > CVSSubscriberOperation


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.internal.ccvs.ui.subscriber;
12
13 import java.lang.reflect.InvocationTargetException JavaDoc;
14 import java.util.ArrayList JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19
20 import org.eclipse.compare.structuremergeviewer.IDiffElement;
21 import org.eclipse.core.resources.IContainer;
22 import org.eclipse.core.resources.IFile;
23 import org.eclipse.core.resources.IProject;
24 import org.eclipse.core.resources.IResource;
25 import org.eclipse.core.resources.ResourcesPlugin;
26 import org.eclipse.core.runtime.CoreException;
27 import org.eclipse.core.runtime.IProgressMonitor;
28 import org.eclipse.core.runtime.IStatus;
29 import org.eclipse.jface.window.Window;
30 import org.eclipse.osgi.util.NLS;
31 import org.eclipse.team.internal.ccvs.core.CVSStatus;
32 import org.eclipse.team.core.TeamException;
33 import org.eclipse.team.core.synchronize.SyncInfo;
34 import org.eclipse.team.core.synchronize.SyncInfoSet;
35 import org.eclipse.team.core.variants.IResourceVariant;
36 import org.eclipse.team.internal.ccvs.core.*;
37 import org.eclipse.team.internal.ccvs.core.client.PruneFolderVisitor;
38 import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
39 import org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer;
40 import org.eclipse.team.internal.ccvs.ui.*;
41 import org.eclipse.team.internal.ccvs.ui.Policy;
42 import org.eclipse.team.internal.ui.TeamUIPlugin;
43 import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration;
44 import org.eclipse.team.ui.synchronize.SynchronizeModelOperation;
45
46 public abstract class CVSSubscriberOperation extends SynchronizeModelOperation {
47     
48     protected CVSSubscriberOperation(ISynchronizePageConfiguration configuration, IDiffElement[] elements) {
49         super(configuration, elements);
50     }
51
52     /* (non-Javadoc)
53      * @see org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core.runtime.IProgressMonitor)
54      */

55     public void run(IProgressMonitor monitor) throws InvocationTargetException JavaDoc, InterruptedException JavaDoc {
56         // Divide the sync info by project
57
final Map JavaDoc projectSyncInfos = getProjectSyncInfoSetMap();
58         monitor.beginTask(null, projectSyncInfos.size() * 100);
59         for (Iterator JavaDoc iter = projectSyncInfos.keySet().iterator(); iter.hasNext(); ) {
60             final IProject project = (IProject) iter.next();
61             run(projectSyncInfos, project, monitor);
62         }
63         monitor.done();
64     }
65
66     /**
67      * Run the operation for the sync infos from the given project. By default, a lock
68      * is acquired on the project.
69      * @param projectSyncInfos the project syncInfos
70      * @param project the project
71      * @param monitor a progress monitor
72      * @throws InvocationTargetException
73      */

74     protected void run(final Map JavaDoc projectSyncInfos, final IProject project, IProgressMonitor monitor) throws InvocationTargetException JavaDoc {
75         try {
76             // Pass the scheduling rule to the synchronizer so that sync change events
77
// and cache commits to disk are batched
78
EclipseSynchronizer.getInstance().run(
79                 project,
80                 new ICVSRunnable() {
81                     public void run(IProgressMonitor monitor) throws CVSException {
82                         try {
83                             CVSSubscriberOperation.this.runWithProjectRule(project, (SyncInfoSet)projectSyncInfos.get(project), monitor);
84                         } catch (TeamException e) {
85                             throw CVSException.wrapException(e);
86                         }
87                     }
88                 }, Policy.subMonitorFor(monitor, 100));
89         } catch (TeamException e) {
90             throw new InvocationTargetException JavaDoc(e);
91         }
92     }
93
94     /**
95      * Run the operation on the sync info in the given set. The sync info will be all
96      * from the same project. Also, a scheduling rule on the project will be
97      * held when this method is invoked.
98      * @param project the project that contaisn the sync info.
99      * @param set the sync info set
100      * @param monitor a progress monitor
101      */

102     protected abstract void runWithProjectRule(IProject project, SyncInfoSet set, IProgressMonitor monitor) throws TeamException;
103
104     /*
105      * Indicate that the resource is out of sync if the sync state is not IN_SYNC
106      * or if the local doesn't exist but the remote does.
107      */

108     protected boolean isOutOfSync(SyncInfo resource) {
109         if (resource == null) return false;
110         return (!(resource.getKind() == 0) ||
111                 (! resource.getLocal().exists() && resource.getRemote() != null));
112     }
113     
114     protected void makeInSync(SyncInfo[] folders, IProgressMonitor monitor) throws TeamException {
115         // If a node has a parent that is an incoming folder creation, we have to
116
// create that folder locally and set its sync info before we can get the
117
// node itself. We must do this for all incoming folder creations (recursively)
118
// in the case where there are multiple levels of incoming folder creations.
119
monitor.beginTask(null, folders.length);
120         for (int i = 0; i < folders.length; i++) {
121             SyncInfo resource = folders[i];
122             makeInSync(resource);
123             monitor.worked(1);
124         }
125         monitor.done();
126     }
127     
128     protected boolean makeInSync(SyncInfo info) throws TeamException {
129         if (isOutOfSync(info)) {
130             SyncInfo parent = getParent(info);
131             if (parent == null) {
132                 if (info.getLocal().getType() == IResource.ROOT) {
133                     // ROOT should be null
134
return true;
135                 } else {
136                     // No other ancestors should be null. Log the problem.
137
CVSUIPlugin.log(IStatus.WARNING, NLS.bind(CVSUIMessages.CVSSubscriberAction_0, new String JavaDoc[] { info.getLocal().getFullPath().toString() }), null);
138                     return false;
139                 }
140             } else {
141                 if (!makeInSync(parent)) {
142                     // The failed makeInSync will log any errors
143
return false;
144                 }
145             }
146             if (info instanceof CVSSyncInfo) {
147                 CVSSyncInfo cvsInfo= (CVSSyncInfo) info;
148                 IStatus status = cvsInfo.makeInSync();
149                 if (status.getSeverity() == IStatus.ERROR) {
150                     logError(status);
151                     return false;
152                 }
153                 return true;
154             }
155             return false;
156         } else {
157             return true;
158         }
159     }
160     
161     protected void makeOutgoing(SyncInfo[] folders, IProgressMonitor monitor) throws TeamException {
162         // If a node has a parent that is an incoming folder creation, we have to
163
// create that folder locally and set its sync info before we can get the
164
// node itself. We must do this for all incoming folder creations (recursively)
165
// in the case where there are multiple levels of incoming folder creations.
166
monitor.beginTask(null, 100 * folders.length);
167         for (int i = 0; i < folders.length; i++) {
168             SyncInfo info = folders[i];
169             makeOutgoing(info, Policy.subMonitorFor(monitor, 100));
170         }
171         monitor.done();
172     }
173     
174     private void makeOutgoing(SyncInfo info, IProgressMonitor monitor) throws TeamException {
175         if (info == null) return;
176         if (info instanceof CVSSyncInfo) {
177             CVSSyncInfo cvsInfo= (CVSSyncInfo) info;
178             IStatus status = cvsInfo.makeOutgoing(monitor);
179             if (status.getSeverity() == IStatus.ERROR) {
180                 logError(status);
181             }
182         }
183     }
184
185     /**
186      * Log an error associated with an operation.
187      * @param status
188      */

189     protected void logError(IStatus status) {
190         CVSUIPlugin.log(status);
191     }
192
193     /**
194      * Handle the exception by showing an error dialog to the user.
195      * Sync actions seem to need to be sync-execed to work
196      * @param t
197      */

198     protected void handle(Exception JavaDoc t) {
199         CVSUIPlugin.openError(getShell(), getErrorTitle(), null, t, CVSUIPlugin.PERFORM_SYNC_EXEC | CVSUIPlugin.LOG_NONTEAM_EXCEPTIONS);
200     }
201
202     /**
203      * Return the error title that will appear in any error dialogs shown to the user
204      * @return
205      */

206     protected String JavaDoc getErrorTitle() {
207         return null;
208     }
209
210     protected boolean canRunAsJob() {
211         return true;
212     }
213     
214     protected void pruneEmptyParents(SyncInfo[] nodes) throws CVSException {
215         // TODO: A more explicit tie in to the pruning mechanism would be prefereable.
216
// i.e. I don't like referencing the option and visitor directly
217
if (!CVSProviderPlugin.getPlugin().getPruneEmptyDirectories()) return;
218         ICVSResource[] cvsResources = new ICVSResource[nodes.length];
219         for (int i = 0; i < cvsResources.length; i++) {
220             cvsResources[i] = CVSWorkspaceRoot.getCVSResourceFor(nodes[i].getLocal());
221         }
222         new PruneFolderVisitor().visit(
223             CVSWorkspaceRoot.getCVSFolderFor(ResourcesPlugin.getWorkspace().getRoot()),
224             cvsResources);
225     }
226     
227     public CVSSyncInfo getCVSSyncInfo(SyncInfo info) {
228         if (info instanceof CVSSyncInfo) {
229             return (CVSSyncInfo)info;
230         }
231         return null;
232     }
233     
234     protected SyncInfo getParent(SyncInfo info) throws TeamException {
235         return ((CVSSyncInfo)info).getSubscriber().getSyncInfo(info.getLocal().getParent());
236     }
237
238     protected IResource[] getIResourcesFrom(SyncInfo[] nodes) {
239         List JavaDoc resources = new ArrayList JavaDoc(nodes.length);
240         for (int i = 0; i < nodes.length; i++) {
241             resources.add(nodes[i].getLocal());
242         }
243         return (IResource[]) resources.toArray(new IResource[resources.size()]);
244     }
245
246     /**
247      * Prompt to overwrite those resources that could not be safely updated
248      * Note: This method is designed to be overridden by test cases.
249      *
250      * @return whether to perform the overwrite
251      */

252     protected boolean promptForOverwrite(final SyncInfoSet syncSet) {
253         final int[] result = new int[] {Window.CANCEL};
254         TeamUIPlugin.getStandardDisplay().syncExec(new Runnable JavaDoc() {
255             public void run() {
256                 UpdateDialog dialog = new UpdateDialog(getShell(), syncSet);
257                 result[0] = dialog.open();
258             }
259         });
260         return (result[0] == UpdateDialog.YES);
261     }
262     
263     /**
264      * Make the contents of the local resource match that of the remote
265      * without modifying the sync info of the local resource.
266      * If called on a new folder, the sync info will be copied.
267      */

268     protected void makeRemoteLocal(SyncInfo info, IProgressMonitor monitor) throws TeamException {
269         IResourceVariant remote = info.getRemote();
270         IResource local = info.getLocal();
271         try {
272             if(remote==null) {
273                 if (local.exists()) {
274                     local.delete(IResource.KEEP_HISTORY, monitor);
275                 }
276             } else {
277                 if(remote.isContainer()) {
278                     ensureContainerExists(info);
279                 } else {
280                     monitor.beginTask(null, 200);
281                     try {
282                         IFile localFile = (IFile)local;
283                         if(local.exists()) {
284                             localFile.setContents(remote.getStorage(Policy.subMonitorFor(monitor, 100)).getContents(), false /*don't force*/, true /*keep history*/, Policy.subMonitorFor(monitor, 100));
285                         } else {
286                             ensureContainerExists(getParent(info));
287                             localFile.create(remote.getStorage(Policy.subMonitorFor(monitor, 100)).getContents(), false /*don't force*/, Policy.subMonitorFor(monitor, 100));
288                         }
289                     } finally {
290                         monitor.done();
291                     }
292                 }
293             }
294         } catch(CoreException e) {
295             IStatus status = new CVSStatus(IStatus.ERROR, CVSStatus.ERROR, CVSUIMessages.UpdateMergeActionProblems_merging_remote_resources_into_workspace_1,e, local);
296             throw new CVSException(status);
297         }
298     }
299     
300     private boolean ensureContainerExists(SyncInfo info) throws TeamException {
301         IResource local = info.getLocal();
302         // make sure that the parent exists
303
if (!local.exists()) {
304             if (!ensureContainerExists(getParent(info))) {
305                 return false;
306             }
307         }
308         // make sure that the folder sync info is set;
309
if (isOutOfSync(info)) {
310             if (info instanceof CVSSyncInfo) {
311                 CVSSyncInfo cvsInfo = (CVSSyncInfo)info;
312                 IStatus status = cvsInfo.makeInSync();
313                 if (status.getSeverity() == IStatus.ERROR) {
314                     logError(status);
315                     return false;
316                 }
317             }
318         }
319         // create the folder if it doesn't exist
320
ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor((IContainer)local);
321         if (!cvsFolder.exists()) {
322             cvsFolder.mkdir();
323         }
324         return true;
325     }
326     
327     /*
328      * Divide the sync info for the operation by project
329      */

330     private Map JavaDoc getProjectSyncInfoSetMap() {
331         Map JavaDoc map = new HashMap JavaDoc();
332         SyncInfoSet all = getSyncInfoSet();
333         SyncInfo[] infos = all.getSyncInfos();
334         for (int i = 0; i < infos.length; i++) {
335             SyncInfo info = infos[i];
336             IProject project = info.getLocal().getProject();
337             SyncInfoSet set = (SyncInfoSet)map.get(project);
338             if (set == null) {
339                 set = new SyncInfoSet();
340                 map.put(project, set);
341             }
342             set.add(info);
343         }
344         return map;
345     }
346 }
347
Popular Tags