1 package org.apache.maven.doxia.module.confluence;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.PrintWriter;
23 import java.io.StringWriter;
24 import java.io.Writer;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Stack;
28
29 import javax.swing.text.html.HTML.Attribute;
30
31 import org.apache.maven.doxia.sink.SinkEventAttributes;
32 import org.apache.maven.doxia.sink.impl.AbstractTextSink;
33 import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
34 import org.apache.maven.doxia.util.HtmlTools;
35 import org.codehaus.plexus.util.StringUtils;
36
37
38
39
40
41
42
43
44
45 public class ConfluenceSink
46 extends AbstractTextSink
47 implements ConfluenceMarkup
48 {
49
50 private final PrintWriter out;
51
52
53 private StringWriter writer;
54
55
56 private boolean headFlag;
57
58 private int levelList = 0;
59
60
61 private final Stack<String> listStyles;
62
63
64 private boolean monospacedFlag;
65
66
67 protected Stack<List<String>> inlineStack = new Stack<>();
68
69
70 private boolean verbatimBoxedFlag;
71
72
73 private boolean tableFlag;
74
75
76 private boolean tableHeaderFlag;
77
78
79 private String linkName;
80
81
82
83
84
85
86
87 protected ConfluenceSink( Writer writer )
88 {
89 this.out = new PrintWriter( writer );
90 this.listStyles = new Stack<>();
91
92 init();
93 }
94
95
96 public void anchor( String name )
97 {
98 write( ANCHOR_START_MARKUP + name + ANCHOR_END_MARKUP );
99 }
100
101
102 public void anchor( String name, SinkEventAttributes attributes )
103 {
104 anchor( name );
105 }
106
107
108
109
110
111 public void anchor_()
112 {
113
114 }
115
116
117
118
119
120 public void author()
121 {
122
123 }
124
125
126 public void author( SinkEventAttributes attributes )
127 {
128 author();
129 }
130
131
132
133
134
135 public void author_()
136 {
137
138 }
139
140
141
142
143
144 public void body()
145 {
146
147 }
148
149
150 public void body( SinkEventAttributes attributes )
151 {
152 body();
153 }
154
155
156
157
158
159 public void body_()
160 {
161
162 }
163
164
165
166
167 public void bold()
168 {
169 inline( SinkEventAttributeSet.Semantics.BOLD );
170 }
171
172
173
174
175 public void bold_()
176 {
177 inline_();
178 }
179
180
181
182
183
184 public void comment( String comment )
185 {
186
187 }
188
189
190
191
192 public void close()
193 {
194 out.write( writer.toString() );
195 out.close();
196
197 init();
198 }
199
200
201
202
203
204 public void date()
205 {
206
207 }
208
209
210 public void date( SinkEventAttributes attributes )
211 {
212 date();
213 }
214
215
216
217
218
219 public void date_()
220 {
221
222 }
223
224
225
226
227 public void definedTerm()
228 {
229
230 }
231
232
233 public void definedTerm( SinkEventAttributes attributes )
234 {
235 definedTerm();
236 }
237
238
239
240
241 public void definedTerm_()
242 {
243 writeEOL( true );
244 }
245
246
247
248
249 public void definition()
250 {
251 writer.write( CITATION_START_MARKUP );
252 }
253
254
255 public void definition( SinkEventAttributes attributes )
256 {
257 definition();
258 }
259
260
261
262
263 public void definition_()
264 {
265 writer.write( CITATION_END_MARKUP );
266 writeEOL( true );
267 }
268
269
270
271
272
273 public void definitionList()
274 {
275
276 }
277
278
279
280
281
282 public void definitionList( SinkEventAttributes attributes )
283 {
284
285 }
286
287
288
289
290 public void definitionList_()
291 {
292 writeEOL();
293 }
294
295
296
297
298
299 public void definitionListItem()
300 {
301
302 }
303
304
305
306
307
308 public void definitionListItem( SinkEventAttributes attributes )
309 {
310
311 }
312
313
314
315
316
317 public void definitionListItem_()
318 {
319
320 }
321
322
323
324
325
326 public void figure()
327 {
328
329 }
330
331
332 public void figure( SinkEventAttributes attributes )
333 {
334 figure();
335 }
336
337
338
339
340
341 public void figure_()
342 {
343
344 }
345
346
347
348
349
350 public void figureCaption()
351 {
352
353 }
354
355
356 public void figureCaption( SinkEventAttributes attributes )
357 {
358 figureCaption();
359 }
360
361
362
363
364
365 public void figureCaption_()
366 {
367
368 }
369
370
371 public void figureGraphics( String name )
372 {
373 writeEOL();
374 write( FIGURE_START_MARKUP + name + FIGURE_END_MARKUP );
375 }
376
377
378 public void figureGraphics( String src, SinkEventAttributes attributes )
379 {
380 figureGraphics( src );
381 if ( attributes != null && attributes.getAttribute( Attribute.ALT.toString() ) != null )
382 {
383 write( attributes.getAttribute( Attribute.ALT.toString() ).toString() );
384 writeEOL( true );
385 }
386 }
387
388
389
390
391 public void flush()
392 {
393 close();
394 writer.flush();
395 }
396
397
398
399
400 public void head()
401 {
402 init();
403
404 headFlag = true;
405 }
406
407
408 public void head( SinkEventAttributes attributes )
409 {
410 head();
411 }
412
413
414
415
416 public void head_()
417 {
418 headFlag = false;
419 }
420
421
422
423
424
425 public void horizontalRule()
426 {
427
428 }
429
430
431 public void horizontalRule( SinkEventAttributes attributes )
432 {
433 horizontalRule();
434 }
435
436
437
438
439 public void inline()
440 {
441 inline( null );
442 }
443
444
445 public void inline( SinkEventAttributes attributes )
446 {
447 if ( !headFlag )
448 {
449 List<String> tags = new ArrayList<>();
450
451 if ( attributes != null )
452 {
453
454 if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "italic" ) )
455 {
456 write( ITALIC_START_MARKUP );
457 tags.add( 0, ITALIC_END_MARKUP );
458 }
459
460 if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "bold" ) )
461 {
462 write( BOLD_START_MARKUP );
463 tags.add( 0, BOLD_END_MARKUP );
464 }
465
466 if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) )
467 {
468 write( MONOSPACED_START_MARKUP );
469 tags.add( 0, MONOSPACED_END_MARKUP );
470 }
471
472 }
473
474 inlineStack.push( tags );
475 }
476 }
477
478
479
480
481 public void inline_()
482 {
483 if ( !headFlag )
484 {
485 for ( String tag: inlineStack.pop() )
486 {
487 write( tag );
488 }
489 }
490 }
491
492
493
494
495 public void italic()
496 {
497 inline( SinkEventAttributeSet.Semantics.ITALIC );
498 }
499
500
501
502
503 public void italic_()
504 {
505 inline_();
506 }
507
508
509
510
511 public void lineBreak()
512 {
513 write( LINE_BREAK_MARKUP );
514 writeEOL();
515 }
516
517
518 public void lineBreak( SinkEventAttributes attributes )
519 {
520 lineBreak();
521 }
522
523
524 public void link( String name )
525 {
526 linkName = name;
527 }
528
529
530 public void link( String name, SinkEventAttributes attributes )
531 {
532 link( name );
533 }
534
535
536
537
538 public void link_()
539 {
540 linkName = null;
541 write( LINK_END_MARKUP );
542 }
543
544
545
546
547 public void list()
548 {
549 if ( !writer.toString().endsWith( EOL + EOL ) )
550 {
551 writeEOL( true );
552 }
553
554 levelList++;
555 }
556
557
558 public void list( SinkEventAttributes attributes )
559 {
560 list();
561 }
562
563
564
565
566 public void list_()
567 {
568 levelList--;
569 if ( levelList == 0 )
570 {
571 writeEOL( true );
572 writeEOL();
573 }
574 }
575
576
577
578
579 public void listItem()
580 {
581 write( StringUtils.repeat( "*", levelList ) + " " );
582 }
583
584
585 public void listItem( SinkEventAttributes attributes )
586 {
587 listItem();
588 }
589
590
591
592
593 public void listItem_()
594 {
595 writeEOL( true );
596 }
597
598
599
600
601 public void monospaced()
602 {
603 monospacedFlag = true;
604 inline( SinkEventAttributeSet.Semantics.CODE );
605 }
606
607
608
609
610 public void monospaced_()
611 {
612 monospacedFlag = false;
613 inline_();
614 }
615
616
617
618
619
620 public void nonBreakingSpace()
621 {
622
623 }
624
625
626 public void numberedList( int numbering )
627 {
628 if ( !writer.toString().endsWith( EOL + EOL ) )
629 {
630 writeEOL( true );
631 }
632 levelList++;
633
634 String style;
635 switch ( numbering )
636 {
637 case NUMBERING_UPPER_ALPHA:
638 case NUMBERING_LOWER_ALPHA:
639 case NUMBERING_UPPER_ROMAN:
640 case NUMBERING_LOWER_ROMAN:
641 case NUMBERING_DECIMAL:
642 default:
643 style = NUMBERING_MARKUP;
644 }
645
646 listStyles.push( style );
647 }
648
649
650 public void numberedList( int numbering, SinkEventAttributes attributes )
651 {
652 numberedList( numbering );
653 }
654
655
656
657
658 public void numberedList_()
659 {
660 levelList--;
661 if ( levelList == 0 )
662 {
663 writeEOL( true );
664 writeEOL();
665 }
666 listStyles.pop();
667 }
668
669
670
671
672 public void numberedListItem()
673 {
674 writeEOL( true );
675 String style = listStyles.peek();
676
677
678
679
680
681 write( StringUtils.repeat( style, levelList ) + SPACE );
682 }
683
684
685 public void numberedListItem( SinkEventAttributes attributes )
686 {
687 numberedListItem();
688 }
689
690
691
692
693 public void numberedListItem_()
694 {
695 writeEOL( true );
696 }
697
698
699
700
701
702 public void pageBreak()
703 {
704
705 }
706
707
708
709
710
711 public void paragraph()
712 {
713
714 }
715
716
717 public void paragraph( SinkEventAttributes attributes )
718 {
719 paragraph();
720 }
721
722
723
724
725 public void paragraph_()
726 {
727 writeEOL( true );
728 writeEOL();
729 }
730
731
732
733
734
735 public void rawText( String text )
736 {
737
738 }
739
740
741
742
743
744 public void section( int level, SinkEventAttributes attributes )
745 {
746
747 }
748
749
750
751
752
753 public void section1()
754 {
755
756 }
757
758
759
760
761
762 public void section1_()
763 {
764
765 }
766
767
768
769
770
771 public void section2()
772 {
773
774 }
775
776
777
778
779
780 public void section2_()
781 {
782
783 }
784
785
786
787
788
789 public void section3()
790 {
791
792 }
793
794
795
796
797
798 public void section3_()
799 {
800
801 }
802
803
804
805
806
807 public void section4()
808 {
809
810 }
811
812
813
814
815
816 public void section4_()
817 {
818
819 }
820
821
822
823
824
825 public void section5()
826 {
827
828 }
829
830
831
832
833
834 public void section5_()
835 {
836
837 }
838
839
840
841
842
843 public void section_( int level )
844 {
845
846 }
847
848
849
850
851
852 public void sectionTitle()
853 {
854
855 }
856
857
858 public void sectionTitle( int level, SinkEventAttributes attributes )
859 {
860 if ( level > 0 && level < 6 )
861 {
862 write( "h" + level + ". " );
863 }
864 }
865
866
867
868
869 public void sectionTitle1()
870 {
871 sectionTitle( 1, null );
872 }
873
874
875
876
877 public void sectionTitle1_()
878 {
879 sectionTitle_( 1 );
880 }
881
882
883
884
885 public void sectionTitle2()
886 {
887 sectionTitle( 2, null );
888 }
889
890
891
892
893 public void sectionTitle2_()
894 {
895 sectionTitle_( 2 );
896 }
897
898
899
900
901 public void sectionTitle3()
902 {
903 sectionTitle( 3, null );
904 }
905
906
907
908
909 public void sectionTitle3_()
910 {
911 sectionTitle_( 3 );
912 }
913
914
915
916
917 public void sectionTitle4()
918 {
919 sectionTitle( 4, null );
920 }
921
922
923
924
925 public void sectionTitle4_()
926 {
927 sectionTitle_( 4 );
928 }
929
930
931
932
933 public void sectionTitle5()
934 {
935 sectionTitle( 5, null );
936 }
937
938
939
940
941 public void sectionTitle5_()
942 {
943 sectionTitle_( 5 );
944 }
945
946
947
948
949
950 public void sectionTitle_()
951 {
952
953 }
954
955
956 public void sectionTitle_( int level )
957 {
958 writeEOL( true );
959 writeEOL();
960 }
961
962
963
964
965 public void table()
966 {
967
968 tableFlag = true;
969 writeEOL( true );
970 writeEOL();
971 }
972
973
974 public void table( SinkEventAttributes attributes )
975 {
976 table();
977 }
978
979
980
981
982 public void table_()
983 {
984 tableFlag = false;
985 writeEOL( true );
986 writeEOL();
987 }
988
989
990
991
992
993 public void tableCaption()
994 {
995
996 }
997
998
999 public void tableCaption( SinkEventAttributes attributes )
1000 {
1001 tableCaption();
1002 }
1003
1004
1005
1006
1007
1008 public void tableCaption_()
1009 {
1010
1011 }
1012
1013
1014
1015
1016 public void tableCell()
1017 {
1018 write( " " );
1019 }
1020
1021
1022 public void tableCell( SinkEventAttributes attributes )
1023 {
1024 tableCell();
1025 }
1026
1027
1028 public void tableCell( String width )
1029 {
1030 tableCell();
1031 }
1032
1033
1034
1035
1036 public void tableCell_()
1037 {
1038 write( " " );
1039 write( TABLE_CELL_MARKUP );
1040 }
1041
1042
1043
1044
1045 public void tableHeaderCell()
1046 {
1047 tableHeaderFlag = true;
1048 write( TABLE_CELL_HEADER_START_MARKUP );
1049 }
1050
1051
1052 public void tableHeaderCell( SinkEventAttributes attributes )
1053 {
1054 tableHeaderCell();
1055 }
1056
1057
1058 public void tableHeaderCell( String width )
1059 {
1060 tableHeaderCell();
1061 }
1062
1063
1064
1065
1066 public void tableHeaderCell_()
1067 {
1068 write( TABLE_CELL_HEADER_END_MARKUP );
1069 }
1070
1071
1072
1073
1074 public void tableRow()
1075 {
1076 write( TABLE_ROW_MARKUP );
1077 }
1078
1079
1080 public void tableRow( SinkEventAttributes attributes )
1081 {
1082 tableRow();
1083 }
1084
1085
1086
1087
1088 public void tableRow_()
1089 {
1090 if ( tableHeaderFlag )
1091 {
1092 tableHeaderFlag = false;
1093 write( TABLE_ROW_MARKUP );
1094 }
1095 writeEOL( true );
1096 }
1097
1098
1099
1100
1101
1102 public void tableRows( int[] justification, boolean grid )
1103 {
1104
1105 }
1106
1107
1108
1109
1110
1111 public void tableRows_()
1112 {
1113
1114 }
1115
1116
1117 public void text( String text )
1118 {
1119 if ( headFlag )
1120 {
1121 return;
1122 }
1123
1124 if ( linkName != null )
1125 {
1126 write( LINK_START_MARKUP );
1127 }
1128
1129 if ( tableFlag )
1130 {
1131
1132 String strippedText = StringUtils.replace( text, "\n", "" );
1133
1134 if ( StringUtils.isWhitespace( strippedText ) )
1135 {
1136 strippedText = StringUtils.trim( strippedText );
1137 }
1138 content( strippedText );
1139 }
1140 else if ( monospacedFlag )
1141 {
1142 content( text, true );
1143 }
1144 else
1145 {
1146 content( text );
1147 }
1148
1149 if ( linkName != null )
1150 {
1151 write( LINK_MIDDLE_MARKUP + linkName );
1152 }
1153 }
1154
1155
1156 public void text( String text, SinkEventAttributes attributes )
1157 {
1158 if ( attributes == null )
1159 {
1160 text( text );
1161 }
1162 else
1163 {
1164 if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "underline" ) )
1165 {
1166 write( UNDERLINED_START_MARKUP );
1167 }
1168 else if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "line-through" ) )
1169 {
1170 write( STRIKETHROUGH_START_MARKUP );
1171 }
1172 if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sub" ) )
1173 {
1174 write( SUBSCRIPT_START_MARKUP );
1175 }
1176 else if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sup" ) )
1177 {
1178 write( SUPERSCRIPT_START_MARKUP );
1179 }
1180
1181 text( text );
1182
1183 if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sup" ) )
1184 {
1185 write( SUPERSCRIPT_END_MARKUP );
1186 }
1187 else if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sub" ) )
1188 {
1189 write( SUBSCRIPT_END_MARKUP );
1190 }
1191 if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "line-through" ) )
1192 {
1193 write( STRIKETHROUGH_END_MARKUP );
1194 }
1195 else if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "underline" ) )
1196 {
1197 write( UNDERLINED_END_MARKUP );
1198 }
1199 }
1200 }
1201
1202
1203
1204
1205
1206 public void title()
1207 {
1208
1209 }
1210
1211
1212 public void title( SinkEventAttributes attributes )
1213 {
1214 title();
1215 }
1216
1217
1218
1219
1220
1221 public void title_()
1222 {
1223
1224 }
1225
1226
1227
1228
1229
1230 public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes )
1231 {
1232
1233 }
1234
1235
1236 public void verbatim( boolean boxed )
1237 {
1238 if ( boxed )
1239 {
1240 verbatimBoxedFlag = true;
1241 }
1242
1243 if ( verbatimBoxedFlag )
1244 {
1245 write( "{code:borderStyle=solid}" );
1246 }
1247 else
1248 {
1249 write( "{noformat}" );
1250 }
1251 writeEOL( true );
1252 }
1253
1254
1255
1256
1257 public void verbatim_()
1258 {
1259 if ( verbatimBoxedFlag )
1260 {
1261 write( "{code}" );
1262 }
1263 else
1264 {
1265 write( "{noformat}" );
1266 }
1267
1268 writeEOL( true );
1269 writeEOL();
1270 }
1271
1272
1273
1274
1275
1276 private void write( String text )
1277 {
1278 writer.write( unifyEOLs( text ) );
1279 }
1280
1281
1282
1283
1284 private void writeEOL()
1285 {
1286 write( EOL );
1287 }
1288
1289
1290
1291
1292 private void writeEOL( boolean trim )
1293 {
1294 if ( !trim )
1295 {
1296 writeEOL();
1297 return;
1298 }
1299
1300 String tmp = writer.toString().trim();
1301 writer = new StringWriter();
1302 writer.write( tmp );
1303 write( EOL );
1304 }
1305
1306
1307
1308
1309
1310
1311 protected void content( String text )
1312 {
1313 write( escapeHTML( text ) );
1314 }
1315
1316
1317
1318
1319
1320
1321
1322 protected void content( String text, boolean escapeConfluence )
1323 {
1324 if ( escapeConfluence )
1325 {
1326 write( escapeConfluence( escapeHTML( text ) ) );
1327 }
1328 else
1329 {
1330 content( text );
1331 }
1332 }
1333
1334
1335
1336
1337 protected void init()
1338 {
1339 super.init();
1340
1341 this.writer = new StringWriter();
1342 this.monospacedFlag = false;
1343 this.headFlag = false;
1344 this.levelList = 0;
1345 this.listStyles.clear();
1346 this.verbatimBoxedFlag = false;
1347 this.tableHeaderFlag = false;
1348 this.linkName = null;
1349 }
1350
1351
1352
1353
1354
1355
1356
1357 protected static String escapeConfluence( String text )
1358 {
1359 if ( text == null )
1360 {
1361 return "";
1362 }
1363 else
1364 {
1365 int length = text.length();
1366 StringBuilder buffer = new StringBuilder( length );
1367
1368 for ( int i = 0; i < length; ++i )
1369 {
1370 char c = text.charAt( i );
1371 switch ( c )
1372 {
1373 case '{':
1374 buffer.append( "\\{" );
1375 break;
1376 case '}':
1377 buffer.append( "\\}" );
1378 break;
1379 default:
1380 buffer.append( c );
1381 }
1382 }
1383
1384 return buffer.toString();
1385 }
1386 }
1387
1388
1389
1390
1391
1392
1393
1394
1395 protected static String escapeHTML( String text )
1396 {
1397 return HtmlTools.escapeHTML( text );
1398 }
1399 }