1 23 package org.hammurapi.inspectors.history; 24 25 import java.io.File ; 26 import java.io.IOException ; 27 import java.io.InputStream ; 28 import java.sql.ResultSet ; 29 import java.sql.SQLException ; 30 import java.text.MessageFormat ; 31 import java.util.ArrayList ; 32 import java.util.Collection ; 33 import java.util.Date ; 34 import java.util.Iterator ; 35 import java.util.Properties ; 36 37 import javax.xml.parsers.DocumentBuilderFactory ; 38 import javax.xml.parsers.FactoryConfigurationError ; 39 import javax.xml.parsers.ParserConfigurationException ; 40 import javax.xml.transform.Transformer ; 41 import javax.xml.transform.TransformerConfigurationException ; 42 import javax.xml.transform.TransformerException ; 43 import javax.xml.transform.TransformerFactory ; 44 import javax.xml.transform.dom.DOMSource ; 45 import javax.xml.transform.stream.StreamResult ; 46 import javax.xml.transform.stream.StreamSource ; 47 48 import org.hammurapi.HammurapiException; 49 import org.hammurapi.HammurapiRuntimeException; 50 import org.hammurapi.PersistingInspectorBase; 51 import org.hammurapi.results.AnnotationContext; 52 import org.hammurapi.results.LinkedAnnotation; 53 import org.hammurapi.results.NamedResults; 54 import org.hammurapi.results.ResultsFactory; 55 import org.hammurapi.results.AnnotationContext.FileEntry; 56 import org.hammurapi.results.persistent.jdbc.sql.AggregatedResultsMetricData; 57 import org.hammurapi.results.persistent.jdbc.sql.BasicResultTotal; 58 import org.hammurapi.results.persistent.jdbc.sql.Report; 59 import org.hammurapi.results.persistent.jdbc.sql.ResultsEngine; 60 import org.hammurapi.results.simple.SimpleAggregatedResults; 61 import org.jfree.chart.ChartFactory; 62 import org.jfree.chart.ChartUtilities; 63 import org.jfree.chart.JFreeChart; 64 import org.jfree.chart.plot.PlotOrientation; 65 import org.jfree.data.time.Day; 66 import org.jfree.data.time.TimeSeries; 67 import org.jfree.data.time.TimeSeriesCollection; 68 import org.w3c.dom.Document ; 69 import org.w3c.dom.Element ; 70 71 import com.pavelvlasov.config.ConfigurationException; 72 import com.pavelvlasov.config.XmlSource; 73 import com.pavelvlasov.convert.CompositeConverter; 74 import com.pavelvlasov.jsel.Repository; 75 import com.pavelvlasov.sql.DataAccessObject; 76 import com.pavelvlasov.sql.SQLProcessor; 77 import com.pavelvlasov.xml.dom.AbstractDomObject; 78 import com.pavelvlasov.xml.dom.DOMUtils; 79 80 84 public class HistoryInspector extends PersistingInspectorBase { 85 86 private XmlSource styleConfig; 87 88 public HistoryInspector() { 89 styleConfig=new XmlSource("style", this.getClass(), ".xsl"); 90 addConfigurator(styleConfig); 91 } 92 93 public static class JoinedHistoryImplEx extends JoinedHistoryImpl implements DataAccessObject { 94 private SQLProcessor processor; 95 96 public void toDom(Element holder) { 97 super.toDom(holder); 98 AbstractDomObject.addTextElement(holder, "DPMO", getDPMO()); 99 AbstractDomObject.addTextElement(holder, "Sigma", getSigma()); 100 101 try { 102 String description=new HistoryEngine(processor).getLastDescription(getReportDate()); 103 if (description!=null) { 104 AbstractDomObject.addTextElement(holder, "Description", description); 105 } 106 } catch (SQLException e) { 107 throw new HammurapiRuntimeException(e); 108 } 109 } 110 111 public String getDPMO() { 112 if (getReviews()==0) { 113 return "Not available, no reviews"; 114 } 115 116 return String.valueOf((int) (1000000*getViolationLevel()/getReviews())) + (getHasWarnings()>0 ? "*" : ""); 117 } 118 119 public String getSigma() { 120 double p=1.0-getViolationLevel()/getReviews(); 121 if (getReviews()==0) { 122 return "No results"; 123 } else if (p<=0) { 124 return "Full incompliance"; 125 } else if (p>=1) { 126 return "Full compliance"; 127 } else { 128 return MessageFormat.format("{0,number,#.###}", new Object [] {new Double (SimpleAggregatedResults.normsinv(p)+1.5)}) + (getHasWarnings()>0 ? "*" : ""); 129 } 130 } 131 132 public JoinedHistoryImplEx() { 133 super(); 134 } 135 136 public JoinedHistoryImplEx(ResultSet rs) throws SQLException { 137 super(rs); 138 } 139 140 public void setSQLProcessor(SQLProcessor sqlProcessor) { 141 this.processor=sqlProcessor; 142 } 143 } 144 145 private static abstract class TimeChartGenerator { 146 147 abstract Number getValue(JoinedHistoryImplEx jhie); 148 149 TimeSeries createTimeSeries(Collection series, String title) { 150 TimeSeries timeSeries = new TimeSeries(title); 151 Iterator sit=series.iterator(); 152 while (sit.hasNext()) { 153 JoinedHistoryImplEx jhie=(JoinedHistoryImplEx) sit.next(); 154 timeSeries.add(new Day(new Date (jhie.getReportDate().getTime())), getValue(jhie)); 155 } 156 return timeSeries; 157 } 158 159 void createPngChart(String title, TimeSeries timeSeries, File out) throws IOException { 160 TimeSeriesCollection timeDataset = new TimeSeriesCollection(timeSeries); 161 162 JFreeChart chart = ChartFactory.createTimeSeriesChart( 163 title, "Time", timeSeries.getName(), timeDataset, true, true, 169 true); 170 171 ChartUtilities.saveChartAsPNG(out, chart, 500, 300 ); 172 } 173 174 void createPngBarChart(String title, TimeSeries timeSeries, File out) throws IOException { 175 TimeSeriesCollection timeDataset = new TimeSeriesCollection(timeSeries); 176 177 JFreeChart chart = ChartFactory.createXYBarChart( 178 title, "Time", true, 181 timeSeries.getName(), timeDataset, PlotOrientation.VERTICAL, 184 true, true, 186 true 187 ); 188 189 ChartUtilities.saveChartAsPNG(out, chart, 500, 300 ); 191 } 192 193 } 194 195 public void leave(Repository repository) { 196 getContext().annotate(new LinkedAnnotation() { 197 NamedResults summary=ResultsFactory.getThreadResults(); 198 FileEntry rootFile; 199 200 public String getName() { 201 return "History"; 202 } 203 204 public void render(AnnotationContext context) throws HammurapiException { 205 if (ResultsFactory.getInstance() instanceof org.hammurapi.results.persistent.jdbc.ResultsFactory) { 206 try { 207 SQLProcessor processor=getContext().getSession().getProcessor(); 208 HistoryEngine historyEngine=new HistoryEngine(processor); 209 ResultsEngine resultsEngine = new ResultsEngine(processor); 210 Iterator it=historyEngine.getReportWithoutHistory(summary.getName(), ((org.hammurapi.results.persistent.jdbc.ResultsFactory) ResultsFactory.getInstance()).getReportId()).iterator(); 211 while (it.hasNext()) { 212 Report report=(Report) it.next(); 213 BasicResultTotal result = resultsEngine.getBasicResultTotal(report.getResultId().intValue()); 214 AggregatedResultsMetricData cr = resultsEngine.getAggregatedResultsMetricData(report.getResultId().intValue(), "Change ratio"); 215 216 historyEngine.insertHistory( 217 report.getId(), 218 result.getCodebase(), 219 (Integer ) CompositeConverter.getDefaultConverter().convert(result.getMaxSeverity(), Integer .class, false), 220 result.getReviews(), 221 result.getViolationLevel(), 222 result.getViolations(), 223 result.getWaivedViolations(), 224 (int) result.getHasWarnings(), 225 cr==null ? -1 : cr.getTotalValue()/ cr.getMeasurements(), 226 result.getCompilationUnits(), 227 result.getResultDate(), 228 report.getName(), 229 report.getDescription(), 230 new Long (report.getExecutionTime()==null ? 0 : report.getExecutionTime().longValue())); 231 } 232 233 Document doc=DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 234 Element root = doc.createElement("history"); 235 root.setAttribute("title", summary.getName()); 236 doc.appendChild(root); 237 Collection series=new ArrayList (); 238 DOMUtils.toDom(historyEngine.getJoinedHistory(summary.getName(), series, JoinedHistoryImplEx.class), root); 239 240 if (series.size()>1) { 242 generateNodesChart(context, root, series); 243 generateFilesChart(context, root, series); 244 generateActivityChart(context, root, series); 245 generateSigmaChart(context, root, series); 246 generateDpmoChart(context, root, series); 247 generateMaxSeverityChart(context, root, series); 248 generateViolationsChart(context, root, series); 249 generateReviewsChart(context, root, series); 250 } 252 253 rootFile=context.getNextFile(context.getExtension()); 254 255 if (context.getExtension().equalsIgnoreCase(".html")) { 256 TransformerFactory tFactory = TransformerFactory.newInstance(); 257 InputStream styleStream = styleConfig.getStream(); 258 if (styleStream==null) { 259 throw new HammurapiException("Stylesheet cannot be loaded"); 260 } 261 262 Transformer transformer = tFactory.newTransformer(new StreamSource (styleStream)); 263 264 DOMSource domSource = new DOMSource (doc); 265 transformer.transform(domSource, new StreamResult (rootFile.getFile())); 266 } else { 267 DOMUtils.serialize(doc, rootFile.getFile()); 268 } 269 } catch (ConfigurationException e) { 270 throw new HammurapiException("Cannot render history annotation, "+e.getMessage(), e); 271 } catch (IOException e) { 272 throw new HammurapiException("Cannot render history annotation, "+e.getMessage(), e); 273 } catch (SQLException e) { 274 throw new HammurapiException("Cannot process history annotation, "+e.getMessage(), e); 275 } catch (ParserConfigurationException e) { 276 throw new HammurapiException("Cannot process history annotation, "+e.getMessage(), e); 277 } catch (FactoryConfigurationError e) { 278 throw new HammurapiException("Cannot process history annotation, "+e.getMessage(), e); 279 } catch (TransformerConfigurationException e) { 280 throw new HammurapiException("Cannot process history annotation, "+e.getMessage(), e); 281 } catch (TransformerException e) { 282 throw new HammurapiException("Cannot process history annotation, "+e.getMessage(), e); 283 } 284 } 285 } 286 287 294 private void generateNodesChart(AnnotationContext context, Element root, Collection series) throws HammurapiException, IOException { 295 TimeChartGenerator codeBaseChartGenerator=new TimeChartGenerator() { 296 Number getValue(JoinedHistoryImplEx jhie) { 297 return new Long (jhie.getCodebase()); 298 } 299 }; 300 301 FileEntry codeBaseNodesChart=context.getNextFile(".png"); 302 TimeSeries cbtn = codeBaseChartGenerator.createTimeSeries(series, "Nodes"); 303 codeBaseChartGenerator.createPngChart("Codebase history (nodes)", cbtn, codeBaseNodesChart.getFile()); 304 root.setAttribute("nodes-chart", codeBaseNodesChart.getPath()); 305 } 306 307 314 private void generateFilesChart(AnnotationContext context, Element root, Collection series) throws HammurapiException, IOException { 315 TimeChartGenerator codeBaseChartGenerator=new TimeChartGenerator() { 316 Number getValue(JoinedHistoryImplEx jhie) { 317 return new Long (jhie.getCompilationUnits()); 318 } 319 }; 320 321 FileEntry codeBaseChart=context.getNextFile(".png"); 322 TimeSeries cbtn = codeBaseChartGenerator.createTimeSeries(series, "Files"); 323 codeBaseChartGenerator.createPngChart("Codebase history (files)", cbtn, codeBaseChart.getFile()); 324 root.setAttribute("files-chart", codeBaseChart.getPath()); 325 } 326 327 334 private void generateActivityChart(AnnotationContext context, Element root, Collection series) throws HammurapiException, IOException { 335 TimeChartGenerator chartGenerator=new TimeChartGenerator() { 336 Number getValue(JoinedHistoryImplEx jhie) { 337 return new Integer ((int) (jhie.getChangeRatio() * 100)); 338 } 339 }; 340 341 FileEntry fileEntry=context.getNextFile(".png"); 342 TimeSeries cbtn = chartGenerator.createTimeSeries(series, "Activity (%)"); 343 chartGenerator.createPngBarChart("Activity history", cbtn, fileEntry.getFile()); 344 root.setAttribute("activity-chart", fileEntry.getPath()); 345 } 346 347 354 private void generateSigmaChart(AnnotationContext context, Element root, Collection series) throws HammurapiException, IOException { 355 TimeChartGenerator chartGenerator=new TimeChartGenerator() { 356 Number getValue(JoinedHistoryImplEx jhie) { 357 String sigma=jhie.getSigma(); 358 int idx=sigma.indexOf(' '); 359 try { 360 return new Double (idx==-1 ? sigma : sigma.substring(0, idx)); 361 } catch (NumberFormatException e) { 362 return null; 363 } 364 } 365 }; 366 367 FileEntry fileEntry=context.getNextFile(".png"); 368 TimeSeries cbtn = chartGenerator.createTimeSeries(series, "Sigma"); 369 chartGenerator.createPngChart("Sigma history", cbtn, fileEntry.getFile()); 370 root.setAttribute("sigma-chart", fileEntry.getPath()); 371 } 372 373 380 private void generateDpmoChart(AnnotationContext context, Element root, Collection series) throws HammurapiException, IOException { 381 TimeChartGenerator chartGenerator=new TimeChartGenerator() { 382 Number getValue(JoinedHistoryImplEx jhie) { 383 String dpmo=jhie.getDPMO(); 384 int idx=dpmo.indexOf(' '); 385 try { 386 return new Long (idx==-1 ? dpmo : dpmo.substring(0, idx)); 387 } catch (NumberFormatException e) { 388 return null; 389 } 390 } 391 }; 392 393 FileEntry fileEntry=context.getNextFile(".png"); 394 TimeSeries cbtn = chartGenerator.createTimeSeries(series, "DPMO"); 395 chartGenerator.createPngChart("DPMO history", cbtn, fileEntry.getFile()); 396 root.setAttribute("dpmo-chart", fileEntry.getPath()); 397 } 398 399 406 private void generateViolationsChart(AnnotationContext context, Element root, Collection series) throws HammurapiException, IOException { 407 TimeChartGenerator chartGenerator=new TimeChartGenerator() { 408 Number getValue(JoinedHistoryImplEx jhie) { 409 return new Long (jhie.getViolations()); 410 } 411 }; 412 413 FileEntry fileEntry=context.getNextFile(".png"); 414 TimeSeries cbtn = chartGenerator.createTimeSeries(series, "Violations"); 415 chartGenerator.createPngChart("Violations history", cbtn, fileEntry.getFile()); 416 root.setAttribute("violations-chart", fileEntry.getPath()); 417 } 418 419 426 private void generateMaxSeverityChart(AnnotationContext context, Element root, Collection series) throws HammurapiException, IOException { 427 TimeChartGenerator chartGenerator=new TimeChartGenerator() { 428 Number getValue(JoinedHistoryImplEx jhie) { 429 return new Integer (jhie.getMaxSeverity()); 430 } 431 }; 432 433 FileEntry fileEntry=context.getNextFile(".png"); 434 TimeSeries cbtn = chartGenerator.createTimeSeries(series, "Max severity"); 435 chartGenerator.createPngChart("Max severity history", cbtn, fileEntry.getFile()); 436 root.setAttribute("max-severity-chart", fileEntry.getPath()); 437 } 438 439 446 private void generateReviewsChart(AnnotationContext context, Element root, Collection series) throws HammurapiException, IOException { 447 TimeChartGenerator chartGenerator=new TimeChartGenerator() { 448 Number getValue(JoinedHistoryImplEx jhie) { 449 return new Long (jhie.getReviews()); 450 } 451 }; 452 453 FileEntry fileEntry=context.getNextFile(".png"); 454 TimeSeries cbtn = chartGenerator.createTimeSeries(series, "Reviews"); 455 chartGenerator.createPngChart("Reviews history", cbtn, fileEntry.getFile()); 456 root.setAttribute("reviews-chart", fileEntry.getPath()); 457 } 458 459 public Properties getProperties() { 460 return null; 461 } 462 463 public String getPath() { 464 return rootFile.getPath(); 465 } 466 467 }); 468 } 469 } 470 | Popular Tags |