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