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.List;
29 import java.util.Locale;
30
31 import org.apache.maven.doxia.sink.Sink;
32 import org.apache.maven.doxia.siterenderer.Renderer;
33 import org.apache.maven.plugin.invoker.model.BuildJob;
34 import org.apache.maven.plugin.invoker.model.io.xpp3.BuildJobXpp3Reader;
35 import org.apache.maven.project.MavenProject;
36 import org.apache.maven.reporting.AbstractMavenReport;
37 import org.apache.maven.reporting.MavenReportException;
38 import org.codehaus.plexus.i18n.I18N;
39 import org.codehaus.plexus.util.ReaderFactory;
40 import org.codehaus.plexus.util.StringUtils;
41 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
42
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<BuildJob> buildJobs = new ArrayList<BuildJob>( 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 ( BuildJob buildJob : buildJobs )
198 {
199 renderBuildJob( buildJob, locale );
200 }
201
202 sink.table_();
203
204 sink.body_();
205
206 sink.flush();
207 sink.close();
208 }
209
210 private void constructSummarySection( List<? extends BuildJob> buildJobs, Locale locale )
211 {
212 Sink sink = getSink();
213
214 sink.section2();
215 sink.sectionTitle2();
216
217 sink.text( getText( locale, "report.invoker.summary.title" ) );
218
219 sink.sectionTitle2_();
220 sink.section2_();
221
222
223
224
225
226
227 sink.table();
228 sink.tableRow();
229
230 sinkTableHeader( sink, getText( locale, "report.invoker.summary.number" ) );
231 sinkTableHeader( sink, getText( locale, "report.invoker.summary.success" ) );
232 sinkTableHeader( sink, getText( locale, "report.invoker.summary.failed" ) );
233 sinkTableHeader( sink, getText( locale, "report.invoker.summary.success.rate" ) );
234 sinkTableHeader( sink, getText( locale, "report.invoker.summary.time.total" ) );
235 sinkTableHeader( sink, getText( locale, "report.invoker.summary.time.avg" ) );
236
237 int number = buildJobs.size();
238 int success = 0;
239 int failed = 0;
240 double totalTime = 0;
241
242 for ( BuildJob buildJob : buildJobs )
243 {
244 if ( BuildJob.Result.SUCCESS.equals( buildJob.getResult() ) )
245 {
246 success++;
247 }
248 else if ( !BuildJob.Result.SKIPPED.equals( buildJob.getResult() ) )
249 {
250 failed++;
251 }
252 totalTime += buildJob.getTime();
253 }
254
255 sink.tableRow_();
256 sink.tableRow();
257
258 sinkCell( sink, Integer.toString( number ) );
259 sinkCell( sink, Integer.toString( success ) );
260 sinkCell( sink, Integer.toString( failed ) );
261
262 if ( success + failed > 0 )
263 {
264 sinkCell( sink, percentFormat.format( (double) success / ( success + failed ) ) );
265 }
266 else
267 {
268 sinkCell( sink, "" );
269 }
270
271 sinkCell( sink, secondsFormat.format( totalTime ) );
272
273 sinkCell( sink, secondsFormat.format( totalTime / number ) );
274
275 sink.tableRow_();
276 sink.table_();
277
278 }
279
280 private void renderBuildJob( BuildJob buildJob, Locale locale )
281 {
282 Sink sink = getSink();
283 sink.tableRow();
284 StringBuffer buffer = new StringBuffer();
285 if ( !StringUtils.isEmpty( buildJob.getName() ) && !StringUtils.isEmpty( buildJob.getDescription() ) )
286 {
287 buffer.append( buildJob.getName() );
288 buffer.append( " : " );
289 buffer.append( buildJob.getDescription() );
290 }
291 else
292 {
293 buffer.append( buildJob.getProject() );
294 }
295 sinkCell( sink, buffer.toString() );
296
297 sinkCell( sink, buildJob.getResult() );
298 sinkCell( sink, secondsFormat.format( buildJob.getTime() ) );
299 sinkCell( sink, buildJob.getFailureMessage() );
300 sink.tableRow_();
301 }
302
303 protected String getOutputDirectory()
304 {
305 return outputDirectory.getAbsolutePath();
306 }
307
308 protected MavenProject getProject()
309 {
310 return project;
311 }
312
313 protected Renderer getSiteRenderer()
314 {
315 return siteRenderer;
316 }
317
318 public String getDescription( Locale locale )
319 {
320 return getText( locale, "report.invoker.result.description" );
321 }
322
323 public String getName( Locale locale )
324 {
325 return getText( locale, "report.invoker.result.name" );
326 }
327
328 public String getOutputName()
329 {
330 return "invoker-report";
331 }
332
333 public boolean canGenerateReport()
334 {
335 return ReportUtils.getReportFiles( reportsDirectory ).length > 0;
336 }
337
338 private String getText( Locale locale, String key )
339 {
340 return i18n.getString( "invoker-report", locale, key );
341 }
342
343 private void sinkTableHeader( Sink sink, String header )
344 {
345 sink.tableHeaderCell();
346 sink.text( header );
347 sink.tableHeaderCell_();
348 }
349
350 private void sinkCell( Sink sink, String text )
351 {
352 sink.tableCell();
353 sink.text( text );
354 sink.tableCell_();
355 }
356
357 }