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
041 package net.sourceforge.cobertura.javancss;
042
043 import java.awt.event.WindowAdapter;
044 import java.awt.event.WindowEvent;
045 import java.io.File;
046 import java.io.FileInputStream;
047 import java.io.FileNotFoundException;
048 import java.io.FileOutputStream;
049 import java.io.InputStream;
050 import java.io.IOException;
051 import java.io.InputStreamReader;
052 import java.io.OutputStream;
053 import java.io.OutputStreamWriter;
054 import java.io.PrintWriter;
055 import java.io.Reader;
056 import java.io.UnsupportedEncodingException;
057 import java.util.ArrayList;
058 import java.util.Collections;
059 import java.util.HashMap;
060 import java.util.HashSet;
061 import java.util.Iterator;
062 import java.util.List;
063 import java.util.Map;
064 import java.util.Set;
065
066 import net.sourceforge.cobertura.javancss.ccl.Exitable;
067 import net.sourceforge.cobertura.javancss.ccl.FileUtil;
068 import net.sourceforge.cobertura.javancss.ccl.Init;
069 import net.sourceforge.cobertura.javancss.ccl.Util;
070
071 import net.sourceforge.cobertura.javancss.parser.JavaParser;
072 import net.sourceforge.cobertura.javancss.parser.JavaParserInterface;
073 import net.sourceforge.cobertura.javancss.parser.JavaParserTokenManager;
074 import net.sourceforge.cobertura.javancss.parser.ParseException;
075 import net.sourceforge.cobertura.javancss.parser.TokenMgrError;
076 import net.sourceforge.cobertura.javancss.parser.debug.JavaParserDebug;
077 import net.sourceforge.cobertura.javancss.parser.java15.JavaParser15;
078 import net.sourceforge.cobertura.javancss.parser.java15.debug.JavaParser15Debug;
079 import 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 */
092 public 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 }