KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > clirr > ant > AntTask


1 //////////////////////////////////////////////////////////////////////////////
2
// Clirr: compares two versions of a java library for binary compatibility
3
// Copyright (C) 2003 - 2005 Lars Kühne
4
//
5
// This library is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU Lesser General Public
7
// License as published by the Free Software Foundation; either
8
// version 2.1 of the License, or (at your option) any later version.
9
//
10
// This library is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
// Lesser General Public License for more details.
14
//
15
// You should have received a copy of the GNU Lesser General Public
16
// License along with this library; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
//////////////////////////////////////////////////////////////////////////////
19

20 package net.sf.clirr.ant;
21
22 import java.io.File JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.LinkedList JavaDoc;
26 import java.util.List JavaDoc;
27
28 import net.sf.clirr.core.Checker;
29 import net.sf.clirr.core.CheckerException;
30 import net.sf.clirr.core.ClassFilter;
31 import net.sf.clirr.core.ClassSelector;
32 import net.sf.clirr.core.PlainDiffListener;
33 import net.sf.clirr.core.XmlDiffListener;
34 import net.sf.clirr.core.internal.ClassLoaderUtil;
35 import net.sf.clirr.core.internal.bcel.BcelTypeArrayBuilder;
36 import net.sf.clirr.core.spi.JavaType;
37
38 import org.apache.bcel.classfile.JavaClass;
39 import org.apache.tools.ant.BuildException;
40 import org.apache.tools.ant.DirectoryScanner;
41 import org.apache.tools.ant.Project;
42 import org.apache.tools.ant.Task;
43 import org.apache.tools.ant.types.FileSet;
44 import org.apache.tools.ant.types.Path;
45 import org.apache.tools.ant.types.PatternSet;
46
47
48 /**
49  * Implements the Clirr ant task.
50  * @author lkuehne
51  */

