KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > versioning > system > cvss > ui > actions > diff > ResolveConflictsExecutor


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.versioning.system.cvss.ui.actions.diff;
21
22 import java.io.BufferedReader JavaDoc;
23 import java.io.BufferedWriter JavaDoc;
24 import java.io.File JavaDoc;
25 import java.io.FileInputStream JavaDoc;
26 import java.io.FileReader JavaDoc;
27 import java.io.FileWriter JavaDoc;
28 import java.io.FilterWriter JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.io.InputStreamReader JavaDoc;
31 import java.io.Reader JavaDoc;
32 import java.io.Writer JavaDoc;
33 import java.util.ArrayList JavaDoc;
34 import java.util.Set JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.awt.*;
37 import org.netbeans.lib.cvsclient.file.*;
38
39 import org.openide.DialogDisplayer;
40 import org.openide.ErrorManager;
41 import org.openide.windows.TopComponent;
42 import org.openide.filesystems.FileLock;
43 import org.openide.filesystems.FileObject;
44 import org.openide.filesystems.FileUtil;
45 import org.openide.filesystems.FileAlreadyLockedException;
46 import org.openide.util.Lookup;
47
48 import org.netbeans.api.diff.Difference;
49 import org.netbeans.api.diff.StreamSource;
50 import org.netbeans.spi.diff.MergeVisualizer;
51 import org.netbeans.modules.diff.EncodedReaderFactory;
52
53 import javax.swing.*;
54
55 /**
56  * This class is used to resolve merge conflicts in a graphical way using a merge visualizer.
57  * We parse the file with merge conflicts marked, let the conflicts resolve by the
58  * visual merging tool and after successfull conflicts resolution save it back
59  * to the original file.
60  *
61  * @author Martin Entlicher
62  */

63 public class ResolveConflictsExecutor {
64     
65     private static final String JavaDoc TMP_PREFIX = "merge"; // NOI18N
66

67     static final String JavaDoc CHANGE_LEFT = "<<<<<<< "; // NOI18N
68
static final String JavaDoc CHANGE_RIGHT = ">>>>>>> "; // NOI18N
69
static final String JavaDoc CHANGE_DELIMETER = "======="; // NOI18N
70

71     private String JavaDoc leftFileRevision = null;
72     private String JavaDoc rightFileRevision = null;
73
74     public void exec(File JavaDoc file) {
75         assert SwingUtilities.isEventDispatchThread();
76         MergeVisualizer merge = (MergeVisualizer) Lookup.getDefault().lookup(MergeVisualizer.class);
77         if (merge == null) {
78             throw new IllegalStateException JavaDoc("No Merge engine found."); // NOI18N
79
}
80         
81         try {
82             FileObject fo = FileUtil.toFileObject(file);
83             handleMergeFor(file, fo, fo.lock(), merge);
84         } catch (FileAlreadyLockedException e) {
85             Set JavaDoc components = TopComponent.getRegistry().getOpened();
86             for (Iterator JavaDoc i = components.iterator(); i.hasNext();) {
87                 TopComponent tc = (TopComponent) i.next();
88                 if (tc.getClientProperty(ResolveConflictsExecutor.class.getName()) != null) {
89                     tc.requestActive();
90                 }
91             }
92         } catch (IOException JavaDoc ioex) {
93             org.openide.ErrorManager.getDefault().notify(ioex);
94         }
95     }
96     
97     private void handleMergeFor(final File JavaDoc file, FileObject fo, FileLock lock,
98                                 final MergeVisualizer merge) throws IOException JavaDoc {
99         String JavaDoc mimeType = (fo == null) ? "text/plain" : fo.getMIMEType(); // NOI18N
100
String JavaDoc ext = "."+fo.getExt(); // NOI18N
101
File JavaDoc f1 = FileUtil.normalizeFile(File.createTempFile(TMP_PREFIX, ext));
102         File JavaDoc f2 = FileUtil.normalizeFile(File.createTempFile(TMP_PREFIX, ext));
103         File JavaDoc f3 = FileUtil.normalizeFile(File.createTempFile(TMP_PREFIX, ext));
104         f1.deleteOnExit();
105         f2.deleteOnExit();
106         f3.deleteOnExit();
107         
108         final Difference[] diffs = copyParts(true, file, f1, true);
109         if (diffs.length == 0) {
110             DialogDisplayer.getDefault ().notify (new org.openide.NotifyDescriptor.Message(
111                 org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "NoConflictsInFile", file)));
112             return ;
113         }
114         copyParts(false, file, f2, false);
115         //GraphicalMergeVisualizer merge = new GraphicalMergeVisualizer();
116
String JavaDoc originalLeftFileRevision = leftFileRevision;
117         String JavaDoc originalRightFileRevision = rightFileRevision;
118         if (leftFileRevision != null) leftFileRevision.trim();
119         if (rightFileRevision != null) rightFileRevision.trim();
120         if (leftFileRevision == null || leftFileRevision.equals(file.getName())) {
121             leftFileRevision = org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Diff.titleWorkingFile");
122         } else {
123             leftFileRevision = org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Diff.titleRevision", leftFileRevision);
124         }
125         if (rightFileRevision == null || rightFileRevision.equals(file.getName())) {
126             rightFileRevision = org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Diff.titleWorkingFile");
127         } else {
128             rightFileRevision = org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Diff.titleRevision", rightFileRevision);
129         }
130         
131         final StreamSource s1;
132         final StreamSource s2;
133         String JavaDoc encoding = EncodedReaderFactory.getDefault().getEncoding(fo);
134         if (encoding != null) {
135             s1 = StreamSource.createSource(file.getName(), leftFileRevision, mimeType, new InputStreamReader JavaDoc(new FileInputStream JavaDoc(f1), encoding));
136             s2 = StreamSource.createSource(file.getName(), rightFileRevision, mimeType, new InputStreamReader JavaDoc(new FileInputStream JavaDoc(f2), encoding));
137         } else {
138             s1 = StreamSource.createSource(file.getName(), leftFileRevision, mimeType, f1);
139             s2 = StreamSource.createSource(file.getName(), rightFileRevision, mimeType, f2);
140         }
141         final StreamSource result = new MergeResultWriterInfo(f1, f2, f3, file, mimeType,
142                                                               originalLeftFileRevision,
143                                                               originalRightFileRevision,
144                                                               fo, lock, encoding);
145
146         try {
147             Component c = merge.createView(diffs, s1, s2, result);
148             if (c instanceof TopComponent) {
149                 ((TopComponent) c).putClientProperty(ResolveConflictsExecutor.class.getName(), Boolean.TRUE);
150             }
151         } catch (IOException JavaDoc ioex) {
152             org.openide.ErrorManager.getDefault().notify(ioex);
153         }
154     }
155
156     /**
157      * Copy the file and conflict parts into another file.
158      */

