1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.apache.maven.plugins.linkcheck;
16
17 import java.util.List;
18 import java.util.Locale;
19
20 import org.apache.commons.io.FilenameUtils;
21
22 import org.apache.maven.doxia.linkcheck.model.LinkcheckFile;
23 import org.apache.maven.doxia.linkcheck.model.LinkcheckFileResult;
24 import org.apache.maven.doxia.linkcheck.model.LinkcheckModel;
25 import org.apache.maven.doxia.sink.Sink;
26
27 import org.codehaus.plexus.i18n.I18N;
28 import org.codehaus.plexus.util.StringUtils;
29
30
31
32
33
34
35 public class LinkcheckReportGenerator
36 {
37 private final I18N i18n;
38
39 private String httpMethod;
40 private boolean offline;
41 private String[] excludedLinks;
42 private Integer[] excludedHttpStatusErrors;
43 private Integer[] excludedHttpStatusWarnings;
44 private String[] excludedPages;
45 private boolean httpFollowRedirect;
46
47
48
49
50
51 public LinkcheckReportGenerator( I18N i18n )
52 {
53 this.i18n = i18n;
54 }
55
56
57
58
59
60 public void setExcludedHttpStatusErrors( Integer[] excludedHttpStatusErrors )
61 {
62 this.excludedHttpStatusErrors = excludedHttpStatusErrors;
63 }
64
65
66
67
68
69 public void setExcludedHttpStatusWarnings( Integer[] excludedHttpStatusWarnings )
70 {
71 this.excludedHttpStatusWarnings = excludedHttpStatusWarnings;
72 }
73
74
75
76
77
78 public void setExcludedLinks( String[] excludedLinks )
79 {
80 this.excludedLinks = excludedLinks;
81 }
82
83
84
85
86
87 public void setExcludedPages( String[] excludedPages )
88 {
89 this.excludedPages = excludedPages;
90 }
91
92
93
94
95
96 public void setHttpFollowRedirect( boolean httpFollowRedirect )
97 {
98 this.httpFollowRedirect = httpFollowRedirect;
99 }
100
101
102
103
104
105 public void setHttpMethod( String httpMethod )
106 {
107 this.httpMethod = httpMethod;
108 }
109
110
111
112
113
114 public void setOffline( boolean offline )
115 {
116 this.offline = offline;
117 }
118
119
120
121
122
123
124
125
126
127 public void generateReport( Locale locale, LinkcheckModel linkcheckModel, Sink sink )
128 {
129 String name = i18n.getString( "linkcheck-report", locale, "report.linkcheck.name" );
130
131 sink.head();
132 sink.title();
133 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.title" ) );
134 sink.title_();
135 sink.head_();
136
137 sink.body();
138
139 if ( linkcheckModel == null )
140 {
141 sink.section1();
142 sink.sectionTitle1();
143 sink.text( name );
144 sink.sectionTitle1_();
145
146 sink.paragraph();
147 sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.empty" ) );
148 sink.paragraph_();
149
150 sink.section1_();
151
152 sink.body_();
153 sink.flush();
154 sink.close();
155
156 return;
157 }
158
159
160 sink.section1();
161 sink.sectionTitle1();
162 sink.text( name );
163 sink.sectionTitle1_();
164
165 sink.paragraph();
166 sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.overview" ) );
167 sink.paragraph_();
168
169 sink.section1_();
170
171
172 generateSummarySection( locale, linkcheckModel, sink );
173
174 if ( linkcheckModel.getFiles().size() > 0 )
175 {
176
177 generateDetailsSection( locale, linkcheckModel, sink );
178 }
179
180 sink.body_();
181 sink.flush();
182 sink.close();
183 }
184
185 private void generateSummarySection( Locale locale, LinkcheckModel linkcheckModel, Sink sink )
186 {
187
188 List linkcheckFiles = linkcheckModel.getFiles();
189
190 int totalFiles = linkcheckFiles.size();
191
192 int totalLinks = 0;
193 int totalValidLinks = 0;
194 int totalErrorLinks = 0;
195 int totalWarningLinks = 0;
196 for (Object linkcheckFile1 : linkcheckFiles) {
197 LinkcheckFile linkcheckFile = (LinkcheckFile) linkcheckFile1;
198
199 totalLinks += linkcheckFile.getNumberOfLinks();
200 totalValidLinks += linkcheckFile.getNumberOfLinks(LinkcheckFileResult.VALID_LEVEL);
201 totalErrorLinks += linkcheckFile.getNumberOfLinks(LinkcheckFileResult.ERROR_LEVEL);
202 totalWarningLinks += linkcheckFile.getNumberOfLinks(LinkcheckFileResult.WARNING_LEVEL);
203 }
204
205 sink.section1();
206 sink.sectionTitle1();
207 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary" ) );
208 sink.sectionTitle1_();
209
210
211 sink.paragraph();
212 sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.overview1" ) );
213 sink.paragraph_();
214
215 sink.table();
216
217 sink.tableRow();
218 sink.tableHeaderCell();
219 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.parameter" ) );
220 sink.tableHeaderCell_();
221 sink.tableHeaderCell();
222 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.value" ) );
223 sink.tableHeaderCell_();
224 sink.tableRow_();
225
226 sink.tableRow();
227 sink.tableCell();
228 sink.rawText(
229 i18n.getString( "linkcheck-report", locale,
230 "report.linkcheck.summary.table.httpFollowRedirect" ) );
231 sink.tableCell_();
232 sink.tableCell();
233 sink.text( String.valueOf( httpFollowRedirect ) );
234 sink.tableCell_();
235 sink.tableRow_();
236
237 sink.tableRow();
238 sink.tableCell();
239 sink
240 .rawText(
241 i18n
242 .getString( "linkcheck-report", locale, "report.linkcheck.summary.table.httpMethod" ) );
243 sink.tableCell_();
244 sink.tableCell();
245 if ( StringUtils.isEmpty( httpMethod ) )
246 {
247 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
248 }
249 else
250 {
251 sink.text( httpMethod );
252 }
253 sink.tableCell_();
254 sink.tableRow_();
255
256 sink.tableRow();
257 sink.tableCell();
258 sink.rawText(
259 i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.offline" ) );
260 sink.tableCell_();
261 sink.tableCell();
262 sink.text( String.valueOf( offline ) );
263 sink.tableCell_();
264 sink.tableRow_();
265
266 sink.tableRow();
267 sink.tableCell();
268 sink.rawText(
269 i18n.getString( "linkcheck-report", locale,
270 "report.linkcheck.summary.table.excludedPages" ) );
271 sink.tableCell_();
272 sink.tableCell();
273 if ( excludedPages == null || excludedPages.length == 0 )
274 {
275 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
276 }
277 else
278 {
279 sink.text( StringUtils.join( excludedPages, "," ) );
280 }
281 sink.tableCell_();
282 sink.tableRow_();
283
284 sink.tableRow();
285 sink.tableCell();
286 sink.rawText(
287 i18n.getString( "linkcheck-report", locale,
288 "report.linkcheck.summary.table.excludedLinks" ) );
289 sink.tableCell_();
290 sink.tableCell();
291 if ( excludedLinks == null || excludedLinks.length == 0 )
292 {
293 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
294 }
295 else
296 {
297 sink.text( StringUtils.join( excludedLinks, "," ) );
298 }
299 sink.tableCell_();
300 sink.tableRow_();
301
302 sink.tableRow();
303 sink.tableCell();
304 sink.rawText(
305 i18n.getString( "linkcheck-report", locale,
306 "report.linkcheck.summary.table.excludedHttpStatusErrors" ) );
307 sink.tableCell_();
308 sink.tableCell();
309 if ( excludedHttpStatusErrors == null || excludedHttpStatusErrors.length == 0 )
310 {
311 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
312 }
313 else
314 {
315 sink.text( toString( excludedHttpStatusErrors ) );
316 }
317 sink.tableCell_();
318 sink.tableRow_();
319
320 sink.tableRow();
321 sink.tableCell();
322 sink.rawText(
323 i18n.getString( "linkcheck-report", locale,
324 "report.linkcheck.summary.table.excludedHttpStatusWarnings" ) );
325 sink.tableCell_();
326 sink.tableCell();
327 if ( excludedHttpStatusWarnings == null || excludedHttpStatusWarnings.length == 0 )
328 {
329 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
330 }
331 else
332 {
333 sink.text( toString( excludedHttpStatusWarnings ) );
334 }
335 sink.tableCell_();
336 sink.tableRow_();
337
338 sink.table_();
339
340
341 sink.paragraph();
342 sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.overview2" ) );
343 sink.paragraph_();
344
345 sink.table();
346
347
348 generateTableHeader( locale, false, sink );
349
350
351 sink.tableRow();
352
353 sink.tableCell();
354 sink.bold();
355 sink.text( totalFiles + "" );
356 sink.bold_();
357 sink.tableCell_();
358 sink.tableCell();
359 sink.bold();
360 sink.text( totalLinks + "" );
361 sink.bold_();
362 sink.tableCell_();
363 sink.tableCell();
364 sink.bold();
365 sink.text( String.valueOf( totalValidLinks ) );
366 sink.bold_();
367 sink.tableCell_();
368 sink.tableCell();
369 sink.bold();
370 sink.text( String.valueOf( totalWarningLinks ) );
371 sink.bold_();
372 sink.tableCell_();
373 sink.tableCell();
374 sink.bold();
375 sink.text( String.valueOf( totalErrorLinks ) );
376 sink.bold_();
377 sink.tableCell_();
378
379 sink.tableRow_();
380
381 sink.table_();
382
383 sink.section1_();
384 }
385
386 private void generateDetailsSection( Locale locale, LinkcheckModel linkcheckModel, Sink sink )
387 {
388 sink.section1();
389 sink.sectionTitle1();
390 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.detail" ) );
391 sink.sectionTitle1_();
392
393 sink.paragraph();
394 sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.detail.overview" ) );
395 sink.paragraph_();
396
397 sink.table();
398
399
400 generateTableHeader( locale, true, sink );
401
402
403 List linkcheckFiles = linkcheckModel.getFiles();
404 for (Object linkcheckFile1 : linkcheckFiles) {
405 LinkcheckFile linkcheckFile = (LinkcheckFile) linkcheckFile1;
406
407 sink.tableRow();
408
409 sink.tableCell();
410 if (linkcheckFile.getUnsuccessful() == 0) {
411 iconValid(locale, sink);
412 } else {
413 iconError(locale, sink);
414 }
415 sink.tableCell_();
416
417
418
419 sink.tableCell();
420 sink.link(linkcheckFile.getRelativePath());
421 sink.text(linkcheckFile.getRelativePath());
422 sink.link_();
423 sink.tableCell_();
424 sink.tableCell();
425 sink.text(String.valueOf(linkcheckFile.getNumberOfLinks()));
426 sink.tableCell_();
427 sink.tableCell();
428 sink.text(String.valueOf(linkcheckFile.getNumberOfLinks(LinkcheckFileResult.VALID_LEVEL)));
429 sink.tableCell_();
430 sink.tableCell();
431 sink.text(String.valueOf(linkcheckFile.getNumberOfLinks(LinkcheckFileResult.WARNING_LEVEL)));
432 sink.tableCell_();
433 sink.tableCell();
434 sink.text(String.valueOf(linkcheckFile.getNumberOfLinks(LinkcheckFileResult.ERROR_LEVEL)));
435 sink.tableCell_();
436
437 sink.tableRow_();
438
439
440 if (linkcheckFile.getUnsuccessful() != 0) {
441 sink.tableRow();
442
443 sink.tableCell();
444 sink.text("");
445 sink.tableCell_();
446
447
448 sink.rawText("<td colspan=\"5\">");
449
450 sink.table();
451
452 for (Object o : linkcheckFile.getResults()) {
453 LinkcheckFileResult linkcheckFileResult = (LinkcheckFileResult) o;
454
455 if (linkcheckFileResult.getStatusLevel() == LinkcheckFileResult.VALID_LEVEL) {
456 continue;
457 }
458
459 sink.tableRow();
460
461 sink.tableCell();
462 if (linkcheckFileResult.getStatusLevel() == LinkcheckFileResult.WARNING_LEVEL) {
463 iconWarning(locale, sink);
464 } else if (linkcheckFileResult.getStatusLevel() == LinkcheckFileResult.ERROR_LEVEL) {
465 iconError(locale, sink);
466 }
467 sink.tableCell_();
468
469 sink.tableCell();
470 sink.italic();
471 if (linkcheckFileResult.getTarget().startsWith("#")) {
472 sink.link(linkcheckFile.getRelativePath() + linkcheckFileResult.getTarget());
473 } else if (linkcheckFileResult.getTarget().startsWith(".")) {
474
475 String absolutePath = FilenameUtils.getFullPath(linkcheckFile.getRelativePath())
476 + linkcheckFileResult.getTarget();
477 String normalizedPath = FilenameUtils.normalize(absolutePath);
478 if (normalizedPath == null) {
479 normalizedPath = absolutePath;
480 }
481 sink.link(normalizedPath);
482 } else {
483 sink.link(linkcheckFileResult.getTarget());
484 }
485
486
487 sink.text(linkcheckFileResult.getTarget());
488 sink.link_();
489 sink.text(": ");
490 sink.text(linkcheckFileResult.getErrorMessage());
491 sink.italic_();
492 sink.tableCell_();
493
494 sink.tableRow_();
495 }
496
497 sink.table_();
498
499 sink.tableCell_();
500
501 sink.tableRow_();
502 }
503 }
504
505 sink.table_();
506
507 sink.section1_();
508 }
509
510 private void generateTableHeader( Locale locale, boolean detail, Sink sink )
511 {
512 sink.tableRow();
513 if ( detail )
514 {
515 sink.rawText( "<th rowspan=\"2\">" );
516 sink.text( "" );
517 sink.tableHeaderCell_();
518 }
519 sink.rawText( "<th rowspan=\"2\">" );
520 sink.text(
521 detail ? i18n.getString( "linkcheck-report", locale,
522 "report.linkcheck.detail.table.documents" )
523 : i18n.getString( "linkcheck-report", locale,
524 "report.linkcheck.summary.table.documents" ) );
525 sink.tableHeaderCell_();
526
527 sink.rawText( "<th colspan=\"4\" align=\"center\">" );
528 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.table.links" ) );
529 sink.tableHeaderCell_();
530 sink.tableRow_();
531
532 sink.tableRow();
533 sink.tableHeaderCell();
534 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.table.totalLinks" ) );
535 sink.tableHeaderCell_();
536 sink.tableHeaderCell();
537 iconValid( locale, sink );
538 sink.tableHeaderCell_();
539 sink.tableHeaderCell();
540 iconWarning( locale, sink );
541 sink.tableHeaderCell_();
542 sink.tableHeaderCell();
543 iconError( locale, sink );
544 sink.tableHeaderCell_();
545 sink.tableRow_();
546 }
547
548 private void iconError( Locale locale, Sink sink )
549 {
550 sink.figure();
551 sink.figureCaption();
552 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.icon.error" ) );
553 sink.figureCaption_();
554 sink.figureGraphics( LinkcheckReport.ICON_ERROR );
555 sink.figure_();
556 }
557
558 private void iconValid( Locale locale, Sink sink )
559 {
560 sink.figure();
561 sink.figureCaption();
562 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.icon.valid" ) );
563 sink.figureCaption_();
564 sink.figureGraphics( LinkcheckReport.ICON_SUCCESS );
565 sink.figure_();
566 }
567
568 private void iconWarning( Locale locale, Sink sink )
569 {
570 sink.figure();
571 sink.figureCaption();
572 sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.icon.warning" ) );
573 sink.figureCaption_();
574 sink.figureGraphics( LinkcheckReport.ICON_WARNING );
575 sink.figure_();
576 }
577
578
579
580
581
582
583
584
585
586
587
588 private static String toString( Object[] a )
589 {
590 if ( a == null || a.length == 0 )
591 {
592 return "";
593 }
594
595 StringBuilder buf = new StringBuilder();
596 buf.append( a[0] );
597
598 for ( int i = 1; i < a.length; i++ )
599 {
600 buf.append( ", " );
601 buf.append( a[i] );
602 }
603
604 return buf.toString();
605 }
606 }