52 public final class AntTask extends Task
53 {
54     private static final String JavaDoc FORMATTER_TYPE_PLAIN = "plain";
55     private static final String JavaDoc FORMATTER_TYPE_XML = "xml";
56
57     /**
58      * Output formater.
59      */

60     public static final class Formatter
61     {
62         private String JavaDoc type = null;
63         private String JavaDoc outFile = null;
64
65         public String JavaDoc getOutFile()
66         {
67             return outFile;
68         }
69
70         public void setOutFile(String JavaDoc outFile)
71         {
72             this.outFile = outFile;
73         }
74
75         public String JavaDoc getType()
76         {
77             return type;
78         }
79
80         public void setType(String JavaDoc type)
81         {
82             String JavaDoc lowerCase = type.toLowerCase();
83             if (!lowerCase.equals(FORMATTER_TYPE_XML)
84                 && !lowerCase.equals(FORMATTER_TYPE_PLAIN))
85             {
86                 throw new BuildException(
87                     "Illegal formatter type, only plain and xml are supported");
88             }
89
90             this.type = type;
91         }
92     }
93
94     /**
95      * Class Filter that returns the logical "and" of two underlying class filters.
96      */

97     private static class CompoundClassFilter implements ClassFilter
98     {
99         private final ClassFilter patternSetFilter;
100         private final ClassFilter scopeSelector;
101
102         public CompoundClassFilter(ClassFilter patternSetFilter, ClassFilter scopeSelector)
103         {
104             this.patternSetFilter = patternSetFilter;
105             this.scopeSelector = scopeSelector;
106         }
107
108         public boolean isSelected(JavaClass clazz)
109         {
110             return patternSetFilter.isSelected(clazz) && scopeSelector.isSelected(clazz);
111         }
112     }
113
114     private FileSet origFiles = null;
115     private FileSet newFiles = null;
116     private Path newClassPath = null;
117     private Path origClassPath = null;
118
119     private boolean failOnBinError = true;
120     private boolean failOnBinWarning = false;
121     private boolean failOnSrcError = true;
122     private boolean failOnSrcWarning = false;
123     private List JavaDoc formatters = new LinkedList JavaDoc();
124     private List JavaDoc patternSets = new LinkedList JavaDoc();
125
126
127     public Path createNewClassPath()
128     {
129         if (newClassPath == null)
130         {
131             newClassPath = new Path(getProject());
132         }
133         return newClassPath.createPath();
134     }
135
136     public void setNewClassPath(Path path)
137     {
138         if (newClassPath == null)
139         {
140             newClassPath = path;
141         }
142         else
143         {
144             newClassPath.append(path);
145         }
146     }
147
148     public Path createOrigClassPath()
149     {
150         if (origClassPath == null)
151         {
152             origClassPath = new Path(getProject());
153         }
154         return origClassPath.createPath();
155     }
156
157     public void setOrigClassPath(Path path)
158     {
159         if (origClassPath == null)
160         {
161             origClassPath = path;
162         }
163         else
164         {
165             origClassPath.append(path);
166         }
167     }
168
169     public void addOrigFiles(FileSet origFiles)
170     {
171         if (this.origFiles != null)
172         {
173             throw new BuildException();
174         }
175         this.origFiles = origFiles;
176     }
177
178     public void addNewFiles(FileSet newFiles)
179     {
180         if (this.newFiles != null)
181         {
182             throw new BuildException();
183         }
184         this.newFiles = newFiles;
185     }
186
187     public void setFailOnBinError(boolean failOnBinError)
188     {
189         this.failOnBinError = failOnBinError;
190     }
191
192     public void setFailOnBinWarning(boolean failOnBinWarning)
193     {
194         this.failOnBinWarning = failOnBinWarning;
195     }
196
197     public void setFailOnSrcError(boolean failOnSrcError)
198     {
199         this.failOnSrcError = failOnSrcError;
200     }
201
202     public void setFailOnSrcWarning(boolean failOnSrcWarning)
203     {
204         this.failOnSrcWarning = failOnSrcWarning;
205     }
206
207     public void addFormatter(Formatter formatter)
208     {
209         formatters.add(formatter);
210     }
211
212     public void addApiClasses(PatternSet set)
213     {
214         patternSets.add(set);
215     }
216
217     public void execute()
218     {
219         log("Running Clirr, built from tag $Name: RELEASE_CLIRR_0_6 $", Project.MSG_VERBOSE);
220
221         if (origFiles == null || newFiles == null)
222         {
223             throw new BuildException(
224                 "Missing nested filesets origFiles and newFiles.", getLocation());
225         }
226
227         if (newClassPath == null)
228         {
229             newClassPath = new Path(getProject());
230         }
231
232         if (origClassPath == null)
233         {
234             origClassPath = new Path(getProject());
235         }
236
237         final File JavaDoc[] origJars = scanFileSet(origFiles);
238         final File JavaDoc[] newJars = scanFileSet(newFiles);
239
240         if (origJars.length == 0)
241         {
242             throw new BuildException(
243                 "No files in nested fileset origFiles - nothing to check!"
244                 + " Please check your fileset specification.");
245         }
246
247         if (newJars.length == 0)
248         {
249             throw new BuildException(
250                 "No files in nested fileset newFiles - nothing to check!"
251                 + " Please check your fileset specification.");
252         }
253
254         final ClassLoader JavaDoc origThirdPartyLoader = createClasspathLoader(origClassPath);
255         final ClassLoader JavaDoc newThirdPartyLoader = createClasspathLoader(newClassPath);
256
257         final Checker checker = new Checker();
258         final ChangeCounter counter = new ChangeCounter();
259
260         boolean formattersWriteToStdOut = false;
261
262         for (Iterator JavaDoc it = formatters.iterator(); it.hasNext();)
263         {
264             Formatter formatter = (Formatter) it.next();
265             final String JavaDoc type = formatter.getType();
266             final String JavaDoc outFile = formatter.getOutFile();
267
268             formattersWriteToStdOut = formattersWriteToStdOut || outFile == null;
269
270             try
271             {
272                 if (FORMATTER_TYPE_PLAIN.equals(type))
273                 {
274                     checker.addDiffListener(new PlainDiffListener(outFile));
275                 }
276                 else if (FORMATTER_TYPE_XML.equals(type))
277                 {
278                     checker.addDiffListener(new XmlDiffListener(outFile));
279                 }
280             }
281             catch (IOException JavaDoc ex)
282             {
283                 log("unable to initialize formatter: " + ex.getMessage(),
284                     Project.MSG_WARN);
285             }
286         }
287
288         if (!formattersWriteToStdOut)
289         {
290             checker.addDiffListener(new AntLogger(this));
291         }
292
293         checker.addDiffListener(counter);
294         try
295         {
296             ClassFilter classSelector = buildClassFilter();
297             final JavaType[] origClasses =
298                 BcelTypeArrayBuilder.createClassSet(origJars, origThirdPartyLoader, classSelector);
299             
300             final JavaType[] newClasses =
301                 BcelTypeArrayBuilder.createClassSet(newJars, newThirdPartyLoader, classSelector);
302             
303             checker.reportDiffs(origClasses, newClasses);
304         }
305         catch (CheckerException ex)
306         {
307             throw new BuildException(ex.getMessage());
308         }
309
310         if ((counter.getBinWarnings() > 0 && failOnBinWarning)
311             || (counter.getBinErrors() > 0 && failOnBinError))
312         {
313             throw new BuildException("detected binary incompatible API changes");
314         }
315
316         if ((counter.getSrcWarnings() > 0 && failOnSrcWarning)
317             || (counter.getSrcErrors() > 0 && failOnSrcError))
318         {
319             throw new BuildException("detected source incompatible API changes");
320         }
321     }
322
323     private ClassFilter buildClassFilter()
324     {
325         final PatternSetFilter patternSetFilter = new PatternSetFilter(getProject(), patternSets);
326         final ClassFilter scopeSelector = new ClassSelector(ClassSelector.MODE_UNLESS);
327         return new CompoundClassFilter(patternSetFilter, scopeSelector);
328     }
329
330
331     private ClassLoader JavaDoc createClasspathLoader(Path classpath)
332     {
333         final String JavaDoc[] cpEntries = classpath.list();
334         return ClassLoaderUtil.createClassLoader(cpEntries);
335     }
336
337     private File JavaDoc[] scanFileSet(FileSet fs)
338     {
339         Project prj = getProject();
340         DirectoryScanner scanner = fs.getDirectoryScanner(prj);
341         scanner.scan();
342         File JavaDoc basedir = scanner.getBasedir();
343         String JavaDoc[] fileNames = scanner.getIncludedFiles();
344         File JavaDoc[] ret = new File JavaDoc[fileNames.length];
345         for (int i = 0; i < fileNames.length; i++)
346         {
347             String JavaDoc fileName = fileNames[i];
348             ret[i] = new File JavaDoc(basedir, fileName);
349         }
350         return ret;
351     }
352
353 }
354
Popular Tags