159     private Difference[] copyParts(boolean generateDiffs, File JavaDoc source,
160                                    File JavaDoc dest, boolean leftPart) throws IOException JavaDoc {
161         //System.out.println("copyParts("+generateDiffs+", "+source+", "+dest+", "+leftPart+")");
162
BufferedReader JavaDoc r = new BufferedReader JavaDoc(new FileReader JavaDoc(source));
163         BufferedWriter JavaDoc w = new BufferedWriter JavaDoc(new FileWriter JavaDoc(dest));
164         ArrayList JavaDoc diffList = null;
165         if (generateDiffs) {
166             diffList = new ArrayList JavaDoc();
167         }
168         try {
169             String JavaDoc line;
170             boolean isChangeLeft = false;
171             boolean isChangeRight = false;
172             int f1l1 = 0, f1l2 = 0, f2l1 = 0, f2l2 = 0;
173             StringBuffer JavaDoc text1 = new StringBuffer JavaDoc();
174             StringBuffer JavaDoc text2 = new StringBuffer JavaDoc();
175             int i = 1, j = 1;
176             while ((line = r.readLine()) != null) {
177                 if (line.startsWith(CHANGE_LEFT)) {
178                     if (generateDiffs) {
179                         if (leftFileRevision == null) {
180                             leftFileRevision = line.substring(CHANGE_LEFT.length());
181                         }
182                         if (isChangeLeft) {
183                             f1l2 = i - 1;
184                             diffList.add((f1l1 > f1l2) ? new Difference(Difference.ADD,
185                                                                         f1l1 - 1, 0, f2l1, f2l2,
186                                                                         text1.toString(),
187                                                                         text2.toString()) :
188                                          (f2l1 > f2l2) ? new Difference(Difference.DELETE,
189                                                                         f1l1, f1l2, f2l1 - 1, 0,
190                                                                         text1.toString(),
191                                                                         text2.toString())
192                                                        : new Difference(Difference.CHANGE,
193                                                                         f1l1, f1l2, f2l1, f2l2,
194                                                                         text1.toString(),
195                                                                         text2.toString()));
196                             f1l1 = f1l2 = f2l1 = f2l2 = 0;
197                             text1.delete(0, text1.length());
198                             text2.delete(0, text2.length());
199                         } else {
200                             f1l1 = i;
201                         }
202                     }
203                     isChangeLeft = !isChangeLeft;
204                     continue;
205                 } else if (line.startsWith(CHANGE_RIGHT)) {
206                     if (generateDiffs) {
207                         if (rightFileRevision == null) {
208                             rightFileRevision = line.substring(CHANGE_RIGHT.length());
209                         }
210                         if (isChangeRight) {
211                             f2l2 = j - 1;
212                             diffList.add((f1l1 > f1l2) ? new Difference(Difference.ADD,
213                                                                         f1l1 - 1, 0, f2l1, f2l2,
214                                                                         text1.toString(),
215                                                                         text2.toString()) :
216                                          (f2l1 > f2l2) ? new Difference(Difference.DELETE,
217                                                                         f1l1, f1l2, f2l1 - 1, 0,
218                                                                         text1.toString(),
219                                                                         text2.toString())
220                                                        : new Difference(Difference.CHANGE,
221                                                                         f1l1, f1l2, f2l1, f2l2,
222                                                                         text1.toString(),
223                                                                         text2.toString()));
224                                                        /*
225                             diffList.add(new Difference((f1l1 > f1l2) ? Difference.ADD :
226                                                         (f2l1 > f2l2) ? Difference.DELETE :
227                                                                         Difference.CHANGE,
228                                                         f1l1, f1l2, f2l1, f2l2));
229                                                         */

230                             f1l1 = f1l2 = f2l1 = f2l2 = 0;
231                             text1.delete(0, text1.length());
232                             text2.delete(0, text2.length());
233                         } else {
234                             f2l1 = j;
235                         }
236                     }
237                     isChangeRight = !isChangeRight;
238                     continue;
239                 } else if (isChangeRight && line.indexOf(CHANGE_RIGHT) != -1) {
240                     String JavaDoc lineText = line.substring(0, line.lastIndexOf(CHANGE_RIGHT));
241                     if (generateDiffs) {
242                         if (rightFileRevision == null) {
243                             rightFileRevision = line.substring(line.lastIndexOf(CHANGE_RIGHT) + CHANGE_RIGHT.length());
244                         }
245                         text2.append(lineText);
246                         f2l2 = j;
247                         diffList.add((f1l1 > f1l2) ? new Difference(Difference.ADD,
248                                                                     f1l1 - 1, 0, f2l1, f2l2,
249                                                                     text1.toString(),
250                                                                     text2.toString()) :
251                                      (f2l1 > f2l2) ? new Difference(Difference.DELETE,
252                                                                     f1l1, f1l2, f2l1 - 1, 0,
253                                                                     text1.toString(),
254                                                                     text2.toString())
255                                                    : new Difference(Difference.CHANGE,
256                                                                     f1l1, f1l2, f2l1, f2l2,
257                                                                     text1.toString(),
258                                                                     text2.toString()));
259                         f1l1 = f1l2 = f2l1 = f2l2 = 0;
260                         text1.delete(0, text1.length());
261                         text2.delete(0, text2.length());
262                     }
263                     if (!leftPart) {
264                         w.write(lineText);
265                         w.newLine();
266                     }
267                     isChangeRight = !isChangeRight;
268                     continue;
269                 } else if (line.equals(CHANGE_DELIMETER)) {
270                     if (isChangeLeft) {
271                         isChangeLeft = false;
272                         isChangeRight = true;
273                         f1l2 = i - 1;
274                         f2l1 = j;
275                         continue;
276                     } else if (isChangeRight) {
277                         isChangeRight = false;
278                         isChangeLeft = true;
279                         f2l2 = j - 1;
280                         f1l1 = i;
281                         continue;
282                     }
283                 } else if (line.endsWith(CHANGE_DELIMETER)) {
284                     String JavaDoc lineText = line.substring(0, line.length() - CHANGE_DELIMETER.length()) + "\n"; // NOI18N
285
if (isChangeLeft) {
286                         text1.append(lineText);
287                         if (leftPart) {
288                             w.write(lineText);
289                             w.newLine();
290                         }
291                         isChangeLeft = false;
292                         isChangeRight = true;
293                         f1l2 = i;
294                         f2l1 = j;
295                     } else if (isChangeRight) {
296                         text2.append(lineText);
297                         if (!leftPart) {
298                             w.write(lineText);
299                             w.newLine();
300                         }
301                         isChangeRight = false;
302                         isChangeLeft = true;
303                         f2l2 = j;
304                         f1l1 = i;
305                     }
306                     continue;
307                 }
308                 if (!isChangeLeft && !isChangeRight || leftPart == isChangeLeft) {
309                     w.write(line);
310                     w.newLine();
311                 }
312                 if (isChangeLeft) text1.append(line + "\n"); // NOI18N
313
if (isChangeRight) text2.append(line + "\n"); // NOI18N
314
if (generateDiffs) {
315                     if (isChangeLeft) i++;
316                     else if (isChangeRight) j++;
317                     else {
318                         i++;
319                         j++;
320                     }
321                 }
322             }
323         } finally {
324             try {
325                 r.close();
326             } finally {
327                 w.close();
328             }
329         }
330         if (generateDiffs) {
331             return (Difference[]) diffList.toArray(new Difference[diffList.size()]);
332         } else {
333             return null;
334         }
335     }
336     
337     /**
338      * Repair the CVS/Entries of the file - remove the conflict.
339      * @param file The file to remove the conflict for
340      */

