1 22 package org.jboss.tools.license; 23 24 import java.io.File ; 25 import java.io.FileFilter ; 26 import java.io.IOException ; 27 import java.io.FileWriter ; 28 import java.io.FileInputStream ; 29 import java.io.FileOutputStream ; 30 import java.io.RandomAccessFile ; 31 import java.io.SyncFailedException ; 32 import java.util.ArrayList ; 33 import java.util.List ; 34 import java.util.Iterator ; 35 import java.util.Map ; 36 import java.util.TreeMap ; 37 import java.util.logging.Level ; 38 import java.util.logging.Logger ; 39 import java.nio.channels.FileChannel ; 40 import java.nio.ByteBuffer ; 41 import java.net.URL ; 42 import javax.xml.parsers.DocumentBuilder ; 43 import javax.xml.parsers.DocumentBuilderFactory ; 44 45 import org.w3c.dom.Document ; 46 import org.w3c.dom.Element ; 47 import org.w3c.dom.NodeList ; 48 import org.w3c.dom.Node ; 49 50 58 public class ValidateLicenseHeaders 59 { 60 61 static final String COPYRIGHT_REGEX = "copyright\\s(\\(c\\))*\\s*[\\d]+(\\s*,\\s*[\\d]+|\\s*-\\s*[\\d]+)*"; 62 63 static final String DEFAULT_HEADER = "/*\n" + 64 " * JBoss, Home of Professional Open Source\n" + 65 " * Copyright 2005, JBoss Inc., and individual contributors as indicated\n" + 66 " * by the @authors tag. See the copyright.txt in the distribution for a\n" + 67 " * full listing of individual contributors.\n" + 68 " *\n" + 69 " * This is free software; you can redistribute it and/or modify it\n" + 70 " * under the terms of the GNU Lesser General Public License as\n" + 71 " * published by the Free Software Foundation; either version 2.1 of\n" + 72 " * the License, or (at your option) any later version.\n" + 73 " *\n" + 74 " * This software is distributed in the hope that it will be useful,\n" + 75 " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + 76 " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" + 77 " * Lesser General Public License for more details.\n" + 78 " *\n" + 79 " * You should have received a copy of the GNU Lesser General Public\n" + 80 " * License along with this software; if not, write to the Free\n" + 81 " * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA\n" + 82 " * 02110-1301 USA, or see the FSF site: http://www.fsf.org.\n" + 83 " */\n"; 84 static Logger log = Logger.getLogger("ValidateCopyrightHeaders"); 85 static boolean addDefaultHeader = true; 86 static FileFilter dotJavaFilter = new DotJavaFilter(); 87 90 static TreeMap licenseHeaders = new TreeMap (); 91 94 static ArrayList noheaders = new ArrayList (); 95 98 static ArrayList invalidheaders = new ArrayList (); 99 100 static int totalCount; 101 102 static int jbossCount; 103 104 108 public static void main(String [] args) 109 throws Exception 110 { 111 if( args.length == 0 || args[0].startsWith("-h") ) 112 { 113 log.info("Usage: ValidateLicenseHeaders [-addheader] jboss-src-root"); 114 System.exit(1); 115 } 116 int rootArg = 0; 117 if( args.length == 2 ) 118 { 119 if( args[0].startsWith("-add") ) 120 addDefaultHeader = true; 121 else 122 { 123 log.severe("Uknown argument: "+args[0]); 124 log.info("Usage: ValidateLicenseHeaders [-addheader] jboss-src-root"); 125 System.exit(1); 126 127 } 128 rootArg = 1; 129 } 130 131 File jbossSrcRoot = new File (args[rootArg]); 132 if( jbossSrcRoot.exists() == false ) 133 { 134 log.info("Src root does not exist, check "+jbossSrcRoot.getAbsolutePath()); 135 System.exit(1); 136 } 137 138 URL u = Thread.currentThread().getContextClassLoader().getResource("META-INF/services/javax.xml.parsers.DocumentBuilderFactory"); 139 System.err.println(u); 140 141 File licenseInfo = new File (jbossSrcRoot, "thirdparty/licenses/license-info.xml"); 143 if( licenseInfo.exists() == false ) 144 { 145 log.severe("Failed to find the thirdparty/licenses/license-info.xml under the src root"); 146 System.exit(1); 147 } 148 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 149 DocumentBuilder db = factory.newDocumentBuilder(); 150 Document doc = db.parse(licenseInfo); 151 NodeList licenses = doc.getElementsByTagName("license"); 152 for(int i = 0; i < licenses.getLength(); i ++) 153 { 154 Element license = (Element ) licenses.item(i); 155 String key = license.getAttribute("id"); 156 ArrayList headers = new ArrayList (); 157 licenseHeaders.put(key, headers); 158 NodeList copyrights = license.getElementsByTagName("terms-header"); 159 for(int j = 0; j < copyrights.getLength(); j ++) 160 { 161 Element copyright = (Element ) copyrights.item(j); 162 copyright.normalize(); 163 String id = copyright.getAttribute("id"); 164 if( id.length() == 0 ) 166 continue; 167 String text = getElementContent(copyright); 168 if( text == null ) 169 continue; 170 text = text.replaceAll("[\\s*]+", " "); 172 if( text.length() == 1) 173 continue; 174 175 text = text.toLowerCase().trim(); 176 text = text.replaceAll(COPYRIGHT_REGEX, "..."); 178 LicenseHeader lh = new LicenseHeader(id, text); 179 headers.add(lh); 180 } 181 } 182 log.fine(licenseHeaders.toString()); 183 184 File [] files = jbossSrcRoot.listFiles(dotJavaFilter); 185 log.info("Root files count: "+files.length); 186 processSourceFiles(files, 0); 187 188 log.info("Processed "+totalCount); 189 log.info("Updated jboss headers: "+jbossCount); 190 log.info("Files with no headers: "+noheaders.size()); 192 FileWriter fw = new FileWriter ("NoHeaders.txt"); 193 for(Iterator iter = noheaders.iterator(); iter.hasNext();) 194 { 195 File f = (File ) iter.next(); 196 fw.write(f.getAbsolutePath()); 197 fw.write('\n'); 198 } 199 fw.close(); 200 201 log.info("Files with invalid headers: "+invalidheaders.size()); 203 fw = new FileWriter ("InvalidHeaders.txt"); 204 for(Iterator iter = invalidheaders.iterator(); iter.hasNext();) 205 { 206 File f = (File ) iter.next(); 207 fw.write(f.getAbsolutePath()); 208 fw.write('\n'); 209 } 210 fw.close(); 211 212 log.info("Creating HeadersSummary.txt"); 214 fw = new FileWriter ("HeadersSummary.txt"); 215 for(Iterator iter = licenseHeaders.entrySet().iterator(); iter.hasNext();) 216 { 217 Map.Entry entry = (Map.Entry ) iter.next(); 218 String key = (String ) entry.getKey(); 219 fw.write("+++ License type="+key); 220 fw.write('\n'); 221 List list = (List ) entry.getValue(); 222 Iterator jiter = list.iterator(); 223 while( jiter.hasNext() ) 224 { 225 LicenseHeader lh = (LicenseHeader) jiter.next(); 226 fw.write('\t'); 227 fw.write(lh.id); 228 fw.write(", count="); 229 fw.write(""+lh.count); 230 fw.write('\n'); 231 } 232 } 233 fw.close(); 234 } 235 236 241 public static String getElementContent(Element element) 242 { 243 if (element == null) 244 return null; 245 246 NodeList children = element.getChildNodes(); 247 StringBuffer result = new StringBuffer (); 248 for (int i = 0; i < children.getLength(); i++) 249 { 250 Node child = children.item(i); 251 if (child.getNodeType() == Node.TEXT_NODE || 252 child.getNodeType() == Node.CDATA_SECTION_NODE) 253 { 254 result.append(child.getNodeValue()); 255 } 256 else if( child.getNodeType() == Node.COMMENT_NODE ) 257 { 258 } 260 else 261 { 262 result.append(child.getFirstChild()); 263 } 264 } 265 return result.toString().trim(); 266 } 267 268 275 static void processSourceFiles(File [] files, int level) 276 throws IOException 277 { 278 for(int i = 0; i < files.length; i ++) 279 { 280 File f = files[i]; 281 if( level == 0 ) 282 log.info("processing "+f); 283 if( f.isDirectory() ) 284 { 285 File [] children = f.listFiles(dotJavaFilter); 286 processSourceFiles(children, level+1); 287 } 288 else 289 { 290 parseHeader(f); 291 } 292 } 293 } 294 295 299 static void parseHeader(File javaFile) 300 throws IOException 301 { 302 totalCount ++; 303 RandomAccessFile raf = new RandomAccessFile (javaFile, "rw"); 304 String line = raf.readLine(); 305 StringBuffer tmp = new StringBuffer (); 306 long endOfHeader = 0; 307 boolean packageOrImport = false; 308 while( line != null ) 309 { 310 long nextEOH = raf.getFilePointer(); 311 line = line.trim(); 312 if( line.startsWith("//") ) 314 { 315 line = raf.readLine(); 316 continue; 317 } 318 319 if( line.startsWith("package") || line.startsWith("import") 321 || line.indexOf("class") >= 0 || line.indexOf("interface") >= 0 ) 322 { 323 packageOrImport = true; 324 break; 325 } 326 327 endOfHeader = nextEOH; 329 330 if( line.startsWith("/**") ) 331 tmp.append(line.substring(3)); 332 else if( line.startsWith("/*") ) 333 tmp.append(line.substring(2)); 334 else if( line.startsWith("*") ) 335 tmp.append(line.substring(1)); 336 else 337 tmp.append(line); 338 tmp.append(' '); 339 line = raf.readLine(); 340 } 341 raf.close(); 342 343 if( tmp.length() == 0 || packageOrImport == false ) 344 { 345 addDefaultHeader(javaFile); 346 return; 347 } 348 349 String text = tmp.toString(); 350 text = text.replaceAll("[\\s*]+", " "); 352 text = text.toLowerCase().trim(); 353 text = text.replaceAll(COPYRIGHT_REGEX, "..."); 355 if( tmp.length() == 0 ) 356 { 357 addDefaultHeader(javaFile); 358 return; 359 } 360 boolean matches = false; 362 String matchID = null; 363 Iterator iter = licenseHeaders.entrySet().iterator(); 364 escape: 365 while( iter.hasNext() ) 366 { 367 Map.Entry entry = (Map.Entry ) iter.next(); 368 String key = (String ) entry.getKey(); 369 List list = (List ) entry.getValue(); 370 Iterator jiter = list.iterator(); 371 while( jiter.hasNext() ) 372 { 373 LicenseHeader lh = (LicenseHeader) jiter.next(); 374 if( text.startsWith(lh.text) ) 375 { 376 matches = true; 377 matchID = lh.id; 378 lh.count ++; 379 lh.usage.add(javaFile); 380 if( log.isLoggable(Level.FINE) ) 381 log.fine(javaFile+" matches copyright key="+key+", id="+lh.id); 382 break escape; 383 } 384 } 385 } 386 text = null; 387 tmp.setLength(0); 388 if( matches == false ) 389 invalidheaders.add(javaFile); 390 else if( matchID.startsWith("jboss") && matchID.endsWith("#0") == false ) 391 { 392 replaceHeader(javaFile, endOfHeader); 394 jbossCount ++; 395 } 396 } 397 398 404 static void replaceHeader(File javaFile, long endOfHeader) 405 throws IOException 406 { 407 if( log.isLoggable(Level.FINE) ) 408 log.fine("Replacing legacy jboss header in: "+javaFile); 409 RandomAccessFile raf = new RandomAccessFile (javaFile, "rw"); 410 File bakFile = new File (javaFile.getAbsolutePath()+".bak"); 411 FileOutputStream fos = new FileOutputStream (bakFile); 412 fos.write(DEFAULT_HEADER.getBytes()); 413 FileChannel fc = raf.getChannel(); 414 long count = raf.length() - endOfHeader; 415 fc.transferTo(endOfHeader, count, fos.getChannel()); 416 fc.close(); 417 fos.close(); 418 raf.close(); 419 if( javaFile.delete() == false ) 420 log.severe("Failed to delete java file: "+javaFile); 421 if( bakFile.renameTo(javaFile) == false ) 422 throw new SyncFailedException ("Failed to replace: "+javaFile); 423 } 424 425 428 static void addDefaultHeader(File javaFile) 429 throws IOException 430 { 431 if( addDefaultHeader ) 432 { 433 FileInputStream fis = new FileInputStream (javaFile); 434 FileChannel fc = fis.getChannel(); 435 int size = (int) fc.size(); 436 ByteBuffer contents = ByteBuffer.allocate(size); 437 fc.read(contents); 438 fis.close(); 439 440 ByteBuffer hdr = ByteBuffer.wrap(DEFAULT_HEADER.getBytes()); 441 FileOutputStream fos = new FileOutputStream (javaFile); 442 fos.write(hdr.array()); 443 fos.write(contents.array()); 444 fos.close(); 445 } 446 447 noheaders.add(javaFile); 448 } 449 450 453 static class LicenseHeader 454 { 455 String id; 456 String text; 457 int count; 458 ArrayList usage = new ArrayList (); 459 LicenseHeader(String id, String text) 460 { 461 this.id = id; 462 this.text = text; 463 } 464 } 465 466 470 static class DotJavaFilter implements FileFilter 471 { 472 public boolean accept(File pathname) 473 { 474 boolean accept = false; 475 String name = pathname.getName(); 476 if( pathname.isDirectory() ) 477 { 478 accept = name.equals("gen-src") == false 480 && name.equals("gen-parsers") == false; 481 } 482 else 483 { 484 accept = name.endsWith("_Stub.java") == false && name.endsWith(".java"); 485 } 486 487 return accept; 488 } 489 } 490 } | Popular Tags |