1 package org.apache.maven.plugin.invoker;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.text.DecimalFormat;
25 import java.text.DecimalFormatSymbols;
26 import java.text.NumberFormat;
27 import java.util.ArrayList;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Locale;
31
32 import org.apache.maven.doxia.sink.Sink;
33 import org.apache.maven.doxia.siterenderer.Renderer;
34 import org.apache.maven.plugin.invoker.model.BuildJob;
35 import org.apache.maven.plugin.invoker.model.io.xpp3.BuildJobXpp3Reader;
36 import org.apache.maven.project.MavenProject;
37 import org.apache.maven.reporting.AbstractMavenReport;
38 import org.apache.maven.reporting.MavenReportException;
39 import org.codehaus.plexus.i18n.I18N;
40 import org.codehaus.plexus.util.ReaderFactory;
41 import org.codehaus.plexus.util.StringUtils;
42 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
43
44
45
46
47
48
49
50
51
52
53 public class InvokerReport
54 extends AbstractMavenReport
55 {
56
57
58
59
60
61
62
63
64 protected MavenProject project;
65
66
67
68
69
70
71 protected Renderer siteRenderer;
72
73
74
75
76
77
78 protected I18N i18n;
79
80
81
82
83
84
85
86
87
88 protected File outputDirectory;
89
90
91
92
93
94
95 private File reportsDirectory;
96
97
98
99
100 private NumberFormat percentFormat;
101
102
103
104
105 private NumberFormat secondsFormat;
106
107 protected void executeReport( Locale locale )
108 throws MavenReportException
109 {
110 DecimalFormatSymbols symbols = new DecimalFormatSymbols( locale );
111 percentFormat = new DecimalFormat( getText( locale, "report.invoker.format.percent" ), symbols );
112 secondsFormat = new DecimalFormat( getText( locale, "report.invoker.format.seconds" ), symbols );
113
114 Sink sink = getSink();
115
116 sink.head();
117
118 sink.title();
119 sink.text( getText( locale, "report.invoker.result.title" ) );
120 sink.title_();
121
122 sink.head_();
123
124 sink.body();
125
126 sink.section1();
127 sink.sectionTitle1();
128 sink.text( getText( locale, "report.invoker.result.title" ) );
129 sink.sectionTitle1_();
130 sink.paragraph();
131 sink.text( getText( locale, "report.invoker.result.description" ) );
132 sink.paragraph_();
133 sink.section1_();
134
135
136
137
138 File[] reportFiles = ReportUtils.getReportFiles( reportsDirectory );
139 if ( reportFiles.length <= 0 )
140 {
141 getLog().info( "no invoker report files found, skip report generation" );
142 return;
143 }
144
145 List buildJobs = new ArrayList( reportFiles.length );
146 for ( int i = 0, size = reportFiles.length; i < size; i++ )
147 {
148 File reportFile = reportFiles[i];
149 try
150 {
151 BuildJobXpp3Reader reader = new BuildJobXpp3Reader();
152 buildJobs.add( reader.read( ReaderFactory.newXmlReader( reportFile ) ) );
153 }
154 catch ( XmlPullParserException e )
155 {
156 throw new MavenReportException( "Failed to parse report file: " + reportFile, e );
157 }
158 catch ( IOException e )
159 {
160 throw new MavenReportException( "Failed to read report file: " + reportFile, e );
161 }
162 }
163
164
165
166
167
168 constructSummarySection( buildJobs, locale );
169
170
171
172
173
174 sink.section2();
175 sink.sectionTitle2();
176
177 sink.text( getText( locale, "report.invoker.detail.title" ) );
178
179 sink.sectionTitle2_();
180
181 sink.section2_();
182
183
184 sink.table();
185
186 sink.tableRow();
187
188
189
190 sinkTableHeader( sink, getText( locale, "report.invoker.detail.name" ) );
191 sinkTableHeader( sink, getText( locale, "report.invoker.detail.result" ) );
192 sinkTableHeader( sink, getText( locale, "report.invoker.detail.time" ) );
193 sinkTableHeader( sink, getText( locale, "report.invoker.detail.message" ) );
194
195 sink.tableRow_();
196
197 for ( Iterator iterator = buildJobs.iterator(); iterator.hasNext(); )
198 {
199 BuildJob buildJob = (BuildJob) iterator.next();
200 renderBuildJob( buildJob, locale );
201 }
202
203 sink.table_();
204
205 sink.body_();
206
207 sink.flush();
208 sink.close();
209 }
210
211 private void constructSummarySection( List
212 {
213 Sink sink = getSink();
214
215 sink.section2();
216 sink.sectionTitle2();
217
218 sink.text( getText( locale, "report.invoker.summary.title" ) );
219
220 sink.sectionTitle2_();
221 sink.section2_();
222
223
224
225
226
227
228 sink.table();
229 sink.tableRow();
230
231 sinkTableHeader( sink, getText( locale, "report.invoker.summary.number" ) );
232 sinkTableHeader( sink, getText( locale, "report.invoker.summary.success" ) );
233 sinkTableHeader( sink, getText( locale, "report.invoker.summary.failed" ) );
234 sinkTableHeader( sink, getText( locale, "report.invoker.summary.success.rate" ) );
235 sinkTableHeader( sink, getText( locale, "report.invoker.summary.time.total" ) );
236 sinkTableHeader( sink, getText( locale, "report.invoker.summary.time.avg" ) );
237
238 int number = buildJobs.size();
239 int success = 0;
240 int failed = 0;
241 double totalTime = 0;
242
243 for ( Iterator iterator = buildJobs.iterator(); iterator.hasNext(); )
244 {
245 BuildJob buildJob = (BuildJob) iterator.next();
246 if ( BuildJob.Result.SUCCESS.equals( buildJob.getResult() ) )
247 {
248 success++;
249 }
250 else if ( !BuildJob.Result.SKIPPED.equals( buildJob.getResult() ) )
251 {
252 failed++;
253 }
254 totalTime += buildJob.getTime();
255 }
256
257 sink.tableRow_();
258 sink.tableRow();
259
260 sinkCell( sink, Integer.toString( number ) );
261 sinkCell( sink, Integer.toString( success ) );
262 sinkCell( sink, Integer.toString( failed ) );
263
264 if ( success + failed > 0 )
265 {
266 sinkCell( sink, percentFormat.format( (double) success / ( success + failed ) ) );
267 }
268 else
269 {
270 sinkCell( sink, "" );
271 }
272
273 sinkCell( sink, secondsFormat.format( totalTime ) );
274
275 sinkCell( sink, secondsFormat.format( totalTime / number ) );
276
277 sink.tableRow_();
278 sink.table_();
279
280 }
281
282 private void renderBuildJob( BuildJob buildJob, Locale locale )
283 {
284 Sink sink = getSink();
285 sink.tableRow();
286 StringBuffer buffer = new StringBuffer();
287 if ( !StringUtils.isEmpty( buildJob.getName() ) && !StringUtils.isEmpty( buildJob.getDescription() ) )
288 {
289 buffer.append( buildJob.getName() );
290 buffer.append( " : " );
291 buffer.append( buildJob.getDescription() );
292 }
293 else
294 {
295 buffer.append( buildJob.getProject() );
296 }
297 sinkCell( sink, buffer.toString() );
298
299 sinkCell( sink, buildJob.getResult() );
300 sinkCell( sink, secondsFormat.format( buildJob.getTime() ) );
301 sinkCell( sink, buildJob.getFailureMessage() );
302 sink.tableRow_();
303 }
304
305 protected String getOutputDirectory()
306 {
307 return outputDirectory.getAbsolutePath();
308 }
309
310 protected MavenProject getProject()
311 {
312 return project;
313 }
314
315 protected Renderer getSiteRenderer()
316 {
317 return siteRenderer;
318 }
319
320 public String getDescription( Locale locale )
321 {
322 return getText( locale, "report.invoker.result.description" );
323 }
324
325 public String getName( Locale locale )
326 {
327 return getText( locale, "report.invoker.result.name" );
328 }
329
330 public String getOutputName()
331 {
332 return "invoker-report";
333 }
334
335 public boolean canGenerateReport()
336 {
337 return ReportUtils.getReportFiles( reportsDirectory ).length > 0;
338 }
339
340 private String getText( Locale locale, String key )
341 {
342 return i18n.getString( "invoker-report", locale, key );
343 }
344
345 private void sinkTableHeader( Sink sink, String header )
346 {
347 sink.tableHeaderCell();
348 sink.text( header );
349 sink.tableHeaderCell_();
350 }
351
352 private void sinkCell( Sink sink, String text )
353 {
354 sink.tableCell();
355 sink.text( text );
356 sink.tableCell_();
357 }
358
359 }