KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > diff > cmdline > CmdlineDiffProvider


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.diff.cmdline;
21
22 import java.io.*;
23 import java.util.ArrayList JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.regex.Pattern JavaDoc;
26 import java.util.regex.PatternSyntaxException JavaDoc;
27
28 import org.openide.filesystems.FileObject;
29 import org.openide.filesystems.FileUtil;
30 import org.openide.util.NbBundle;
31 import org.openide.util.Utilities;
32
33 import org.netbeans.api.diff.Difference;
34 import org.netbeans.spi.diff.DiffProvider;
35 import org.openide.ErrorManager;
36
37 /**
38  * The parser of an external diff utility compatible with Unix diff output.
39  *
40  * <p>The implementtaion is interruptible by Thread.interrupt().
41  * On interrupt it kills external program and throws InterruptedIOException,
42  *
43  * @author Martin Entlicher
44  */

45 public class CmdlineDiffProvider extends DiffProvider implements java.io.Serializable JavaDoc {
46
47     //private static final String REVISION_STR = "retrieving revision";
48
public static final String JavaDoc DIFF_REGEXP = "(^[0-9]+(,[0-9]+|)[d][0-9]+$)|"+
49                                               "(^[0-9]+(,[0-9]+|)[c][0-9]+(,[0-9]+|)$)|"+
50                                               "(^[0-9]+[a][0-9]+(,[0-9]+|)$)";
51     private static final int BUFF_LENGTH = 1024;
52
53     private String JavaDoc diffCmd;
54     private transient Pattern JavaDoc pattern;
55     //private transient StringBuffer firstText;
56
//private transient StringBuffer secondText;
57

58     static final long serialVersionUID =4101521743158176210L;
59     /** Creates new CmdlineDiffProvider
60      * @param diffCmd The diff command. Must contain "{0}" and "{1}", which
61      * will be replaced with the files being compared.
62      */

63     public CmdlineDiffProvider(String JavaDoc diffCmd) {
64         this.diffCmd = diffCmd;
65         try {
66             pattern = Pattern.compile(DIFF_REGEXP);
67         } catch (PatternSyntaxException JavaDoc resex) {}
68         //firstText = new StringBuffer();
69
//secondText = new StringBuffer();
70
}
71     
72     public static CmdlineDiffProvider createDefault() {
73         return new CmdlineDiffProvider("diff {0} {1}"); // NOI18N
74
}
75
76     /**
77      * Set a new diff command.
78      * @param diffCmd The diff command. Must contain "{0}" and "{1}", which
79      * will be replaced with the files being compared.
80      */

81     public void setDiffCommand(String JavaDoc diffCmd) {
82         this.diffCmd = diffCmd;
83     }
84     
85     /**
86      * Get the diff command being used.
87      */

88     public String JavaDoc getDiffCommand() {
89         return diffCmd;
90     }
91     
92     private static boolean checkEmpty(String JavaDoc str, String JavaDoc element) {
93         if (str == null || str.length() == 0) {
94             /*
95             if (this.stderrListener != null) {
96                 String[] elements = { "Bad format of diff result: "+element }; // NOI18N
97                 stderrListener.match(elements);
98             }
99             */

100             //Edeb("Bad format of diff result: "+element); // NOI18N
101
return true;
102         }
103         return false;
104     }
105
106     /**
107      * Get the display name of this diff provider.
108      */

109     public String JavaDoc getDisplayName() {
110         return NbBundle.getMessage(CmdlineDiffProvider.class, "displayName");
111     }
112     
113     /**
114      * Get a short description of this diff provider.
115      */

116     public String JavaDoc getShortDescription() {
117         return NbBundle.getMessage(CmdlineDiffProvider.class, "shortDescription");
118     }
119
120     /**
121      * Create the differences of the content two streams.
122      * @param r1 the first source
123      * @param r2 the second source to be compared with the first one.
124      * @return the list of differences found, instances of {@link Difference};
125      * or <code>null</code> when some error occured.
126      */

127     public Difference[] computeDiff(Reader r1, Reader r2) throws IOException {
128         File f1 = null;
129         File f2 = null;
130         try {
131             f1 = FileUtil.normalizeFile(File.createTempFile("TempDiff".intern(), null));
132             f2 = FileUtil.normalizeFile(File.createTempFile("TempDiff".intern(), null));
133             FileWriter fw1 = new FileWriter(f1);
134             FileWriter fw2 = new FileWriter(f2);
135             char[] buffer = new char[BUFF_LENGTH];
136             int length;
137             while((length = r1.read(buffer)) > 0) fw1.write(buffer, 0, length);
138             while((length = r2.read(buffer)) > 0) fw2.write(buffer, 0, length);
139             r1.close();
140             r2.close();
141             fw1.close();
142             fw2.close();
143             return createDiff(f1, f2);
144         } finally {
145             if (f1 != null) f1.delete();
146             if (f2 != null) f2.delete();
147         }
148     }
149     
150     /**
151      * Create the differences of the content of two FileObjects.
152      * @param fo1 the first FileObject
153      * @param fo2 the second FileObject to be compared with the first one.
154      * @return the list of differences found, instances of {@link Difference};
155      * or <code>null</code> when some error occured.
156      */

157     public Difference[] computeDiff(FileObject fo1, FileObject fo2) throws IOException {
158         File f1 = FileUtil.toFile(fo1);
159         File f2 = FileUtil.toFile(fo2);
160         if (f1 != null && f2 != null) {
161             return createDiff(f1, f2);
162         } else {
163             return null;
164         }
165     }
166
167     /**
168      * Executes (possibly broken) external program.
169      */

170     private Difference[] createDiff(File f1, File f2) throws IOException {
171         final StringBuffer JavaDoc firstText = new StringBuffer JavaDoc();
172         final StringBuffer JavaDoc secondText = new StringBuffer JavaDoc();
173         if (pattern == null) {
174             try {
175                 pattern = Pattern.compile(DIFF_REGEXP);
176             } catch (PatternSyntaxException JavaDoc resex) {
177                 throw (IOException) ErrorManager.getDefault().annotate(
178                     new IOException(), resex.getLocalizedMessage());
179             }
180             //firstText = new StringBuffer();
181
//secondText = new StringBuffer();
182
}
183         diffCmd = diffCmd.replace("\"{0}\"", "{0}").replace("\"{1}\"", "{1}"); // compatibility // NOI18N
184
String JavaDoc firstPath;
185         String JavaDoc secondPath;
186         if (Utilities.isWindows()) {
187             firstPath = "\"" + f1.getAbsolutePath() + "\""; // NOI18N
188
secondPath = "\"" + f2.getAbsolutePath() + "\""; // NOI18N
189
} else {
190             firstPath = f1.getAbsolutePath();
191             secondPath = f2.getAbsolutePath();
192         }
193         final String JavaDoc cmd = java.text.MessageFormat.format(diffCmd, firstPath, secondPath);
194
195         final Process JavaDoc p[] = new Process JavaDoc[1];
196         final Object JavaDoc[] ret = new Object JavaDoc[1];
197         Runnable JavaDoc cancellableProcessWrapper = new Runnable JavaDoc() {
198             public void run() {
199                 try {
200                     ErrorManager.getDefault().log("#69616 CDP: executing: " + cmd); // NOI18N
201
synchronized(p) {
202                         p[0] = Runtime.getRuntime().exec(cmd);
203                     }
204                     Reader stdout = new InputStreamReader(p[0].getInputStream());
205                     char[] buffer = new char[BUFF_LENGTH];
206                     StringBuffer JavaDoc outBuffer = new StringBuffer JavaDoc();
207                     int length;
208                     List JavaDoc<Difference> differences = new ArrayList JavaDoc<Difference>();
209                     while ((length = stdout.read(buffer)) > 0) {
210                         for (int i = 0; i < length; i++) {
211                             if (buffer[i] == '\n') {
212                                 //stdoutNextLine(outBuffer.toString(), differences);
213
outputLine(outBuffer.toString(), pattern, differences,
214                                            firstText, secondText);
215                                 outBuffer.delete(0, outBuffer.length());
216                             } else {
217                                 if (buffer[i] != 13) {
218                                     outBuffer.append(buffer[i]);
219                                 }
220                             }
221                         }
222                     }
223                     if (outBuffer.length() > 0) outputLine(outBuffer.toString(), pattern, differences,
224                                                            firstText, secondText);
225                     setTextOnLastDifference(differences, firstText, secondText);
226                     ret[0] = differences.toArray(new Difference[differences.size()]);
227                 } catch (IOException ioex) {
228                     ret[0] = (IOException) ErrorManager.getDefault().annotate(ioex,
229                             NbBundle.getMessage(CmdlineDiffProvider.class, "runtimeError", cmd));
230                 }
231             }
232         };
233
234         Thread JavaDoc t = new Thread JavaDoc(cancellableProcessWrapper, "Diff.exec()"); // NOI18N
235
t.start();
236         try {
237             t.join();
238             synchronized(ret) {
239                 if (ret[0] instanceof IOException) {
240                     throw (IOException) ret[0];
241                 }
242                 return (Difference[]) ret[0];
243             }
244         } catch (InterruptedException JavaDoc e) {
245             synchronized(p[0]) {
246                 p[0].destroy();
247             }
248             throw new InterruptedIOException();
249         }
250
251     }
252
253     public static void setTextOnLastDifference(List JavaDoc<Difference> differences,
254         StringBuffer JavaDoc firstText, StringBuffer JavaDoc secondText) {
255         if (differences.size() > 0) {
256             String JavaDoc t1 = firstText.toString();
257             if (t1.length() == 0) t1 = null;
258             String JavaDoc t2 = secondText.toString();
259             if (t2.length() == 0) t2 = null;
260             Difference d = (Difference) differences.remove(differences.size() - 1);
261             differences.add(new Difference(d.getType(), d.getFirstStart(), d.getFirstEnd(),
262             d.getSecondStart(), d.getSecondEnd(), t1, t2));
263             firstText.delete(0, firstText.length());
264             secondText.delete(0, secondText.length());
265         }
266     }
267     
268     /**
269      * This method is called, with elements of the output data.
270      * @param elements the elements of output data.
271      */

272     //private void outputData(String[] elements, List differences) {
273
public static void outputLine(String JavaDoc elements, Pattern JavaDoc pattern, List JavaDoc<Difference> differences,
274                                    StringBuffer JavaDoc firstText, StringBuffer JavaDoc secondText) {
275         //diffBuffer.append(elements[0]+"\n"); // NOI18N
276
//D.deb("diff match: "+elements[0]); // NOI18N
277
//System.out.println("diff outputData: "+elements[0]); // NOI18N
278

279         int index = 0, commaIndex = 0;
280         int n1 = 0, n2 = 0, n3 = 0, n4 = 0;
281         String JavaDoc nStr;
282         if (pattern.matcher(elements).matches()) {
283             setTextOnLastDifference(differences, firstText, secondText);
284         } else {
285             if (elements.startsWith("< ")) {
286                 firstText.append(elements.substring(2) + "\n");
287             }
288             if (elements.startsWith("> ")) {
289                 secondText.append(elements.substring(2) + "\n");
290             }
291             return ;
292         }
293         if ((index = elements.indexOf('a')) >= 0) {
294             //DiffAction action = new DiffAction();
295
try {
296                 n1 = Integer.parseInt(elements.substring(0, index));
297                 index++;
298                 commaIndex = elements.indexOf(',', index);
299                 if (commaIndex < 0) {
300                     nStr = elements.substring(index, elements.length());
301                     if (checkEmpty(nStr, elements)) return;
302                     n3 = Integer.parseInt(nStr);
303                     n4 = n3;
304                 } else {
305                     nStr = elements.substring(index, commaIndex);
306                     if (checkEmpty(nStr, elements)) return;
307                     n3 = Integer.parseInt(nStr);
308                     nStr = elements.substring(commaIndex+1, elements.length());
309                     if (nStr == null || nStr.length() == 0) n4 = n3;
310                     else n4 = Integer.parseInt(nStr);
311                 }
312             } catch (NumberFormatException JavaDoc e) {
313                 /*
314                 if (this.stderrListener != null) {
315                     String[] debugOut = { "NumberFormatException "+e.getMessage() }; // NOI18N
316                     stderrListener.match(debugOut);
317                 }
318                 */

319                 //Edeb("NumberFormatException "+e.getMessage()); // NOI18N
320
return;
321             }
322             //action.setAddAction(n1, n3, n4);
323
//diffActions.add(action);
324
differences.add(new Difference(Difference.ADD, n1, 0, n3, n4));
325         } else if ((index = elements.indexOf('d')) >= 0) {
326             //DiffAction action = new DiffAction();
327
commaIndex = elements.lastIndexOf(',', index);
328             try {
329                 if (commaIndex < 0) {
330                     n1 = Integer.parseInt(elements.substring(0, index));
331                     n2 = n1;
332                 } else {
333                     nStr = elements.substring(0, commaIndex);
334                     if (checkEmpty(nStr, elements)) return;
335                     n1 = Integer.parseInt(nStr);
336                     nStr = elements.substring(commaIndex+1, index);
337                     if (checkEmpty(nStr, elements)) return;
338                     n2 = Integer.parseInt(nStr);
339                 }
340                 nStr = elements.substring(index+1, elements.length());
341                 if (checkEmpty(nStr, elements)) return;
342                 n3 = Integer.parseInt(nStr);
343             } catch (NumberFormatException JavaDoc e) {
344                 /*
345                 if (this.stderrListener != null) {
346                     String[] debugOut = { "NumberFormatException "+e.getMessage() }; // NOI18N
347                     stderrListener.match(debugOut);
348                 }
349                 */

350                 //Edeb("NumberFormatException "+e.getMessage()); // NOI18N
351
return;
352             }
353             //action.setDeleteAction(n1, n2, n3);
354
//diffActions.add(action);
355
differences.add(new Difference(Difference.DELETE, n1, n2, n3, 0));
356         } else if ((index = elements.indexOf('c')) >= 0) {
357             //DiffAction action = new DiffAction();
358
commaIndex = elements.lastIndexOf(',', index);
359             try {
360                 if (commaIndex < 0) {
361                     n1 = Integer.parseInt(elements.substring(0, index));
362                     n2 = n1;
363                 } else {
364                     nStr = elements.substring(0, commaIndex);
365                     if (checkEmpty(nStr, elements)) return;
366                     n1 = Integer.parseInt(nStr);
367                     nStr = elements.substring(commaIndex+1, index);
368                     if (checkEmpty(nStr, elements)) return;
369                     n2 = Integer.parseInt(nStr);
370                 }
371                 index++;
372                 commaIndex = elements.indexOf(',', index);
373                 if (commaIndex < 0) {
374                     nStr = elements.substring(index, elements.length());
375                     if (checkEmpty(nStr, elements)) return;
376                     n3 = Integer.parseInt(nStr);
377                     n4 = n3;
378                 } else {
379                     nStr = elements.substring(index, commaIndex);
380                     if (checkEmpty(nStr, elements)) return;
381                     n3 = Integer.parseInt(nStr);
382                     nStr = elements.substring(commaIndex+1, elements.length());
383                     if (nStr == null || nStr.length() == 0) n4 = n3;
384                     else n4 = Integer.parseInt(nStr);
385                 }
386             } catch (NumberFormatException JavaDoc e) {
387                 /*
388                 if (this.stderrListener != null) {
389                     String[] debugOut = { "NumberFormatException "+e.getMessage() }; // NOI18N
390                     stderrListener.match(debugOut);
391                 }
392                 */

393                 //Edeb("NumberFormatException "+e.getMessage()); // NOI18N
394
return;
395             }
396             //action.setChangeAction(n1, n2, n3, n4);
397
//diffActions.add(action);
398
differences.add(new Difference(Difference.CHANGE, n1, n2, n3, n4));
399         }
400     }
401     
402 }
403
Popular Tags