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 Paako Hannu 088 * , additional javadoc metrics by Emilio Gongora <emilio@sms.nl> 089 * , and Guillermo Rodriguez <guille@sms.nl>. 090 * @version $Id: Javancss.java 198 2009-09-07 21:43:19Z hboutemy $ 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 boolean parser15 = _pInit != null && _pInit.getOptions() != null && _pInit.getOptions().get( "parser15" ) != null; 236 if ( Util.isDebug() ) 237 { 238 if ( parser15 ) 239 { 240 Util.debug( "creating JavaParser15Debug" ); 241 _pJavaParser = new JavaParser15Debug( reader ); 242 } 243 else 244 { 245 Util.debug( "creating JavaParserDebug" ); 246 _pJavaParser = new JavaParserDebug( reader ); 247 } 248 } 249 else 250 { 251 if ( parser15 ) 252 { 253 Util.debug( "creating JavaParser15" ); 254 _pJavaParser = new JavaParser15( reader ); 255 } 256 else 257 { 258 Util.debug( "creating JavaParser" ); 259 _pJavaParser = new JavaParser( reader ); 260 } 261 } 262 263 // execute the parser 264 _pJavaParser.parse(); 265 Util.debug( "Javancss._measureSource(DataInputStream).SUCCESSFULLY_PARSED" ); 266 267 _ncss += _pJavaParser.getNcss(); // increment the ncss 268 _loc += _pJavaParser.getLOC(); // and loc 269 // add new data to global vector 270 _vFunctionMetrics.addAll( _pJavaParser.getFunction() ); 271 _vObjectMetrics.addAll( _pJavaParser.getObject() ); 272 Map htNewPackages = _pJavaParser.getPackage(); 273 274 /* List vNewPackages = new Vector(); */ 275 for ( Iterator ePackages = htNewPackages.entrySet().iterator(); ePackages.hasNext(); ) 276 { 277 String sPackage = (String) ( (Map.Entry) ePackages.next() ).getKey(); 278 279 PackageMetric pckmNext = (PackageMetric) htNewPackages.get( sPackage ); 280 pckmNext.name = sPackage; 281 282 PackageMetric pckmPrevious = (PackageMetric) _htPackages.get( sPackage ); 283 pckmNext.add( pckmPrevious ); 284 285 _htPackages.put( sPackage, pckmNext ); 286 } 287 } 288 catch ( Exception pParseException ) 289 { 290 if ( _sErrorMessage == null ) 291 { 292 _sErrorMessage = ""; 293 } 294 _sErrorMessage += "ParseException in STDIN"; 295 if ( _pJavaParser != null ) 296 { 297 _sErrorMessage += "\nLast useful checkpoint: \"" + _pJavaParser.getLastFunction() + "\"\n"; 298 } 299 _sErrorMessage += pParseException.getMessage() + "\n"; 300 _thrwError = pParseException; 301 302 throw pParseException; 303 } 304 catch ( Error pTokenMgrError ) 305 { 306 if ( _sErrorMessage == null ) 307 { 308 _sErrorMessage = ""; 309 } 310 _sErrorMessage += "TokenMgrError in STDIN\n"; 311 _sErrorMessage += pTokenMgrError.getMessage() + "\n"; 312 _thrwError = pTokenMgrError; 313 314 throw pTokenMgrError; 315 } 316 } 317 318 private void _measureFiles( List/*<File>*/ vJavaSourceFiles_ ) throws IOException, ParseException, TokenMgrError 319 { 320 // for each file 321 for ( Iterator e = vJavaSourceFiles_.iterator(); e.hasNext(); ) 322 { 323 File file = (File) e.next(); 324 325 try 326 { 327 _measureSource( file ); 328 } 329 catch ( Throwable pThrowable ) 330 { 331 // hmm, do nothing? Use getLastError() or so to check for details. 332 } 333 } 334 } 335 336 /** 337 * If arguments were provided, they are used, otherwise 338 * the input stream is used. 339 */ 340 private void _measureRoot( Reader reader ) throws IOException, Exception, Error 341 { 342 _htPackages = new HashMap(); 343 344 // either there are argument files, or stdin is used 345 if ( _vJavaSourceFiles == null ) 346 { 347 _measureSource( reader ); 348 } 349 else 350 { 351 // the collection of files get measured 352 _measureFiles( _vJavaSourceFiles ); 353 } 354 355 _vPackageMetrics = new ArrayList(); 356 for ( Iterator ePackages = _htPackages.keySet().iterator(); ePackages.hasNext(); ) 357 { 358 String sPackage = (String) ePackages.next(); 359 360 PackageMetric pckmNext = (PackageMetric) _htPackages.get( sPackage ); 361 _vPackageMetrics.add( pckmNext ); 362 } 363 } 364 365 public List getImports() { 366 return _vImports; 367 } 368 369 /** 370 * Return info about package statement. 371 * First element has name of package, 372 * then begin of line, etc. 373 */ 374 public Object[] getPackage() { 375 return _aoPackage; 376 } 377 378 /** 379 * The same as getFunctionMetrics?! 380 */ 381 public List/*<FunctionMetric>*/ getFunctions() { 382 return _vFunctionMetrics; 383 } 384 385 public Javancss( List/*<File>*/ vJavaSourceFiles_ ) 386 { 387 _vJavaSourceFiles = vJavaSourceFiles_; 388 try { 389 _measureRoot(newReader(System.in)); 390 } catch(Exception e) { 391 e.printStackTrace(); 392 } catch(TokenMgrError pError) { 393 pError.printStackTrace(); 394 } 395 } 396 397 public Javancss( File sJavaSourceFile_ ) 398 { 399 Util.debug( "Javancss.<init>(String).sJavaSourceFile_: " + sJavaSourceFile_ ); 400 _sErrorMessage = null; 401 _vJavaSourceFiles = new ArrayList(); 402 _vJavaSourceFiles.add(sJavaSourceFile_); 403 try { 404 _measureRoot(newReader(System.in)); 405 } catch(Exception e) { 406 Util.debug( "Javancss.<init>(String).e: " + e ); 407 e.printStackTrace(); 408 } catch(TokenMgrError pError) { 409 Util.debug( "Javancss.<init>(String).pError: " + pError ); 410 pError.printStackTrace(); 411 } 412 } 413 414 /* 415 * cobertura: add this next constructor so any input stream can be used. 416 * 417 * It should (more or less) be a copy of the Javancss(File) constructor, but just 418 * make sure _vJavaSourceFiles is null. _measureRoot will 419 * use the input stream if it is null. 420 */ 421 public Javancss(InputStream isJavaSource_) { 422 Util.debug( "Javancss.<init>(InputStream).sJavaSourceFile_: " + isJavaSource_ ); 423 _sErrorMessage = null; 424 _vJavaSourceFiles = null; 425 426 try { 427 _measureRoot(newReader(isJavaSource_)); 428 } catch(Exception e) { 429 Util.debug( "Javancss.<init>(InputStream).e: " + e ); 430 e.printStackTrace(); 431 } catch(TokenMgrError pError) { 432 Util.debug( "Javancss.<init>(InputStream).pError: " + pError ); 433 pError.printStackTrace(); 434 } 435 } 436 437 /** 438 * Only way to create object that does not immediately 439 * start to parse. 440 */ 441 public Javancss() { 442 super(); 443 444 _sErrorMessage = null; 445 _thrwError = null; 446 } 447 448 public boolean parseImports() { 449 if ( _sJavaSourceFile == null ) { 450 Util.debug( "Javancss.parseImports().NO_FILE" ); 451 452 return true; 453 } 454 Reader reader = createSourceReader( _sJavaSourceFile ); 455 if ( reader == null ) { 456 Util.debug( "Javancss.parseImports().NO_DIS" ); 457 458 return true; 459 } 460 461 try { 462 Util.debug( "Javancss.parseImports().START_PARSING" ); 463 if ( Util.isDebug() == false ) { 464 _pJavaParser = (JavaParserInterface)(new JavaParser(reader)); 465 } else { 466 _pJavaParser = (JavaParserInterface)(new JavaParserDebug(reader)); 467 } 468 _pJavaParser.parseImportUnit(); 469 _vImports = _pJavaParser.getImports(); 470 _aoPackage = _pJavaParser.getPackageObjects(); 471 Util.debug( "Javancss.parseImports().END_PARSING" ); 472 } catch(Exception pParseException) { 473 Util.debug( "Javancss.parseImports().PARSE_EXCEPTION" ); 474 if (_sErrorMessage == null) { 475 _sErrorMessage = ""; 476 } 477 _sErrorMessage += "ParseException in STDIN"; 478 if (_pJavaParser != null) { 479 _sErrorMessage += "\nLast useful checkpoint: \"" + _pJavaParser.getLastFunction() + "\"\n"; 480 } 481 _sErrorMessage += pParseException.getMessage() + "\n"; 482 _thrwError = pParseException; 483 484 return true; 485 } catch(Error pTokenMgrError) { 486 Util.debug( "Javancss.parseImports().TOKEN_ERROR" ); 487 if (_sErrorMessage == null) { 488 _sErrorMessage = ""; 489 } 490 _sErrorMessage += "TokenMgrError in STDIN\n"; 491 _sErrorMessage += pTokenMgrError.getMessage() + "\n"; 492 _thrwError = pTokenMgrError; 493 494 return true; 495 } 496 497 return false; 498 } 499 500 public void setSourceFile( File javaSourceFile_ ) { 501 _sJavaSourceFile = javaSourceFile_; 502 _vJavaSourceFiles = new ArrayList(); 503 _vJavaSourceFiles.add(javaSourceFile_); 504 } 505 private Init _pInit = null; 506 public int getNcss() { 507 return _ncss; 508 } 509 510 public int getLOC() { 511 return _loc; 512 } 513 514 // added by SMS 515 public int getJvdc() { 516 return _pJavaParser.getJvdc(); 517 } 518 519 /** 520 * JDCL stands for javadoc comment lines (while jvdc stands 521 * for number of javadoc comments). 522 */ 523 public int getJdcl() { 524 return JavaParserTokenManager._iFormalComments; 525 } 526 527 public int getSl() { 528 return JavaParserTokenManager._iSingleComments; 529 } 530 531 public int getMl() { 532 return JavaParserTokenManager._iMultiComments; 533 } 534 // 535 536 public List getFunctionMetrics() { 537 return(_vFunctionMetrics); 538 } 539 540 public List/*<ObjectMetric>*/ getObjectMetrics() { 541 return(_vObjectMetrics); 542 } 543 544 /** 545 * Returns list of packages in the form 546 * PackageMetric objects. 547 */ 548 public List getPackageMetrics() { 549 return(_vPackageMetrics); 550 } 551 552 public String getLastErrorMessage() { 553 if (_sErrorMessage == null) { 554 return null; 555 } 556 return _sErrorMessage; 557 } 558 559 public Throwable getLastError() { 560 return _thrwError; 561 } 562 563 public void setExit() { 564 _bExit = true; 565 } 566 567 568 public String getEncoding() 569 { 570 return encoding; 571 } 572 573 public void setEncoding( String encoding ) 574 { 575 this.encoding = encoding; 576 } 577 578 private Reader newReader( InputStream stream ) throws UnsupportedEncodingException 579 { 580 return ( encoding == null ) ? new InputStreamReader( stream ) : new InputStreamReader( stream, encoding ); 581 } 582 583 private Reader newReader( File file ) throws FileNotFoundException, UnsupportedEncodingException 584 { 585 return newReader( new FileInputStream( file ) ); 586 } 587}