1 package com.google.code.jetm.maven;
2
3 import java.io.File;
4 import java.io.FileNotFoundException;
5 import java.io.FileReader;
6 import java.text.DecimalFormat;
7 import java.util.ArrayList;
8 import java.util.Collection;
9 import java.util.Collections;
10 import java.util.HashMap;
11 import java.util.LinkedHashMap;
12 import java.util.LinkedList;
13 import java.util.List;
14 import java.util.Locale;
15 import java.util.Map;
16 import java.util.Map.Entry;
17
18 import org.apache.commons.io.FileUtils;
19 import org.apache.commons.io.IOUtils;
20 import org.apache.commons.io.filefilter.TrueFileFilter;
21 import org.apache.maven.doxia.sink.Sink;
22 import org.apache.maven.doxia.siterenderer.Renderer;
23 import org.apache.maven.project.MavenProject;
24 import org.apache.maven.reporting.AbstractMavenReport;
25 import org.apache.maven.reporting.MavenReportException;
26
27 import com.google.code.jetm.maven.data.AggregateSummary;
28 import com.google.code.jetm.maven.util.XmlIOFileFilter;
29 import com.google.code.jetm.reporting.AggregateBinder;
30 import com.google.code.jetm.reporting.xml.XmlAggregateBinder;
31
32 import etm.core.aggregation.Aggregate;
33
34
35
36
37
38
39
40
41
42
43 public class TimingReportMojo extends AbstractMavenReport {
44
45
46
47
48
49
50 private File[] timings;
51
52
53
54
55
56
57
58
59 private String outputDirectory;
60
61
62
63
64
65
66 private MavenProject project;
67
68
69
70
71
72
73 private Renderer siteRenderer;
74
75
76
77
78 public String getOutputName() {
79 return "jetm-timing-report";
80 }
81
82
83
84
85 public String getName(Locale locale) {
86 return "JETM Timing Report";
87 }
88
89
90
91
92 public String getDescription(Locale locale) {
93 return "A collective report of all JETM timings that were collected and rendered.";
94 }
95
96
97
98
99 protected Renderer getSiteRenderer() {
100 return siteRenderer;
101 }
102
103
104
105
106 protected String getOutputDirectory() {
107 return outputDirectory;
108 }
109
110
111
112
113 protected MavenProject getProject() {
114 return project;
115 }
116
117 private DecimalFormat decimalFormatter = new DecimalFormat("0.00");
118 private final AggregateBinder binder = new XmlAggregateBinder();
119 private final XmlIOFileFilter xmlFileFilter = new XmlIOFileFilter();
120
121
122
123
124 protected void executeReport(Locale locale) throws MavenReportException {
125 final Map<File, List<Aggregate>> aggregates = getAggregates();
126 final List<AggregateSummary> summaries = aggregate(aggregates);
127 Collections.sort(summaries);
128
129 final Sink sink = getSink();
130 try {
131 sink.head();
132 sink.title();
133 sink.text(getName(locale));
134 sink.title_();
135 sink.head_();
136
137 sink.body();
138 sink.sectionTitle1();
139 sink.text(getName(locale));
140 sink.sectionTitle1_();
141
142 if (summaries.isEmpty()) {
143 sink.text(" There are no JETM timings available for reporting.");
144 return;
145 }
146
147 sink.sectionTitle2();
148 sink.text("Summary");
149 sink.sectionTitle2_();
150
151 sink.text("This is a summary, by measurement name, of the measurements taken.");
152
153 print(sink, summaries);
154
155 sink.sectionTitle2();
156 sink.text("File Breakdown");
157 sink.sectionTitle2_();
158
159 sink.text("This is a list of, per XML file, the measurements taken.");
160
161 for (Entry<File, List<Aggregate>> entry : aggregates.entrySet()) {
162 sink.sectionTitle3();
163 sink.text(entry.getKey().getName());
164 sink.sectionTitle3_();
165
166 print(sink, entry.getValue());
167 }
168 } finally {
169 sink.body_();
170
171 sink.flush();
172 sink.close();
173 }
174 }
175
176
177
178
179
180
181
182
183
184
185 private void print(Sink sink, Collection<? extends Aggregate> aggregates) {
186 sink.table();
187 sink.tableRows(null, false);
188 sink.tableRow();
189 tableHeaderCell(sink, "Name");
190 tableHeaderCell(sink, "Average (sec)");
191 tableHeaderCell(sink, "Measurements");
192 tableHeaderCell(sink, "Minimum (sec)");
193 tableHeaderCell(sink, "Maximum (sec)");
194 tableHeaderCell(sink, "Total");
195 sink.tableRow_();
196 for (Aggregate aggregate : aggregates) {
197 sink.tableRow();
198 tableCell(sink, aggregate.getName());
199 tableCell(sink, decimalFormatter.format((aggregate.getTotal() / aggregate
200 .getMeasurements()) / 1000.0));
201 tableCell(sink, Long.toString(aggregate.getMeasurements()));
202 tableCell(sink, decimalFormatter.format(aggregate.getMin() / 1000.0));
203 tableCell(sink, decimalFormatter.format(aggregate.getMax() / 1000.0));
204 tableCell(sink, decimalFormatter.format(aggregate.getTotal() / 1000.0));
205 sink.tableRow_();
206 }
207 sink.tableRows_();
208 sink.table_();
209 }
210
211
212
213
214
215
216
217
218
219 private void tableHeaderCell(Sink sink, String text) {
220 sink.tableHeaderCell();
221 sink.text(text);
222 sink.tableHeaderCell_();
223 }
224
225
226
227
228
229
230
231
232
233 private void tableCell(Sink sink, String text) {
234 sink.tableCell();
235 sink.text(text);
236 sink.tableCell_();
237 }
238
239
240
241
242
243
244
245
246
247
248
249
250
251 private Map<File, List<Aggregate>> getAggregates() throws MavenReportException {
252 final Map<File, List<Aggregate>> aggregates = new LinkedHashMap<File, List<Aggregate>>();
253 for (File directory : timings) {
254 if (!directory.exists())
255 continue;
256
257 for (File file : FileUtils.listFiles(directory, xmlFileFilter, TrueFileFilter.TRUE)) {
258 final List<Aggregate> aggregateList = new LinkedList<Aggregate>();
259 FileReader reader;
260 try {
261 reader = new FileReader(file);
262 } catch (FileNotFoundException e) {
263 throw new MavenReportException("File not found: " + file, e);
264 }
265 try {
266 final Collection<Aggregate> unbound = binder.unbind(reader);
267 if (unbound.isEmpty())
268 continue;
269 aggregateList.addAll(unbound);
270 } finally {
271 IOUtils.closeQuietly(reader);
272 }
273 aggregates.put(file, aggregateList);
274 }
275 }
276 return aggregates;
277 }
278
279
280
281
282
283
284
285
286
287
288 private List<AggregateSummary> aggregate(Map<File, List<Aggregate>> aggregates) {
289 if (aggregates.isEmpty())
290 return Collections.emptyList();
291
292 final Map<String, AggregateSummary> summaries = new HashMap<String, AggregateSummary>();
293 for (List<Aggregate> aggregateList : aggregates.values())
294 for (Aggregate aggregate : aggregateList) {
295 final String name = aggregate.getName();
296 if (!summaries.containsKey(name))
297 summaries.put(name, new AggregateSummary(name));
298
299 final AggregateSummary summary = summaries.get(name);
300 summary.add(aggregate);
301 }
302
303 final List<AggregateSummary> summaryList = new ArrayList<AggregateSummary>(summaries.size());
304 for (AggregateSummary summary : summaries.values())
305 summaryList.add(summary);
306
307 return summaryList;
308 }
309 }