View Javadoc
1 ////////////////////////////////////////////////////////////////////////////// 2 // Clirr: compares two versions of a java library for binary compatibility 3 // Copyright (C) 2003 - 2004 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; 23 import java.io.IOException; 24 import java.net.MalformedURLException; 25 import java.net.URL; 26 import java.net.URLClassLoader; 27 import java.util.Iterator; 28 import java.util.LinkedList; 29 import java.util.List; 30 31 import net.sf.clirr.Checker; 32 import net.sf.clirr.event.PlainDiffListener; 33 import net.sf.clirr.event.XmlDiffListener; 34 import org.apache.tools.ant.BuildException; 35 import org.apache.tools.ant.DirectoryScanner; 36 import org.apache.tools.ant.Project; 37 import org.apache.tools.ant.Task; 38 import org.apache.tools.ant.types.FileSet; 39 import org.apache.tools.ant.types.Path; 40 41 42 /*** 43 * Implements the Clirr ant task. 44 * @author lkuehne 45 */ 46 public final class AntTask extends Task 47 { 48 private static final String FORMATTER_TYPE_PLAIN = "plain"; 49 private static final String FORMATTER_TYPE_XML = "xml"; 50 51 /*** 52 * Output formater. 53 */ 54 public static final class Formatter 55 { 56 private String type = null; 57 private String outFile = null; 58 59 public String getOutFile() 60 { 61 return outFile; 62 } 63 64 public void setOutFile(String outFile) 65 { 66 this.outFile = outFile; 67 } 68 69 public String getType() 70 { 71 return type; 72 } 73 74 public void setType(String type) 75 { 76 String lowerCase = type.toLowerCase(); 77 if (!lowerCase.equals(FORMATTER_TYPE_XML) && !lowerCase.equals(FORMATTER_TYPE_PLAIN)) 78 { 79 throw new BuildException("Illegal formatter type, only plain and xml are supported"); 80 } 81 82 this.type = type; 83 } 84 } 85 86 87 private FileSet origFiles = null; 88 private FileSet newFiles = null; 89 private Path newClassPath = null; 90 private Path origClassPath = null; 91 92 private boolean failOnError = true; 93 private boolean failOnWarning = false; 94 private List formatters = new LinkedList(); 95 96 97 public Path createNewClassPath() 98 { 99 if (newClassPath == null) 100 { 101 newClassPath = new Path(getProject()); 102 } 103 return newClassPath.createPath(); 104 } 105 106 public void setNewClassPath(Path path) 107 { 108 if (newClassPath == null) 109 { 110 newClassPath = path; 111 } 112 else 113 { 114 newClassPath.append(path); 115 } 116 } 117 118 public Path createOrigClassPath() 119 { 120 if (origClassPath == null) 121 { 122 origClassPath = new Path(getProject()); 123 } 124 return origClassPath.createPath(); 125 } 126 127 public void setOrigClassPath(Path path) 128 { 129 if (origClassPath == null) 130 { 131 origClassPath = path; 132 } 133 else 134 { 135 origClassPath.append(path); 136 } 137 } 138 139 public void addOrigFiles(FileSet origFiles) 140 { 141 if (this.origFiles != null) 142 { 143 throw new BuildException(); 144 } 145 this.origFiles = origFiles; 146 } 147 148 public void addNewFiles(FileSet newFiles) 149 { 150 if (this.newFiles != null) 151 { 152 throw new BuildException(); 153 } 154 this.newFiles = newFiles; 155 } 156 157 public void setFailOnError(boolean failOnError) 158 { 159 this.failOnError = failOnError; 160 } 161 162 public void setFailOnWarning(boolean failOnWarning) 163 { 164 this.failOnWarning = failOnWarning; 165 } 166 167 public void addFormatter(Formatter formatter) 168 { 169 formatters.add(formatter); 170 } 171 172 public void execute() 173 { 174 log("Running Clirr, built from tag $Name: RELEASE_CLIRR_0_3 $", Project.MSG_VERBOSE); 175 176 if (origFiles == null || newFiles == null) 177 { 178 throw new BuildException("Missing nested filesets origFiles and newFiles.", getLocation()); 179 } 180 181 if (newClassPath == null) 182 { 183 newClassPath = new Path(getProject()); 184 } 185 186 if (origClassPath == null) 187 { 188 origClassPath = new Path(getProject()); 189 } 190 191 final File[] origJars = scanFileSet(origFiles); 192 final File[] newJars = scanFileSet(newFiles); 193 194 if (origJars.length == 0) 195 { 196 throw new BuildException("No files in nested fileset origFiles - nothing to check!" 197 + " Please check your fileset specification."); 198 } 199 200 if (newJars.length == 0) 201 { 202 throw new BuildException("No files in nested fileset newFiles - nothing to check!" 203 + " Please check your fileset specification."); 204 } 205 206 final ClassLoader origThirdPartyLoader = createClasspathLoader(origClassPath); 207 final ClassLoader newThirdPartyLoader = createClasspathLoader(newClassPath); 208 209 final Checker checker = new Checker(); 210 final ChangeCounter counter = new ChangeCounter(); 211 212 boolean formattersWriteToStdOut = false; 213 214 for (Iterator it = formatters.iterator(); it.hasNext();) 215 { 216 Formatter formatter = (Formatter) it.next(); 217 final String type = formatter.getType(); 218 final String outFile = formatter.getOutFile(); 219 220 formattersWriteToStdOut = formattersWriteToStdOut || outFile == null; 221 222 try 223 { 224 if (FORMATTER_TYPE_PLAIN.equals(type)) 225 { 226 checker.addDiffListener(new PlainDiffListener(outFile)); 227 } 228 else if (FORMATTER_TYPE_XML.equals(type)) 229 { 230 checker.addDiffListener(new XmlDiffListener(outFile)); 231 } 232 } 233 catch (IOException ex) 234 { 235 log("unable to initialize formatter: " + ex.getMessage(), Project.MSG_WARN); 236 } 237 } 238 239 if (!formattersWriteToStdOut) 240 { 241 checker.addDiffListener(new AntLogger(this)); 242 } 243 244 checker.addDiffListener(counter); 245 checker.reportDiffs(origJars, newJars, origThirdPartyLoader, newThirdPartyLoader); 246 247 if (counter.getWarnings() > 0 && failOnWarning || counter.getErrors() > 0 && failOnError) 248 { 249 throw new BuildException("detected incompatible API changes"); 250 } 251 } 252 253 254 private ClassLoader createClasspathLoader(Path classpath) 255 { 256 final String[] cpEntries = classpath.list(); 257 final URL[] cpUrls = new URL[cpEntries.length]; 258 for (int i = 0; i < cpEntries.length; i++) 259 { 260 String cpEntry = cpEntries[i]; 261 File entry = new File(cpEntry); 262 try 263 { 264 URL url = entry.toURL(); 265 cpUrls[i] = url; 266 } 267 catch (MalformedURLException ex) 268 { 269 final IllegalArgumentException illegalArgEx = new IllegalArgumentException( 270 "Cannot create classLoader from classpath entry " + entry); 271 illegalArgEx.initCause(ex); 272 throw illegalArgEx; 273 } 274 } 275 final URLClassLoader classPathLoader = new URLClassLoader(cpUrls); 276 return classPathLoader; 277 } 278 279 private File[] scanFileSet(FileSet fs) 280 { 281 Project prj = getProject(); 282 DirectoryScanner scanner = fs.getDirectoryScanner(prj); 283 scanner.scan(); 284 File basedir = scanner.getBasedir(); 285 String[] fileNames = scanner.getIncludedFiles(); 286 File[] ret = new File[fileNames.length]; 287 for (int i = 0; i < fileNames.length; i++) 288 { 289 String fileName = fileNames[i]; 290 ret[i] = new File(basedir, fileName); 291 } 292 return ret; 293 } 294 }

This page was automatically generated by Maven