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