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 tableHeaderCell(sink, "Name");
188 tableHeaderCell(sink, "Average (sec)");
189 tableHeaderCell(sink, "Measurements");
190 tableHeaderCell(sink, "Minimum (sec)");
191 tableHeaderCell(sink, "Maximum (sec)");
192 tableHeaderCell(sink, "Total");
193 for (Aggregate aggregate : aggregates) {
194 sink.tableRow();
195 tableCell(sink, aggregate.getName());
196 tableCell(sink, decimalFormatter.format((aggregate.getTotal() / aggregate
197 .getMeasurements()) / 1000.0));
198 tableCell(sink, Long.toString(aggregate.getMeasurements()));
199 tableCell(sink, decimalFormatter.format(aggregate.getMin() / 1000.0));
200 tableCell(sink, decimalFormatter.format(aggregate.getMax() / 1000.0));
201 tableCell(sink, decimalFormatter.format(aggregate.getTotal() / 1000.0));
202 sink.tableRow_();
203 }
204 sink.table_();
205 }
206
207
208
209
210
211
212
213
214
215 private void tableHeaderCell(Sink sink, String text) {
216 sink.tableHeaderCell();
217 sink.text(text);
218 sink.tableHeaderCell_();
219 }
220
221
222
223
224
225
226
227
228
229 private void tableCell(Sink sink, String text) {
230 sink.tableCell();
231 sink.text(text);
232 sink.tableCell_();
233 }
234
235
236
237
238
239
240
241
242
243
244
245
246
247 private Map<File, List<Aggregate>> getAggregates() throws MavenReportException {
248 final Map<File, List<Aggregate>> aggregates = new LinkedHashMap<File, List<Aggregate>>();
249 for (File directory : timings) {
250 if (!directory.exists())
251 continue;
252
253 for (File file : FileUtils.listFiles(directory, xmlFileFilter, TrueFileFilter.TRUE)) {
254 final List<Aggregate> aggregateList = new LinkedList<Aggregate>();
255 FileReader reader;
256 try {
257 reader = new FileReader(file);
258 } catch (FileNotFoundException e) {
259 throw new MavenReportException("File not found: " + file, e);
260 }
261 try {
262 final Collection<Aggregate> unbound = binder.unbind(reader);
263 if (unbound.isEmpty())
264 continue;
265 aggregateList.addAll(unbound);
266 } finally {
267 IOUtils.closeQuietly(reader);
268 }
269 aggregates.put(file, aggregateList);
270 }
271 }
272 return aggregates;
273 }
274
275
276
277
278
279
280
281
282
283
284 private List<AggregateSummary> aggregate(Map<File, List<Aggregate>> aggregates) {
285 if (aggregates.isEmpty())
286 return Collections.emptyList();
287
288 final Map<String, AggregateSummary> summaries = new HashMap<String, AggregateSummary>();
289 for (List<Aggregate> aggregateList : aggregates.values())
290 for (Aggregate aggregate : aggregateList) {
291 final String name = aggregate.getName();
292 if (!summaries.containsKey(name))
293 summaries.put(name, new AggregateSummary(name));
294
295 final AggregateSummary summary = summaries.get(name);
296 summary.add(aggregate);
297 }
298
299 final List<AggregateSummary> summaryList = new ArrayList<AggregateSummary>(summaries.size());
300 for (AggregateSummary summary : summaries.values())
301 summaryList.add(summary);
302
303 return summaryList;
304 }
305 }