1 26 27 package net.sourceforge.groboutils.codecoverage.v2.report; 28 29 import java.io.IOException ; 30 import java.text.NumberFormat ; 31 import java.util.HashMap ; 32 import java.util.Iterator ; 33 import java.util.LinkedList ; 34 import java.util.List ; 35 import java.util.Map ; 36 37 import javax.xml.parsers.DocumentBuilder ; 38 import javax.xml.parsers.DocumentBuilderFactory ; 39 40 import net.sourceforge.groboutils.codecoverage.v2.IAnalysisMetaData; 41 42 import org.w3c.dom.Document ; 43 import org.w3c.dom.Element ; 44 import org.w3c.dom.NodeList ; 45 46 47 55 public class XmlCombinedReportGenerator implements IXmlCombinedReportConst 56 { 57 private static final org.apache.log4j.Logger LOG = 58 org.apache.log4j.Logger.getLogger( XmlCombinedReportGenerator.class ); 59 60 61 private static final NumberFormat DFORMAT = NumberFormat.getInstance(); 62 private static final NumberFormat IFORMAT = NumberFormat.getInstance(); 63 static { 64 DFORMAT.setMaximumFractionDigits( 2 ); 65 DFORMAT.setMinimumFractionDigits( 2 ); 66 IFORMAT.setMaximumFractionDigits( 0 ); 67 } 68 69 private DocumentBuilder docBuilder = getDocumentBuilder(); 70 71 72 private static class Report 73 { 74 String measureName; 75 String unitName; 76 Element current; 77 78 public Report( Document doc ) 79 { 80 Element e = doc.getDocumentElement(); 81 if (!T_COVERAGEREPORT.equals( e.getTagName() )) 82 { 83 throw new IllegalArgumentException ( "Document root is not "+ 84 T_COVERAGEREPORT ); 85 } 86 this.measureName = e.getAttribute( A_MEASURE ); 87 this.unitName = e.getAttribute( A_UNIT ); 88 if (this.measureName == null || this.measureName.length() <= 0 89 || this.unitName == null || this.unitName.length() <= 0) 90 { 91 throw new IllegalArgumentException ( 92 "Document root is not a proper "+T_COVERAGEREPORT ); 93 } 94 this.current = e; 95 } 96 97 public Report( String mn, String un, Element c ) 98 { 99 this.measureName = mn; 100 this.unitName = un; 101 this.current = c; 102 } 103 104 public Report getFirst( String childName ) 105 { 106 NodeList list = this.current.getChildNodes(); 107 for (int i = 0; i < list.getLength(); ++i) 108 { 109 if (list.item(i) instanceof Element ) 110 { 111 Element e = (Element )list.item(i); 112 if (e.getTagName().equals( childName )) 113 { 114 return new Report( this.measureName, this.unitName, e ); 115 } 116 } 117 } 118 return null; 119 } 120 121 public Report[] getAll( String childName ) 122 { 123 NodeList list = this.current.getChildNodes(); 124 List out = new LinkedList (); 125 for (int i = list.getLength(); --i >= 0;) 126 { 127 if (list.item(i) instanceof Element ) 128 { 129 Element e = (Element )list.item(i); 130 if (e.getTagName().equals( childName )) 131 { 132 out.add( new Report( this.measureName, this.unitName, 133 e ) ); 134 } 135 } 136 } 137 Report r[] = (Report[])out.toArray( new Report[ out.size() ] ); 138 return r; 139 } 140 } 141 142 143 146 private static class ReportSet 147 { 148 private Map reports = new HashMap (); 149 150 public ReportSet( Document docs[] ) 151 { 152 for (int i = 0; i < docs.length; ++i) 153 { 154 Report r = new Report( docs[i] ); 155 this.reports.put( r.measureName, r ); 156 } 157 } 158 159 public ReportSet( Report r[] ) 160 { 161 for (int i = 0; i < r.length; ++i) 162 { 163 this.reports.put( r[i].measureName, r[i] ); 164 } 165 } 166 167 public ReportSet getFirst( String childName ) 168 { 169 Iterator iter = getMeasureNames(); 170 List reps = new LinkedList (); 171 while (iter.hasNext()) 172 { 173 Report r = getReport( (String )iter.next() ); 174 if (r != null) 175 { 176 r = r.getFirst( childName ); 177 if (r != null) 178 { 179 reps.add( r ); 180 } 181 } 182 } 183 return new ReportSet( (Report[])reps.toArray( 184 new Report[ reps.size() ] ) ); 185 } 186 187 public Report getReport( String measureName ) 188 { 189 Object o = this.reports.get( measureName ); 190 if (!(o instanceof Report)) 191 { 192 throw new IllegalStateException ("Expected Report, but found " 193 +o+" ("+o.getClass()+")" ); 194 } 195 Report r = (Report)o; 196 204 return r; 205 } 206 207 public Report nextReport( Iterator iter ) 209 { 210 return getReport( (String )iter.next() ); 211 } 212 213 public Iterator getMeasureNames() 214 { 215 return this.reports.keySet().iterator(); 216 } 217 } 218 219 220 225 public Element createReport( Document reports[] ) 226 throws IOException 227 { 228 if (reports == null) 229 { 230 throw new IllegalArgumentException ("no null args"); 231 } 232 233 Document doc = this.docBuilder.newDocument(); 234 Element rootEl = createRootNode( doc ); 235 236 ReportSet rootDocs = new ReportSet( reports ); 237 join( doc, rootEl, rootDocs ); 238 239 return rootEl; 240 } 241 242 243 private Element createRootNode( Document doc ) 244 { 245 if (doc == null) 246 { 247 throw new IllegalArgumentException ("no null args"); 248 } 249 250 Element rootEl = doc.createElement( T_COVERAGEREPORT ); 251 doc.appendChild( rootEl ); 252 253 return rootEl; 254 } 255 256 257 private void join( Document doc, Element rootEl, ReportSet reports ) 258 { 259 Element moduleTypesEl = doc.createElement( T_MODULETYPES ); 261 rootEl.appendChild( moduleTypesEl ); 262 Iterator iter = reports.getMeasureNames(); 263 while (iter.hasNext()) 264 { 265 Report r = reports.nextReport( iter ); 266 Element moduleEl = doc.createElement( T_MODULE ); 267 moduleTypesEl.appendChild( moduleEl ); 268 moduleEl.setAttribute( A_MEASURE, r.measureName ); 269 moduleEl.setAttribute( A_UNIT, r.unitName ); 270 } 271 272 joinCoverage( doc, rootEl, reports.getFirst( T_COVER ) ); 274 275 ReportSet[] byPackage = sort( reports, T_PACKAGE, A_NAME ); 277 for (int i = 0; i < byPackage.length; ++i) 278 { 279 joinPackage( doc, rootEl, byPackage[i] ); 280 } 281 282 ReportSet[] byClass = sort( reports, T_CLASSCOVERAGE, A_CLASSSIGNATURE ); 284 for (int i = 0; i < byClass.length; ++i) 285 { 286 joinClass( doc, rootEl, byClass[i] ); 287 } 288 } 289 290 291 private void joinClass( Document doc, Element parentEl, ReportSet reports ) 292 { 293 Iterator iter = reports.getMeasureNames(); 294 if (!iter.hasNext()) 295 { 296 throw new IllegalStateException ("No class elements."); 297 } 298 Element classEl = doc.createElement( T_CLASSCOVERAGE ); 299 parentEl.appendChild( classEl ); 300 301 joinCoverage( doc, classEl, reports.getFirst( T_COVER ) ); 303 304 Report r = reports.nextReport( iter ); 305 iter = null; 306 classEl.setAttribute( A_CLASSSIGNATURE, r.current.getAttribute( A_CLASSSIGNATURE ) ); 307 classEl.setAttribute( A_CLASSNAME, r.current.getAttribute( A_CLASSNAME ) ); 308 classEl.setAttribute( A_PACKAGE, r.current.getAttribute( A_PACKAGE ) ); 309 classEl.setAttribute( A_SOURCEFILE, r.current.getAttribute( A_SOURCEFILE ) ); 310 r = null; 311 312 313 ReportSet[] byMethod = sort( reports, T_METHODCOVERAGE, A_METHODSIGNATURE ); 315 for (int i = 0; i < byMethod.length; ++i) 316 { 317 joinMethod( doc, classEl, byMethod[i] ); 318 } 319 } 320 321 322 private void joinMethod( Document doc, Element parentEl, ReportSet reports ) 323 { 324 Iterator iter = reports.getMeasureNames(); 325 if (!iter.hasNext()) 326 { 327 throw new IllegalStateException ("No class elements."); 328 } 329 330 Element methodEl = doc.createElement( T_METHODCOVERAGE ); 331 parentEl.appendChild( methodEl ); 332 boolean notSetup = true; 333 while (iter.hasNext()) 334 { 335 Report r = reports.nextReport( iter ); 336 if (notSetup) 337 { 338 methodEl.setAttribute( A_METHODSIGNATURE, r.current.getAttribute( A_METHODSIGNATURE ) ); 339 methodEl.setAttribute( A_METHODSIGNATURE_REAL, r.current.getAttribute( A_METHODSIGNATURE_REAL ) ); 340 notSetup = false; 341 } 342 Report marks[] = r.getAll( T_MARK ); 343 for (int i = 0; i < marks.length; ++i) 344 { 345 joinMark( doc, methodEl, marks[i] ); 346 } 347 } 348 349 joinCoverage( doc, methodEl, reports.getFirst( T_COVER ) ); 351 } 352 353 354 private void joinMark( Document doc, Element parentEl, Report mark ) 355 { 356 Element mEl = doc.createElement( T_MARK ); 359 parentEl.appendChild( mEl ); 360 361 mEl.setAttribute( A_MEASURE, mark.measureName ); 362 mEl.setAttribute( A_COVERED, mark.current.getAttribute( A_COVERED ) ); 363 mEl.setAttribute( A_INDEX, mark.current.getAttribute( A_INDEX ) ); 364 mEl.setAttribute( A_TEXT, mark.current.getAttribute( A_TEXT ) ); 365 mEl.setAttribute( A_WEIGHT, mark.current.getAttribute( A_WEIGHT ) ); 366 mEl.setAttribute( A_SOURCELINE, mark.current.getAttribute( A_SOURCELINE ) ); 367 } 368 369 370 373 private void joinPackage( Document doc, Element parentEl, ReportSet reports ) 374 { 375 Iterator iter = reports.getMeasureNames(); 376 if (!iter.hasNext()) 377 { 378 throw new IllegalStateException ("No package elements."); 379 } 380 Element packageEl = doc.createElement( T_PACKAGE ); 381 parentEl.appendChild( packageEl ); 382 383 Report r = reports.nextReport( iter ); 384 iter = null; 385 packageEl.setAttribute( A_NAME, r.current.getAttribute( A_NAME ) ); 386 r = null; 387 388 joinCoverage( doc, packageEl, reports.getFirst( T_COVER ) ); 389 } 390 391 private void joinCoverage( Document doc, Element parentEl, ReportSet reports ) 392 { 393 joinCoverage( doc, parentEl, reports, false ); 394 } 395 396 399 private void joinCoverage( Document doc, Element parentEl, ReportSet reports, boolean debug ) 400 { 401 Element coverEl = doc.createElement( T_COVER ); 402 parentEl.appendChild( coverEl ); 403 if (debug) 404 { 405 System.out.println("jc: Adding coverage to "+parentEl.getTagName()); 406 } 407 408 Iterator iter = reports.getMeasureNames(); 409 int measureCount = 0; 410 int coveredCount = 0; 411 int totalCount = 0; 412 double weightedPercentTotal = 0.0; 413 while (iter.hasNext()) 414 { 415 Report r = reports.nextReport( iter ); 416 if (debug) 417 { 418 System.out.println("jc: - Adding measure "+r.measureName); 419 System.out.println("jc: - measure parent = "+ 420 ((Element )r.current.getParentNode()).getTagName()); 421 } 422 Element modCoverEl = doc.createElement( T_MODULECOVER ); 423 coverEl.appendChild( modCoverEl ); 424 modCoverEl.setAttribute( A_MEASURE, r.measureName ); 425 426 Element cur = r.current; 427 ++measureCount; 428 coveredCount += parseI( cur.getAttribute( A_COVERED ) ); 429 totalCount += parseI( cur.getAttribute( A_TOTAL ) ); 430 weightedPercentTotal += parseD( cur.getAttribute( A_WEIGHTEDPERCENT ) ); 431 432 modCoverEl.setAttribute( A_COVERED_DISP, cur.getAttribute( A_COVERED_DISP ) ); 433 modCoverEl.setAttribute( A_COVERED, cur.getAttribute( A_COVERED ) ); 434 modCoverEl.setAttribute( A_TOTAL_DISP, cur.getAttribute( A_TOTAL_DISP ) ); 435 modCoverEl.setAttribute( A_TOTAL, cur.getAttribute( A_TOTAL ) ); 436 modCoverEl.setAttribute( A_PERCENTCOVERED_DISP, cur.getAttribute( A_PERCENTCOVERED_DISP ) ); 437 modCoverEl.setAttribute( A_PERCENTCOVERED, cur.getAttribute( A_PERCENTCOVERED ) ); 438 modCoverEl.setAttribute( A_WEIGHTEDPERCENT_DISP, cur.getAttribute( A_WEIGHTEDPERCENT_DISP ) ); 439 modCoverEl.setAttribute( A_WEIGHTEDPERCENT, cur.getAttribute( A_WEIGHTEDPERCENT ) ); 440 } 441 442 double perc = 100.0; 443 if (totalCount > 0) 444 { 445 perc = (double)coveredCount * 100.0 / (double)totalCount; 446 } 447 448 double weight = 100.0; 450 if (measureCount > 0) 451 { 452 weight = weightedPercentTotal / (double)measureCount; 453 } 454 455 coverEl.setAttribute( A_COVERED_DISP, format( coveredCount ) ); 456 coverEl.setAttribute( A_COVERED, formatNumber( coveredCount ) ); 457 coverEl.setAttribute( A_TOTAL_DISP, format( totalCount ) ); 458 coverEl.setAttribute( A_TOTAL, formatNumber( totalCount ) ); 459 coverEl.setAttribute( A_PERCENTCOVERED_DISP, format( perc ) ); 460 coverEl.setAttribute( A_PERCENTCOVERED, formatNumber( perc ) ); 461 coverEl.setAttribute( A_WEIGHTEDPERCENT_DISP, format( weight ) ); 462 coverEl.setAttribute( A_WEIGHTEDPERCENT, formatNumber( weight ) ); 463 } 464 465 466 469 470 private String format( int i ) 471 { 472 return IFORMAT.format( (long)i ); 473 } 474 475 476 private String format( double d ) 477 { 478 return DFORMAT.format( d ); 479 } 480 481 482 private String formatNumber( int i ) 483 { 484 return Integer.toString( i ); 485 } 486 487 488 private String formatNumber( double d ) 489 { 490 return Double.toString( d ); 491 } 492 493 494 private int parseI( String s ) 495 { 496 try 497 { 498 return IFORMAT.parse( s ).intValue(); 499 } 500 catch (java.text.ParseException e) 501 { 502 throw new IllegalStateException ( "Expected an integer, but found "+ 503 s ); 504 } 505 } 506 507 508 private double parseD( String s ) 509 { 510 try 511 { 512 return DFORMAT.parse( s ).doubleValue(); 513 } 514 catch (java.text.ParseException e) 515 { 516 throw new IllegalStateException ( "Expected a number, but found "+ 517 s ); 518 } 519 } 520 521 522 private ReportSet[] sort( ReportSet reports, String tagName, 523 String attrName ) 524 { 525 Map reportsByPackage = new HashMap (); 526 Iterator iter = reports.getMeasureNames(); 527 while (iter.hasNext()) 528 { 529 Report r = reports.nextReport( iter ); 530 Report[] subs = r.getAll( tagName ); 531 for (int i = 0; i < subs.length; ++i) 532 { 533 String val = subs[i].current.getAttribute( attrName ); 534 List s = (List )reportsByPackage.get( val ); 535 if (s == null) 536 { 537 s = new LinkedList (); 538 reportsByPackage.put( val, s ); 539 } 540 s.add( subs[i] ); 541 } 542 } 543 List sets = new LinkedList (); 544 iter = reportsByPackage.values().iterator(); 545 while (iter.hasNext()) 546 { 547 List rep = (List )iter.next(); 548 ReportSet rs = new ReportSet( (Report[])rep.toArray( 549 new Report[ rep.size() ] ) ); 550 sets.add( rs ); 551 } 552 return (ReportSet[])sets.toArray( new ReportSet[ sets.size() ] ); 553 } 554 555 556 private static DocumentBuilder getDocumentBuilder() { 557 try { 558 return DocumentBuilderFactory.newInstance().newDocumentBuilder(); 559 } catch (Exception exc) { 560 throw new ExceptionInInitializerError (exc); 561 } 562 } 563 } 564 565 | Popular Tags |