1 package org.apache.maven.reporting;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.doxia.sink.Sink;
23 import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
24 import org.apache.maven.doxia.util.HtmlTools;
25
26 import org.apache.maven.shared.utils.StringUtils;
27
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Properties;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 public abstract class AbstractMavenReportRenderer
51 implements MavenReportRenderer
52 {
53
54 protected Sink sink;
55
56
57 private int section;
58
59
60
61
62
63
64 public AbstractMavenReportRenderer( Sink sink )
65 {
66 this.sink = sink;
67 }
68
69
70 @Override
71 public void render()
72 {
73 sink.head();
74
75 sink.title();
76 text( getTitle() );
77 sink.title_();
78
79 sink.head_();
80
81 sink.body();
82 renderBody();
83 sink.body_();
84
85 sink.flush();
86
87 sink.close();
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115 protected void startSection( String name )
116 {
117 section = section + 1;
118
119 switch ( section )
120 {
121 case 1:
122 sink.section1();
123 sink.sectionTitle1();
124 break;
125 case 2:
126 sink.section2();
127 sink.sectionTitle2();
128 break;
129 case 3:
130 sink.section3();
131 sink.sectionTitle3();
132 break;
133 case 4:
134 sink.section4();
135 sink.sectionTitle4();
136 break;
137 case 5:
138 sink.section5();
139 sink.sectionTitle5();
140 break;
141
142 default:
143
144 break;
145 }
146
147 text( name );
148
149 switch ( section )
150 {
151 case 1:
152 sink.sectionTitle1_();
153 break;
154 case 2:
155 sink.sectionTitle2_();
156 break;
157 case 3:
158 sink.sectionTitle3_();
159 break;
160 case 4:
161 sink.sectionTitle4_();
162 break;
163 case 5:
164 sink.sectionTitle5_();
165 break;
166
167 default:
168
169 break;
170 }
171
172 sink.anchor( HtmlTools.encodeId( name ) );
173 sink.anchor_();
174 }
175
176
177
178
179
180
181
182
183
184
185
186 protected void endSection()
187 {
188 switch ( section )
189 {
190 case 1:
191 sink.section1_();
192 break;
193 case 2:
194 sink.section2_();
195 break;
196 case 3:
197 sink.section3_();
198 break;
199 case 4:
200 sink.section4_();
201 break;
202 case 5:
203 sink.section5_();
204 break;
205
206 default:
207
208 break;
209 }
210
211 section = section - 1;
212
213 if ( section < 0 )
214 {
215 throw new IllegalStateException( "Too many closing sections" );
216 }
217 }
218
219
220
221
222
223
224
225
226
227
228 protected void startTable()
229 {
230 startTable( new int[] {Sink.JUSTIFY_LEFT}, false );
231 }
232
233
234
235
236
237
238
239
240
241
242
243 protected void startTable( int[] justification, boolean grid )
244 {
245 sink.table();
246 sink.tableRows( justification, grid );
247 }
248
249
250
251
252
253
254 protected void endTable()
255 {
256 sink.tableRows_();
257 sink.table_();
258 }
259
260
261
262
263
264
265
266
267
268 protected void tableHeaderCell( String text )
269 {
270 sink.tableHeaderCell();
271
272 text( text );
273
274 sink.tableHeaderCell_();
275 }
276
277
278
279
280
281
282
283
284
285 protected void tableCell( String text )
286 {
287 tableCell( text, false );
288 }
289
290
291
292
293
294
295
296
297
298
299
300
301
302 protected void tableCell( String text, boolean asHtml )
303 {
304 sink.tableCell();
305
306 if ( asHtml )
307 {
308 sink.rawText( text );
309 }
310 else
311 {
312 linkPatternedText( text );
313 }
314
315 sink.tableCell_();
316 }
317
318
319
320
321
322
323
324
325
326
327 protected void tableRow( String[] content )
328 {
329 sink.tableRow();
330
331 if ( content != null )
332 {
333 for ( int i = 0; i < content.length; i++ )
334 {
335 tableCell( content[i] );
336 }
337 }
338
339 sink.tableRow_();
340 }
341
342
343
344
345
346
347
348
349
350 protected void tableHeader( String[] content )
351 {
352 sink.tableRow();
353
354 if ( content != null )
355 {
356 for ( int i = 0; i < content.length; i++ )
357 {
358 tableHeaderCell( content[i] );
359 }
360 }
361
362 sink.tableRow_();
363 }
364
365
366
367
368
369
370
371
372
373 protected void tableCaption( String caption )
374 {
375 sink.tableCaption();
376
377 text( caption );
378
379 sink.tableCaption_();
380 }
381
382
383
384
385
386
387
388
389
390
391
392
393
394 protected void paragraph( String paragraph )
395 {
396 sink.paragraph();
397
398 text( paragraph );
399
400 sink.paragraph_();
401 }
402
403
404
405
406
407
408
409
410
411
412 protected void link( String href, String name )
413 {
414 sink.link( href );
415
416 text( name );
417
418 sink.link_();
419 }
420
421
422
423
424
425
426
427
428 protected void text( String text )
429 {
430 if ( StringUtils.isEmpty( text ) )
431 {
432 sink.text( "-" );
433 }
434 else
435 {
436 sink.text( text );
437 }
438 }
439
440
441
442
443
444
445
446
447
448 protected void verbatimText( String text )
449 {
450 sink.verbatim( SinkEventAttributeSet.BOXED );
451
452 text( text );
453
454 sink.verbatim_();
455 }
456
457
458
459
460
461
462
463
464
465
466
467 protected void verbatimLink( String text, String href )
468 {
469 if ( StringUtils.isEmpty( href ) )
470 {
471 verbatimText( text );
472 }
473 else
474 {
475 sink.verbatim( SinkEventAttributeSet.BOXED );
476
477 link( href, text );
478
479 sink.verbatim_();
480 }
481 }
482
483
484
485
486
487
488
489 protected void javaScript( String jsCode )
490 {
491 sink.rawText( "<script type=\"text/javascript\">\n" + jsCode + "</script>" );
492 }
493
494
495
496
497
498
499
500
501
502
503
504 public void linkPatternedText( String text )
505 {
506 if ( StringUtils.isEmpty( text ) )
507 {
508 text( text );
509 }
510 else
511 {
512 List<String> segments = applyPattern( text );
513
514 if ( segments == null )
515 {
516 text( text );
517 }
518 else
519 {
520 for ( Iterator<String> it = segments.iterator(); it.hasNext(); )
521 {
522 String name = it.next();
523 String href = it.next();
524
525 if ( href == null )
526 {
527 text( name );
528 }
529 else
530 {
531 link( href, name );
532 }
533 }
534 }
535 }
536 }
537
538
539
540
541
542
543
544
545
546
547
548 protected static String createLinkPatternedText( String text, String href )
549 {
550 if ( text == null )
551 {
552 return text;
553 }
554
555 if ( href == null )
556 {
557 return text;
558 }
559
560 return '{' + text + ", " + href + '}';
561 }
562
563
564
565
566
567
568
569 protected static String propertiesToString( Properties props )
570 {
571 if ( props == null || props.isEmpty() )
572 {
573 return "";
574 }
575
576 StringBuilder sb = new StringBuilder();
577
578 for ( Map.Entry<?, ?> entry : props.entrySet() )
579 {
580 if ( sb.length() > 0 )
581 {
582 sb.append( ", " );
583 }
584
585 sb.append( entry.getKey() ).append( "=" ).append( entry.getValue() );
586 }
587
588 return sb.toString();
589 }
590
591
592
593
594
595
596
597
598
599
600
601
602 private static List<String> applyPattern( String text )
603 {
604 if ( StringUtils.isEmpty( text ) )
605 {
606 return null;
607 }
608
609
610
611 List<String> segments = new ArrayList<>();
612
613
614 if ( text.indexOf( "${" ) != -1 )
615 {
616 int lastComma = text.lastIndexOf( "," );
617 int lastSemi = text.lastIndexOf( "}" );
618 if ( lastComma != -1 && lastSemi != -1 && lastComma < lastSemi )
619 {
620 segments.add( text.substring( lastComma + 1, lastSemi ).trim() );
621 segments.add( null );
622 }
623 else
624 {
625 segments.add( text );
626 segments.add( null );
627 }
628
629 return segments;
630 }
631
632 boolean inQuote = false;
633 int braceStack = 0;
634 int lastOffset = 0;
635
636 for ( int i = 0; i < text.length(); i++ )
637 {
638 char ch = text.charAt( i );
639
640 if ( ch == '\'' && !inQuote && braceStack == 0 )
641 {
642
643 if ( i + 1 < text.length() && text.charAt( i + 1 ) == '\'' )
644 {
645 i++;
646 segments.add( text.substring( lastOffset, i ) );
647 segments.add( null );
648 lastOffset = i + 1;
649 }
650 else
651 {
652 inQuote = true;
653 }
654 }
655 else
656 {
657 switch ( ch )
658 {
659 case '{':
660 if ( !inQuote )
661 {
662 if ( braceStack == 0 )
663 {
664 if ( i != lastOffset )
665 {
666 segments.add( text.substring( lastOffset, i ) );
667 segments.add( null );
668 }
669 lastOffset = i + 1;
670 }
671 braceStack++;
672 }
673 break;
674 case '}':
675 if ( !inQuote )
676 {
677 braceStack--;
678 if ( braceStack == 0 )
679 {
680 String subString = text.substring( lastOffset, i );
681 lastOffset = i + 1;
682
683 int lastComma = subString.lastIndexOf( "," );
684 if ( lastComma != -1 )
685 {
686 segments.add( subString.substring( 0, lastComma ).trim() );
687 segments.add( subString.substring( lastComma + 1 ).trim() );
688 }
689 else
690 {
691 segments.add( subString );
692 segments.add( null );
693 }
694 }
695 }
696 break;
697 case '\'':
698 inQuote = false;
699 break;
700 default:
701 break;
702 }
703 }
704 }
705
706 if ( !StringUtils.isEmpty( text.substring( lastOffset ) ) )
707 {
708 segments.add( text.substring( lastOffset ) );
709 segments.add( null );
710 }
711
712 if ( braceStack != 0 )
713 {
714 throw new IllegalArgumentException( "Unmatched braces in the pattern." );
715 }
716
717 if ( inQuote )
718 {
719
720
721 }
722
723 return Collections.unmodifiableList( segments );
724 }
725
726
727
728
729
730 @Override
731 public abstract String getTitle();
732
733
734
735
736 protected abstract void renderBody();
737 }