001/* 002 * Cobertura - http://cobertura.sourceforge.net/ 003 * 004 * This file was taken from JavaNCSS 005 * http://www.kclee.com/clemens/java/javancss/ 006 * Copyright (C) 2000 Chr. Clemens Lee <clemens a.t kclee d.o.t com> 007 * 008 * Cobertura is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License as published 010 * by the Free Software Foundation; either version 2 of the License, 011 * or (at your option) any later version. 012 * 013 * Cobertura is distributed in the hope that it will be useful, but 014 * WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 016 * General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with Cobertura; if not, write to the Free Software 020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 021 * USA 022 */ 023 024 025/* 026 * 027 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 028 * 029 * WARNING TO COBERTURA DEVELOPERS 030 * 031 * DO NOT MODIFY THIS FILE! 032 * 033 * MODIFY THE FILES UNDER THE JAVANCSS DIRECTORY LOCATED AT THE ROOT OF THE COBERTURA PROJECT. 034 * 035 * FOLLOW THE PROCEDURE FOR MERGING THE LATEST JAVANCSS INTO COBERTURA LOCATED AT 036 * javancss/coberturaREADME.txt 037 * 038 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 039 */ 040 041package net.sourceforge.cobertura.javancss; 042 043import java.awt.event.WindowAdapter; 044import java.awt.event.WindowEvent; 045import java.io.File; 046import java.io.FileInputStream; 047import java.io.FileNotFoundException; 048import java.io.FileOutputStream; 049import java.io.InputStream; 050import java.io.IOException; 051import java.io.InputStreamReader; 052import java.io.OutputStream; 053import java.io.OutputStreamWriter; 054import java.io.PrintWriter; 055import java.io.Reader; 056import java.io.UnsupportedEncodingException; 057import java.util.ArrayList; 058import java.util.Collections; 059import java.util.HashMap; 060import java.util.HashSet; 061import java.util.Iterator; 062import java.util.List; 063import java.util.Map; 064import java.util.Set; 065 066import net.sourceforge.cobertura.javancss.ccl.Exitable; 067import net.sourceforge.cobertura.javancss.ccl.FileUtil; 068import net.sourceforge.cobertura.javancss.ccl.Init; 069import net.sourceforge.cobertura.javancss.ccl.Util; 070 071import net.sourceforge.cobertura.javancss.parser.JavaParser; 072import net.sourceforge.cobertura.javancss.parser.JavaParserInterface; 073import net.sourceforge.cobertura.javancss.parser.JavaParserTokenManager; 074import net.sourceforge.cobertura.javancss.parser.ParseException; 075import net.sourceforge.cobertura.javancss.parser.TokenMgrError; 076import net.sourceforge.cobertura.javancss.parser.debug.JavaParserDebug; 077import net.sourceforge.cobertura.javancss.parser.java15.JavaParser15; 078import net.sourceforge.cobertura.javancss.parser.java15.debug.JavaParser15Debug; 079import net.sourceforge.cobertura.javancss.test.JavancssTest; 080 081/** 082 * While the Java parser class might be the heart of JavaNCSS, 083 * this class is the brain. This class controls input and output and 084 * invokes the Java parser. 085 * 086 * @author Chr. Clemens Lee <clemens@kclee.com> 087 * , recursive feature by P??k? Hannu 088 * , additional javadoc metrics by Emilio Gongora <emilio@sms.nl> 089 * , and Guillermo Rodriguez <guille@sms.nl>. 090 * @version $Id: Javancss.java 676 2009-09-04 13:42:13Z lewijw $ 091 */ 092public class Javancss implements Exitable 093{ 094 private static final String S_INIT__FILE_CONTENT = 095 "[Init]\n" + 096 "Author=Chr. Clemens Lee\n" + 097 "\n" + 098 "[Help]\n"+ 099 "; Please do not edit the Help section\n"+ 100 "HelpUsage=@srcfiles.txt | *.java | <stdin>\n" + 101 "Options=ncss,package,object,function,all,gui,xml,out,recursive,check,encoding,parser15\n" + 102 "ncss=b,o,Counts the program NCSS (default).\n" + 103 "package=b,o,Assembles a statistic on package level.\n" + 104 "object=b,o,Counts the object NCSS.\n" + 105 "function=b,o,Counts the function NCSS.\n" + 106 "all=b,o,The same as '-function -object -package'.\n" + 107 "gui=b,o,Opens a gui to present the '-all' output in tabbed panels.\n" + 108 "xml=b,o,Output in xml format.\n" + 109 "out=s,o,Output file name. By default output goes to standard out.\n"+ 110 "recursive=b,o,Recurse to subdirs.\n" + 111 "check=b,o,Triggers a javancss self test.\n" + 112 "encoding=s,o,Encoding used while reading source files (default: platform encoding).\n" + 113 "parser15=b,o,Use new experimental Java 1.5 parser.\n" + 114 "\n" + 115 "[Colors]\n" + 116 "UseSystemColors=true\n"; 117 118 private boolean _bExit = false; 119 120 private List/*<File>*/ _vJavaSourceFiles = null; 121 private String encoding = null; 122 123 private String _sErrorMessage = null; 124 private Throwable _thrwError = null; 125 126 private JavaParserInterface _pJavaParser = null; 127 private int _ncss = 0; 128 private int _loc = 0; 129 private List/*<FunctionMetric>*/ _vFunctionMetrics = new ArrayList(); 130 private List/*<ObjectMetric>*/ _vObjectMetrics = new ArrayList(); 131 private List/*<PackageMetric>*/ _vPackageMetrics = null; 132 private List _vImports = null; 133 private Map/*<String,PackageMetric>*/ _htPackages = null; 134 private Object[] _aoPackage = null; 135 136 /** 137 * Just used for parseImports. 138 */ 139 private File _sJavaSourceFile = null; 140 141 private Reader createSourceReader( File sSourceFile_ ) 142 { 143 try 144 { 145 return newReader( sSourceFile_ ); 146 } 147 catch ( IOException pIOException ) 148 { 149 if ( Util.isEmpty( _sErrorMessage ) ) 150 { 151 _sErrorMessage = ""; 152 } 153 else 154 { 155 _sErrorMessage += "\n"; 156 } 157 _sErrorMessage += "File not found: " + sSourceFile_.getAbsolutePath(); 158 _thrwError = pIOException; 159 160 return null; 161 } 162 } 163 164 private void _measureSource( File sSourceFile_ ) throws IOException, Exception, Error 165 { 166 Reader reader = null; 167 168 // opens the file 169 try 170 { 171 reader = newReader( sSourceFile_ ); 172 } 173 catch ( IOException pIOException ) 174 { 175 if ( Util.isEmpty( _sErrorMessage ) ) 176 { 177 _sErrorMessage = ""; 178 } 179 else 180 { 181 _sErrorMessage += "\n"; 182 } 183 _sErrorMessage += "File not found: " + sSourceFile_.getAbsolutePath(); 184 _thrwError = pIOException; 185 186 throw pIOException; 187 } 188 189 String sTempErrorMessage = _sErrorMessage; 190 try 191 { 192 // the same method but with a Reader 193 _measureSource( reader ); 194 } 195 catch ( Exception pParseException ) 196 { 197 if ( sTempErrorMessage == null ) 198 { 199 sTempErrorMessage = ""; 200 } 201 sTempErrorMessage += "ParseException in " + sSourceFile_.getAbsolutePath() + 202 "\nLast useful checkpoint: \"" + _pJavaParser.getLastFunction() + "\"\n"; 203 sTempErrorMessage += pParseException.getMessage() + "\n"; 204 205 _sErrorMessage = sTempErrorMessage; 206 _thrwError = pParseException; 207 208 throw pParseException; 209 } 210 catch ( Error pTokenMgrError ) 211 { 212 if ( sTempErrorMessage == null ) 213 { 214 sTempErrorMessage = ""; 215 } 216 sTempErrorMessage += "TokenMgrError in " + sSourceFile_.getAbsolutePath() + 217 "\n" + pTokenMgrError.getMessage() + "\n"; 218 _sErrorMessage = sTempErrorMessage; 219 _thrwError = pTokenMgrError; 220 221 throw pTokenMgrError; 222 } 223 } 224 225 private void _measureSource( Reader reader ) throws IOException, Exception, Error 226 { 227 Util.debug( "_measureSource(Reader).ENTER" ); 228 //Util.debug( "_measureSource(Reader).parser15: -->" + (_pInit.getOptions().get( "parser15" ) + "<--" ); 229 //Util.panicIf( _pInit == null ); 230 //Util.panicIf( _pInit.getOptions() == null ); 231 Util.debug( "_measureSource(Reader).ENTER2" ); 232 try 233 { 234 // create a parser object 235 if ( Util.isDebug() == false ) 236 { 237 if ( _pInit == null || _pInit.getOptions() == null || _pInit.getOptions().get( "parser15" ) == null ) { 238 Util.debug( "creating JavaParser" ); 239 _pJavaParser = (JavaParserInterface)(new JavaParser( reader )); 240 } else { 241 Util.debug( "creating JavaParser15" ); 242 _pJavaParser = (JavaParserInterface)(new JavaParser15( reader )); 243 } 244 } else { 245 if ( _pInit == null || _pInit.getOptions() == null || _pInit.getOptions().get( "parser15" ) == null ) { 246 Util.debug( "creating JavaParserDebug" ); 247 Util.println( "creating JavaParserDebug" ); 248 _pJavaParser = (JavaParserInterface)(new JavaParserDebug( reader )); 249 } else { 250 Util.debug( "creating JavaParser15Debug" ); 251 _pJavaParser = (JavaParserInterface)(new JavaParser15Debug( reader )); 252 } 253 } 254 255 // execute the parser 256 _pJavaParser.parse(); 257 Util.debug( "Javancss._measureSource(DataInputStream).SUCCESSFULLY_PARSED" ); 258 259 _ncss += _pJavaParser.getNcss(); // increment the ncss 260 _loc += _pJavaParser.getLOC(); // and loc 261 // add new data to global vector 262 _vFunctionMetrics.addAll( _pJavaParser.getFunction() ); 263 _vObjectMetrics.addAll( _pJavaParser.getObject() ); 264 Map htNewPackages = _pJavaParser.getPackage(); 265 266 /* List vNewPackages = new Vector(); */ 267 for ( Iterator ePackages = htNewPackages.entrySet().iterator(); ePackages.hasNext(); ) 268 { 269 String sPackage = (String) ( (Map.Entry) ePackages.next() ).getKey(); 270 271 PackageMetric pckmNext = (PackageMetric) htNewPackages.get( sPackage ); 272 pckmNext.name = sPackage; 273 274 PackageMetric pckmPrevious = (PackageMetric) _htPackages.get( sPackage ); 275 pckmNext.add( pckmPrevious ); 276 277 _htPackages.put( sPackage, pckmNext ); 278 } 279 } 280 catch ( Exception pParseException ) 281 { 282 if ( _sErrorMessage == null ) 283 { 284 _sErrorMessage = ""; 285 } 286 _sErrorMessage += "ParseException in STDIN"; 287 if ( _pJavaParser != null ) 288 { 289 _sErrorMessage += "\nLast useful checkpoint: \"" + _pJavaParser.getLastFunction() + "\"\n"; 290 } 291 _sErrorMessage += pParseException.getMessage() + "\n"; 292 _thrwError = pParseException; 293 294 throw pParseException; 295 } 296 catch ( Error pTokenMgrError ) 297 { 298 if ( _sErrorMessage == null ) 299 { 300 _sErrorMessage = ""; 301 } 302 _sErrorMessage += "TokenMgrError in STDIN\n"; 303 _sErrorMessage += pTokenMgrError.getMessage() + "\n"; 304 _thrwError = pTokenMgrError; 305 306 throw pTokenMgrError; 307 } 308 } 309 310 private void _measureFiles( List/*<File>*/ vJavaSourceFiles_ ) throws IOException, ParseException, TokenMgrError 311 { 312 // for each file 313 for ( Iterator e = vJavaSourceFiles_.iterator(); e.hasNext(); ) 314 { 315 File file = (File) e.next(); 316 317 try 318 { 319 _measureSource( file ); 320 } 321 catch ( Throwable pThrowable ) 322 { 323 // hmm, do nothing? Use getLastError() or so to check for details. 324 } 325 } 326 } 327 328 /** 329 * If arguments were provided, they are used, otherwise 330 * the input stream is used. 331 */ 332 private void _measureRoot( Reader reader ) throws IOException, Exception, Error 333 { 334 _htPackages = new HashMap(); 335 336 // either there are argument files, or stdin is used 337 if ( _vJavaSourceFiles == null ) 338 { 339 _measureSource( reader ); 340 } 341 else 342 { 343 // the collection of files get measured 344 _measureFiles( _vJavaSourceFiles ); 345 } 346 347 _vPackageMetrics = new ArrayList(); 348 for ( Iterator ePackages = _htPackages.keySet().iterator(); ePackages.hasNext(); ) 349 { 350 String sPackage = (String) ePackages.next(); 351 352 PackageMetric pckmNext = (PackageMetric) _htPackages.get( sPackage ); 353 _vPackageMetrics.add( pckmNext ); 354 } 355 } 356 357 public List getImports() { 358 return _vImports; 359 } 360 361 /** 362 * Return info about package statement. 363 * First element has name of package, 364 * then begin of line, etc. 365 */ 366 public Object[] getPackage() { 367 return _aoPackage; 368 } 369 370 /** 371 * The same as getFunctionMetrics?! 372 */ 373 public List/*<FunctionMetric>*/ getFunctions() { 374 return _vFunctionMetrics; 375 } 376 377 public Javancss( List/*<File>*/ vJavaSourceFiles_ ) 378 { 379 _vJavaSourceFiles = vJavaSourceFiles_; 380 try { 381 _measureRoot(newReader(System.in)); 382 } catch(Exception e) { 383 e.printStackTrace(); 384 } catch(TokenMgrError pError) { 385 pError.printStackTrace(); 386 } 387 } 388 389 public Javancss( File sJavaSourceFile_ ) 390 { 391 Util.debug( "Javancss.<init>(String).sJavaSourceFile_: " + sJavaSourceFile_ ); 392 _sErrorMessage = null; 393 _vJavaSourceFiles = new ArrayList(); 394 _vJavaSourceFiles.add(sJavaSourceFile_); 395 try { 396 _measureRoot(newReader(System.in)); 397 } catch(Exception e) { 398 Util.debug( "Javancss.<init>(String).e: " + e ); 399 e.printStackTrace(); 400 } catch(TokenMgrError pError) { 401 Util.debug( "Javancss.<init>(String).pError: " + pError ); 402 pError.printStackTrace(); 403 } 404 } 405 406 /* 407 * cobertura: add this next constructor so any input stream can be used. 408 * 409 * It should be a copy of the Javancss(String) constructor, but just 410 * make sure _vJavaSourceFiles is null. _measureRoot will 411 * use the input stream if it is null. 412 */ 413 public Javancss(InputStream isJavaSource_) { 414 Util.debug( "Javancss.<init>(InputStream).sJavaSourceFile_: " + isJavaSource_ ); 415 _sErrorMessage = null; 416 _vJavaSourceFiles = null; 417 418 try { 419 _measureRoot(newReader(isJavaSource_)); 420 } catch(Exception e) { 421 Util.debug( "Javancss.<init>(InputStream).e: " + e ); 422 e.printStackTrace(); 423 } catch(TokenMgrError pError) { 424 Util.debug( "Javancss.<init>(InputStream).pError: " + pError ); 425 pError.printStackTrace(); 426 } 427 } 428 429 /** 430 * Only way to create object that does not immediately 431 * start to parse. 432 */ 433 public Javancss() { 434 super(); 435 436 _sErrorMessage = null; 437 _thrwError = null; 438 } 439 440 public boolean parseImports() { 441 if ( _sJavaSourceFile == null ) { 442 Util.debug( "Javancss.parseImports().NO_FILE" ); 443 444 return true; 445 } 446 Reader reader = createSourceReader( _sJavaSourceFile ); 447 if ( reader == null ) { 448 Util.debug( "Javancss.parseImports().NO_DIS" ); 449 450 return true; 451 } 452 453 try { 454 Util.debug( "Javancss.parseImports().START_PARSING" ); 455 if ( Util.isDebug() == false ) { 456 _pJavaParser = (JavaParserInterface)(new JavaParser(reader)); 457 } else { 458 _pJavaParser = (JavaParserInterface)(new JavaParserDebug(reader)); 459 } 460 _pJavaParser.parseImportUnit(); 461 _vImports = _pJavaParser.getImports(); 462 _aoPackage = _pJavaParser.getPackageObjects(); 463 Util.debug( "Javancss.parseImports().END_PARSING" ); 464 } catch(Exception pParseException) { 465 Util.debug( "Javancss.parseImports().PARSE_EXCEPTION" ); 466 if (_sErrorMessage == null) { 467 _sErrorMessage = ""; 468 } 469 _sErrorMessage += "ParseException in STDIN"; 470 if (_pJavaParser != null) { 471 _sErrorMessage += "\nLast useful checkpoint: \"" + _pJavaParser.getLastFunction() + "\"\n"; 472 } 473 _sErrorMessage += pParseException.getMessage() + "\n"; 474 _thrwError = pParseException; 475 476 return true; 477 } catch(Error pTokenMgrError) { 478 Util.debug( "Javancss.parseImports().TOKEN_ERROR" ); 479 if (_sErrorMessage == null) { 480 _sErrorMessage = ""; 481 } 482 _sErrorMessage += "TokenMgrError in STDIN\n"; 483 _sErrorMessage += pTokenMgrError.getMessage() + "\n"; 484 _thrwError = pTokenMgrError; 485 486 return true; 487 } 488 489 return false; 490 } 491 492 public void setSourceFile( File javaSourceFile_ ) { 493 _sJavaSourceFile = javaSourceFile_; 494 _vJavaSourceFiles = new ArrayList(); 495 _vJavaSourceFiles.add(javaSourceFile_); 496 } 497 private Init _pInit = null; 498 public int getNcss() { 499 return _ncss; 500 } 501 502 public int getLOC() { 503 return _loc; 504 } 505 506 // added by SMS 507 public int getJvdc() { 508 return _pJavaParser.getJvdc(); 509 } 510 511 /** 512 * JDCL stands for javadoc comment lines (while jvdc stands 513 * for number of javadoc comments). 514 */ 515 public int getJdcl() { 516 return JavaParserTokenManager._iFormalComments; 517 } 518 519 public int getSl() { 520 return JavaParserTokenManager._iSingleComments; 521 } 522 523 public int getMl() { 524 return JavaParserTokenManager._iMultiComments; 525 } 526 // 527 528 public List getFunctionMetrics() { 529 return(_vFunctionMetrics); 530 } 531 532 public List/*<ObjectMetric>*/ getObjectMetrics() { 533 return(_vObjectMetrics); 534 } 535 536 /** 537 * Returns list of packages in the form 538 * PackageMetric objects. 539 */ 540 public List getPackageMetrics() { 541 return(_vPackageMetrics); 542 } 543 544 public String getLastErrorMessage() { 545 if (_sErrorMessage == null) { 546 return null; 547 } 548 return _sErrorMessage; 549 } 550 551 public Throwable getLastError() { 552 return _thrwError; 553 } 554 555 public void setExit() { 556 _bExit = true; 557 } 558 559 560 public String getEncoding() 561 { 562 return encoding; 563 } 564 565 public void setEncoding( String encoding ) 566 { 567 this.encoding = encoding; 568 } 569 570 private Reader newReader( InputStream stream ) throws UnsupportedEncodingException 571 { 572 return ( encoding == null ) ? new InputStreamReader( stream ) : new InputStreamReader( stream, encoding ); 573 } 574 575 private Reader newReader( File file ) throws FileNotFoundException, UnsupportedEncodingException 576 { 577 return newReader( new FileInputStream( file ) ); 578 } 579}