341     static void repairEntries(File JavaDoc file) throws IOException JavaDoc {
342         String JavaDoc name = file.getName();
343         File JavaDoc entries = new File JavaDoc(file.getParentFile(), "CVS"+File.separator+"Entries"); // NOI18N
344
File JavaDoc backup = new File JavaDoc(entries.getAbsolutePath()+".Backup"); // NOI18N
345
int attemps = 100;
346         while (backup.exists() && attemps-- > 0) {
347             // Someone else is occupying Entries, wait a while...
348
try {
349                 Thread.sleep(500);
350             } catch (InterruptedException JavaDoc intrex) {
351                 attemps = 0;
352             }
353         }
354         if (attemps <= 0) return ; // Give up, someone else is occupying Entries
355
backup.createNewFile();
356         try {
357             BufferedReader JavaDoc reader = null;
358             BufferedWriter JavaDoc writer = null;
359             try {
360                 reader = new BufferedReader JavaDoc(new FileReader JavaDoc(entries));
361                 writer = new BufferedWriter JavaDoc(new FileWriter JavaDoc(backup));
362                 String JavaDoc line;
363                 String JavaDoc pattern = "/"+name; // NOI18N
364
while ((line = reader.readLine()) != null) {
365                     if (line.startsWith(pattern)) {
366                         line = removeConflict(line);
367                     }
368                     writer.write(line+"\n"); // NOI18N
369
}
370             } finally {
371                 if (reader != null) reader.close();
372                 if (writer != null) writer.close();
373             }
374             FileUtils.renameFile(backup, entries);
375         } finally {
376             if (backup.exists()) backup.delete();
377         }
378     }
379     
380     private static String JavaDoc removeConflict(String JavaDoc line) {
381         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
382         int n = line.length();
383         int slashNum = 0;
384         boolean ignoreField = false;
385         for (int i = 0; i < n; i++) {
386             char c = line.charAt(i);
387             if (!ignoreField) result.append(c);
388             if (c == '/') {
389                 ignoreField = false;
390                 slashNum++;
391                 if (slashNum == 3) {
392                     result.append("Result of merge/"); // NOI18N
393
ignoreField = true;
394                 }
395             }
396         }
397         return result.toString();
398     }
399     
400     private static class MergeResultWriterInfo extends StreamSource {
401         
402         private File JavaDoc tempf1, tempf2, tempf3, outputFile;
403         private File JavaDoc fileToRepairEntriesOf;
404         private String JavaDoc mimeType;
405         private String JavaDoc leftFileRevision;
406         private String JavaDoc rightFileRevision;
407         private FileObject fo;
408         private FileLock lock;
409         private String JavaDoc encoding;
410         
411         public MergeResultWriterInfo(File JavaDoc tempf1, File JavaDoc tempf2, File JavaDoc tempf3,
412                                      File JavaDoc outputFile, String JavaDoc mimeType,
413                                      String JavaDoc leftFileRevision, String JavaDoc rightFileRevision,
414                                      FileObject fo, FileLock lock, String JavaDoc encoding) {
415             this.tempf1 = tempf1;
416             this.tempf2 = tempf2;
417             this.tempf3 = tempf3;
418             this.outputFile = outputFile;
419             this.mimeType = mimeType;
420             this.leftFileRevision = leftFileRevision;
421             this.rightFileRevision = rightFileRevision;
422             this.fo = fo;
423             this.lock = lock;
424             if (encoding == null) {
425                 encoding = EncodedReaderFactory.getDefault().getEncoding(tempf1);
426             }
427             this.encoding = encoding;
428         }
429         
430         public String JavaDoc getName() {
431             return outputFile.getName();
432         }
433         
434         public String JavaDoc getTitle() {
435             return org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Merge.titleResult");
436         }
437         
438         public String JavaDoc getMIMEType() {
439             return mimeType;
440         }
441         
442         public Reader JavaDoc createReader() throws IOException JavaDoc {
443             throw new IOException JavaDoc("No reader of merge result"); // NOI18N
444
}
445         
446         /**
447          * Create a writer, that writes to the source.
448          * @param conflicts The list of conflicts remaining in the source.
449          * Can be <code>null</code> if there are no conflicts.
450          * @return The writer or <code>null</code>, when no writer can be created.
451          */

452         public Writer JavaDoc createWriter(Difference[] conflicts) throws IOException JavaDoc {
453             Writer JavaDoc w;
454             if (fo != null) {
455                 w = EncodedReaderFactory.getDefault().getWriter(fo, lock, encoding);
456             } else {
457                 w = EncodedReaderFactory.getDefault().getWriter(outputFile, mimeType, encoding);
458             }
459             if (conflicts == null || conflicts.length == 0) {
460                 fileToRepairEntriesOf = outputFile;
461                 return w;
462             } else {
463                 return new MergeConflictFileWriter(w, fo, conflicts,
464                                                    leftFileRevision, rightFileRevision);
465             }
466         }
467         
468         /**
469          * This method is called when the visual merging process is finished.
470          * All possible writting processes are finished before this method is called.
471          */

472         public void close() {
473             tempf1.delete();
474             tempf2.delete();
475             tempf3.delete();
476             if (lock != null) {
477                 lock.releaseLock();
478                 lock = null;
479             }
480             fo = null;
481             if (fileToRepairEntriesOf != null) {
482                 try {
483                     repairEntries(fileToRepairEntriesOf);
484                 } catch (IOException JavaDoc ioex) {
485                     // The Entries will not be repaired at worse
486
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ioex);
487                 }
488                 fileToRepairEntriesOf = null;
489             }
490         }
491         
492     }
493     
494     private static class MergeConflictFileWriter extends FilterWriter JavaDoc {
495         
496         private Difference[] conflicts;
497         private int lineNumber;
498         private int currentConflict;
499         private String JavaDoc leftName;
500         private String JavaDoc rightName;
501         private FileObject fo;
502         
503         public MergeConflictFileWriter(Writer JavaDoc delegate, FileObject fo,
504                                        Difference[] conflicts, String JavaDoc leftName,
505                                        String JavaDoc rightName) throws IOException JavaDoc {
506             super(delegate);
507             this.conflicts = conflicts;
508             this.leftName = leftName;
509             this.rightName = rightName;
510             this.lineNumber = 1;
511             this.currentConflict = 0;
512             if (lineNumber == conflicts[currentConflict].getFirstStart()) {
513                 writeConflict(conflicts[currentConflict]);
514                 currentConflict++;
515             }
516             this.fo = fo;
517         }
518         
519         public void write(String JavaDoc str) throws IOException JavaDoc {
520             //System.out.println("MergeConflictFileWriter.write("+str+")");
521
super.write(str);
522             lineNumber += numChars('\n', str);
523             //System.out.println(" lineNumber = "+lineNumber+", current conflict start = "+conflicts[currentConflict].getFirstStart());
524
if (currentConflict < conflicts.length && lineNumber >= conflicts[currentConflict].getFirstStart()) {
525                 writeConflict(conflicts[currentConflict]);
526                 currentConflict++;
527             }
528         }
529         
530         private void writeConflict(Difference conflict) throws IOException JavaDoc {
531             //System.out.println("MergeConflictFileWriter.writeConflict('"+conflict.getFirstText()+"', '"+conflict.getSecondText()+"')");
532
super.write(CHANGE_LEFT + leftName + "\n"); // NOI18N
533
super.write(conflict.getFirstText());
534             super.write(CHANGE_DELIMETER + "\n"); // NOI18N
535
super.write(conflict.getSecondText());
536             super.write(CHANGE_RIGHT + rightName + "\n"); // NOI18N
537
}
538         
539         private static int numChars(char c, String JavaDoc str) {
540             int n = 0;
541             for (int pos = str.indexOf(c); pos >= 0 && pos < str.length(); pos = str.indexOf(c, pos + 1)) {
542                 n++;
543             }
544             return n;
545         }
546         
547         public void close() throws IOException JavaDoc {
548             super.close();
549             if (fo != null) fo.refresh(true);
550         }
551     }
552 }
553
554
Popular Tags