1 package org.apache.maven.doxia.parser;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.Reader;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.TreeSet;
27
28 import javax.swing.text.html.HTML.Attribute;
29
30 import org.apache.maven.doxia.macro.MacroExecutionException;
31 import org.apache.maven.doxia.markup.HtmlMarkup;
32 import org.apache.maven.doxia.sink.Sink;
33 import org.apache.maven.doxia.sink.SinkEventAttributeSet;
34 import org.apache.maven.doxia.sink.SinkEventAttributes;
35 import org.apache.maven.doxia.util.DoxiaUtils;
36
37 import org.codehaus.plexus.util.StringUtils;
38 import org.codehaus.plexus.util.xml.pull.XmlPullParser;
39 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
40
41
42
43
44
45
46
47
48
49 public class XhtmlBaseParser
50 extends AbstractXmlParser
51 implements HtmlMarkup
52 {
53
54 private boolean scriptBlock;
55
56
57 private boolean isLink;
58
59
60 private boolean isAnchor;
61
62
63 private int orderedListDepth = 0;
64
65
66 private int sectionLevel;
67
68
69 private boolean inVerbatim;
70
71
72 private boolean inFigure;
73
74
75 private final SinkEventAttributeSet decoration = new SinkEventAttributeSet();
76
77
78
79 private Map<String, Set<String>> warnMessages;
80
81
82 @Override
83 public void parse( Reader source, Sink sink )
84 throws ParseException
85 {
86 init();
87
88 try
89 {
90 super.parse( source, sink );
91 }
92 finally
93 {
94 logWarnings();
95
96 setSecondParsing( false );
97 init();
98 }
99 }
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122 protected boolean baseStartTag( XmlPullParser parser, Sink sink )
123 {
124 boolean visited = true;
125
126 SinkEventAttributeSet attribs = getAttributesFromParser( parser );
127
128 if ( parser.getName().equals( HtmlMarkup.H2.toString() ) )
129 {
130 handleSectionStart( sink, Sink.SECTION_LEVEL_1, attribs );
131 }
132 else if ( parser.getName().equals( HtmlMarkup.H3.toString() ) )
133 {
134 handleSectionStart( sink, Sink.SECTION_LEVEL_2, attribs );
135 }
136 else if ( parser.getName().equals( HtmlMarkup.H4.toString() ) )
137 {
138 handleSectionStart( sink, Sink.SECTION_LEVEL_3, attribs );
139 }
140 else if ( parser.getName().equals( HtmlMarkup.H5.toString() ) )
141 {
142 handleSectionStart( sink, Sink.SECTION_LEVEL_4, attribs );
143 }
144 else if ( parser.getName().equals( HtmlMarkup.H6.toString() ) )
145 {
146 handleSectionStart( sink, Sink.SECTION_LEVEL_5, attribs );
147 }
148 else if ( parser.getName().equals( HtmlMarkup.U.toString() ) )
149 {
150 decoration.addAttribute( SinkEventAttributes.DECORATION, "underline" );
151 }
152 else if ( parser.getName().equals( HtmlMarkup.S.toString() )
153 || parser.getName().equals( HtmlMarkup.STRIKE.toString() )
154 || parser.getName().equals( "del" ) )
155 {
156 decoration.addAttribute( SinkEventAttributes.DECORATION, "line-through" );
157 }
158 else if ( parser.getName().equals( HtmlMarkup.SUB.toString() ) )
159 {
160 decoration.addAttribute( SinkEventAttributes.VALIGN, "sub" );
161 }
162 else if ( parser.getName().equals( HtmlMarkup.SUP.toString() ) )
163 {
164 decoration.addAttribute( SinkEventAttributes.VALIGN, "sup" );
165 }
166 else if ( parser.getName().equals( HtmlMarkup.P.toString() ) )
167 {
168 handlePStart( sink, attribs );
169 }
170 else if ( parser.getName().equals( HtmlMarkup.DIV.toString() ) )
171 {
172 visited = handleDivStart( parser, attribs, sink );
173 }
174 else if ( parser.getName().equals( HtmlMarkup.PRE.toString() ) )
175 {
176 handlePreStart( attribs, sink );
177 }
178 else if ( parser.getName().equals( HtmlMarkup.UL.toString() ) )
179 {
180 sink.list( attribs );
181 }
182 else if ( parser.getName().equals( HtmlMarkup.OL.toString() ) )
183 {
184 handleOLStart( parser, sink, attribs );
185 }
186 else if ( parser.getName().equals( HtmlMarkup.LI.toString() ) )
187 {
188 handleLIStart( sink, attribs );
189 }
190 else if ( parser.getName().equals( HtmlMarkup.DL.toString() ) )
191 {
192 sink.definitionList( attribs );
193 }
194 else if ( parser.getName().equals( HtmlMarkup.DT.toString() ) )
195 {
196 sink.definitionListItem( attribs );
197 sink.definedTerm( attribs );
198 }
199 else if ( parser.getName().equals( HtmlMarkup.DD.toString() ) )
200 {
201 sink.definition( attribs );
202 }
203 else if ( ( parser.getName().equals( HtmlMarkup.B.toString() ) )
204 || ( parser.getName().equals( HtmlMarkup.STRONG.toString() ) ) )
205 {
206 sink.bold();
207 }
208 else if ( ( parser.getName().equals( HtmlMarkup.I.toString() ) )
209 || ( parser.getName().equals( HtmlMarkup.EM.toString() ) ) )
210 {
211 handleFigureCaptionStart( sink, attribs );
212 }
213 else if ( ( parser.getName().equals( HtmlMarkup.CODE.toString() ) )
214 || ( parser.getName().equals( HtmlMarkup.SAMP.toString() ) )
215 || ( parser.getName().equals( HtmlMarkup.TT.toString() ) ) )
216 {
217 sink.monospaced();
218 }
219 else if ( parser.getName().equals( HtmlMarkup.A.toString() ) )
220 {
221 handleAStart( parser, sink, attribs );
222 }
223 else if ( parser.getName().equals( HtmlMarkup.TABLE.toString() ) )
224 {
225 handleTableStart( sink, attribs, parser );
226 }
227 else if ( parser.getName().equals( HtmlMarkup.TR.toString() ) )
228 {
229 sink.tableRow( attribs );
230 }
231 else if ( parser.getName().equals( HtmlMarkup.TH.toString() ) )
232 {
233 sink.tableHeaderCell( attribs );
234 }
235 else if ( parser.getName().equals( HtmlMarkup.TD.toString() ) )
236 {
237 sink.tableCell( attribs );
238 }
239 else if ( parser.getName().equals( HtmlMarkup.CAPTION.toString() ) )
240 {
241 sink.tableCaption( attribs );
242 }
243 else if ( parser.getName().equals( HtmlMarkup.BR.toString() ) )
244 {
245 sink.lineBreak( attribs );
246 }
247 else if ( parser.getName().equals( HtmlMarkup.HR.toString() ) )
248 {
249 sink.horizontalRule( attribs );
250 }
251 else if ( parser.getName().equals( HtmlMarkup.IMG.toString() ) )
252 {
253 handleImgStart( parser, sink, attribs );
254 }
255 else if ( parser.getName().equals( HtmlMarkup.SCRIPT.toString() ) )
256 {
257 handleUnknown( parser, sink, TAG_TYPE_START );
258 scriptBlock = true;
259 }
260 else
261 {
262 visited = false;
263 }
264
265 return visited;
266 }
267
268
269
270
271
272
273
274
275
276
277
278
279
280 protected boolean baseEndTag( XmlPullParser parser, Sink sink )
281 {
282 boolean visited = true;
283
284 if ( parser.getName().equals( HtmlMarkup.P.toString() ) )
285 {
286 if ( !inFigure )
287 {
288 sink.paragraph_();
289 }
290 }
291 else if ( parser.getName().equals( HtmlMarkup.U.toString() )
292 || parser.getName().equals( HtmlMarkup.S.toString() )
293 || parser.getName().equals( HtmlMarkup.STRIKE.toString() )
294 || parser.getName().equals( "del" ) )
295 {
296 decoration.removeAttribute( SinkEventAttributes.DECORATION );
297 }
298 else if ( parser.getName().equals( HtmlMarkup.SUB.toString() )
299 || parser.getName().equals( HtmlMarkup.SUP.toString() ) )
300 {
301 decoration.removeAttribute( SinkEventAttributes.VALIGN );
302 }
303 else if ( parser.getName().equals( HtmlMarkup.DIV.toString() ) )
304 {
305 if ( inFigure )
306 {
307 sink.figure_();
308 this.inFigure = false;
309 }
310 else
311 {
312 visited = false;
313 }
314 }
315 else if ( parser.getName().equals( HtmlMarkup.PRE.toString() ) )
316 {
317 verbatim_();
318
319 sink.verbatim_();
320 }
321 else if ( parser.getName().equals( HtmlMarkup.UL.toString() ) )
322 {
323 sink.list_();
324 }
325 else if ( parser.getName().equals( HtmlMarkup.OL.toString() ) )
326 {
327 sink.numberedList_();
328 orderedListDepth--;
329 }
330 else if ( parser.getName().equals( HtmlMarkup.LI.toString() ) )
331 {
332 handleListItemEnd( sink );
333 }
334 else if ( parser.getName().equals( HtmlMarkup.DL.toString() ) )
335 {
336 sink.definitionList_();
337 }
338 else if ( parser.getName().equals( HtmlMarkup.DT.toString() ) )
339 {
340 sink.definedTerm_();
341 }
342 else if ( parser.getName().equals( HtmlMarkup.DD.toString() ) )
343 {
344 sink.definition_();
345 sink.definitionListItem_();
346 }
347 else if ( ( parser.getName().equals( HtmlMarkup.B.toString() ) )
348 || ( parser.getName().equals( HtmlMarkup.STRONG.toString() ) ) )
349 {
350 sink.bold_();
351 }
352 else if ( ( parser.getName().equals( HtmlMarkup.I.toString() ) )
353 || ( parser.getName().equals( HtmlMarkup.EM.toString() ) ) )
354 {
355 handleFigureCaptionEnd( sink );
356 }
357 else if ( ( parser.getName().equals( HtmlMarkup.CODE.toString() ) )
358 || ( parser.getName().equals( HtmlMarkup.SAMP.toString() ) )
359 || ( parser.getName().equals( HtmlMarkup.TT.toString() ) ) )
360 {
361 sink.monospaced_();
362 }
363 else if ( parser.getName().equals( HtmlMarkup.A.toString() ) )
364 {
365 handleAEnd( sink );
366 }
367
368
369
370
371
372 else if ( parser.getName().equals( HtmlMarkup.TABLE.toString() ) )
373 {
374 sink.tableRows_();
375
376 sink.table_();
377 }
378 else if ( parser.getName().equals( HtmlMarkup.TR.toString() ) )
379 {
380 sink.tableRow_();
381 }
382 else if ( parser.getName().equals( HtmlMarkup.TH.toString() ) )
383 {
384 sink.tableHeaderCell_();
385 }
386 else if ( parser.getName().equals( HtmlMarkup.TD.toString() ) )
387 {
388 sink.tableCell_();
389 }
390 else if ( parser.getName().equals( HtmlMarkup.CAPTION.toString() ) )
391 {
392 sink.tableCaption_();
393 }
394 else if ( parser.getName().equals( HtmlMarkup.H2.toString() ) )
395 {
396 sink.sectionTitle1_();
397 }
398 else if ( parser.getName().equals( HtmlMarkup.H3.toString() ) )
399 {
400 sink.sectionTitle2_();
401 }
402 else if ( parser.getName().equals( HtmlMarkup.H4.toString() ) )
403 {
404 sink.sectionTitle3_();
405 }
406 else if ( parser.getName().equals( HtmlMarkup.H5.toString() ) )
407 {
408 sink.sectionTitle4_();
409 }
410 else if ( parser.getName().equals( HtmlMarkup.H6.toString() ) )
411 {
412 sink.sectionTitle5_();
413 }
414 else if ( parser.getName().equals( HtmlMarkup.SCRIPT.toString() ) )
415 {
416 handleUnknown( parser, sink, TAG_TYPE_END );
417
418 scriptBlock = false;
419 }
420 else
421 {
422 visited = false;
423 }
424
425 return visited;
426 }
427
428
429
430
431
432
433
434 protected void handleStartTag( XmlPullParser parser, Sink sink )
435 throws XmlPullParserException, MacroExecutionException
436 {
437 if ( !baseStartTag( parser, sink ) )
438 {
439 if ( getLog().isWarnEnabled() )
440 {
441 String position = "[" + parser.getLineNumber() + ":"
442 + parser.getColumnNumber() + "]";
443 String tag = "<" + parser.getName() + ">";
444
445 getLog().warn( "Unrecognized xml tag: " + tag + " at " + position );
446 }
447 }
448 }
449
450
451
452
453
454
455
456 protected void handleEndTag( XmlPullParser parser, Sink sink )
457 throws XmlPullParserException, MacroExecutionException
458 {
459 if ( !baseEndTag( parser, sink ) )
460 {
461
462 }
463 }
464
465
466 @Override
467 protected void handleText( XmlPullParser parser, Sink sink )
468 throws XmlPullParserException
469 {
470 String text = getText( parser );
471
472
473
474
475
476
477
478 if ( StringUtils.isNotEmpty( text ) && !isScriptBlock() )
479 {
480 sink.text( text, decoration );
481 }
482 }
483
484
485 @Override
486 protected void handleComment( XmlPullParser parser, Sink sink )
487 throws XmlPullParserException
488 {
489 String text = getText( parser ).trim();
490
491 if ( "PB".equals( text ) )
492 {
493 sink.pageBreak();
494 }
495 else
496 {
497 sink.comment( text );
498 }
499 }
500
501
502 @Override
503 protected void handleCdsect( XmlPullParser parser, Sink sink )
504 throws XmlPullParserException
505 {
506 String text = getText( parser );
507
508 if ( isScriptBlock() )
509 {
510 sink.unknown( CDATA, new Object[] {new Integer( CDATA_TYPE ), text}, null );
511 }
512 else
513 {
514 sink.text( text );
515 }
516 }
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546 protected void consecutiveSections( int newLevel, Sink sink )
547 {
548 closeOpenSections( newLevel, sink );
549 openMissingSections( newLevel, sink );
550
551 this.sectionLevel = newLevel;
552 }
553
554
555
556
557
558
559
560 private void closeOpenSections( int newLevel, Sink sink )
561 {
562 while ( this.sectionLevel >= newLevel )
563 {
564 if ( sectionLevel == Sink.SECTION_LEVEL_5 )
565 {
566 sink.section5_();
567 }
568 else if ( sectionLevel == Sink.SECTION_LEVEL_4 )
569 {
570 sink.section4_();
571 }
572 else if ( sectionLevel == Sink.SECTION_LEVEL_3 )
573 {
574 sink.section3_();
575 }
576 else if ( sectionLevel == Sink.SECTION_LEVEL_2 )
577 {
578 sink.section2_();
579 }
580 else if ( sectionLevel == Sink.SECTION_LEVEL_1 )
581 {
582 sink.section1_();
583 }
584
585 this.sectionLevel--;
586 }
587 }
588
589
590
591
592
593
594
595 private void openMissingSections( int newLevel, Sink sink )
596 {
597 while ( this.sectionLevel < newLevel - 1 )
598 {
599 this.sectionLevel++;
600
601 if ( sectionLevel == Sink.SECTION_LEVEL_5 )
602 {
603 sink.section5();
604 }
605 else if ( sectionLevel == Sink.SECTION_LEVEL_4 )
606 {
607 sink.section4();
608 }
609 else if ( sectionLevel == Sink.SECTION_LEVEL_3 )
610 {
611 sink.section3();
612 }
613 else if ( sectionLevel == Sink.SECTION_LEVEL_2 )
614 {
615 sink.section2();
616 }
617 else if ( sectionLevel == Sink.SECTION_LEVEL_1 )
618 {
619 sink.section1();
620 }
621 }
622 }
623
624
625
626
627
628
629 protected int getSectionLevel()
630 {
631 return this.sectionLevel;
632 }
633
634
635
636
637
638
639 protected void setSectionLevel( int newLevel )
640 {
641 this.sectionLevel = newLevel;
642 }
643
644
645
646
647 protected void verbatim_()
648 {
649 this.inVerbatim = false;
650 }
651
652
653
654
655 protected void verbatim()
656 {
657 this.inVerbatim = true;
658 }
659
660
661
662
663
664
665 protected boolean isVerbatim()
666 {
667 return this.inVerbatim;
668 }
669
670
671
672
673
674
675
676
677 protected boolean isScriptBlock()
678 {
679 return this.scriptBlock;
680 }
681
682
683
684
685
686
687
688
689 protected String validAnchor( String id )
690 {
691 if ( !DoxiaUtils.isValidId( id ) )
692 {
693 String linkAnchor = DoxiaUtils.encodeId( id, true );
694
695 String msg = "Modified invalid link: '" + id + "' to '" + linkAnchor + "'";
696 logMessage( "modifiedLink", msg );
697
698 return linkAnchor;
699 }
700
701 return id;
702 }
703
704
705 @Override
706 protected void init()
707 {
708 super.init();
709
710 this.scriptBlock = false;
711 this.isLink = false;
712 this.isAnchor = false;
713 this.orderedListDepth = 0;
714 this.sectionLevel = 0;
715 this.inVerbatim = false;
716 this.inFigure = false;
717 while ( this.decoration.getAttributeNames().hasMoreElements() )
718 {
719 this.decoration.removeAttribute( this.decoration.getAttributeNames().nextElement() );
720 }
721 this.warnMessages = null;
722 }
723
724 private void handleAEnd( Sink sink )
725 {
726 if ( isLink )
727 {
728 sink.link_();
729 isLink = false;
730 }
731 else if ( isAnchor )
732 {
733 sink.anchor_();
734 isAnchor = false;
735 }
736 }
737
738 private void handleAStart( XmlPullParser parser, Sink sink, SinkEventAttributeSet attribs )
739 {
740 String href = parser.getAttributeValue( null, Attribute.HREF.toString() );
741
742 if ( href != null )
743 {
744 int hashIndex = href.indexOf( '#');
745 if ( hashIndex != -1 && !DoxiaUtils.isExternalLink( href ) )
746 {
747 String hash = href.substring( hashIndex + 1 );
748
749 if ( !DoxiaUtils.isValidId( hash ) )
750 {
751 href = href.substring( 0, hashIndex ) + "#" + DoxiaUtils.encodeId( hash, true );
752
753 String msg = "Modified invalid link: '" + hash + "' to '" + href + "'";
754 logMessage( "modifiedLink", msg );
755 }
756 }
757 sink.link( href, attribs );
758 isLink = true;
759 }
760 else
761 {
762 String name = parser.getAttributeValue( null, Attribute.NAME.toString() );
763
764 if ( name != null )
765 {
766 sink.anchor( validAnchor( name ), attribs );
767 isAnchor = true;
768 }
769 else
770 {
771 String id = parser.getAttributeValue( null, Attribute.ID.toString() );
772 if ( id != null )
773 {
774 sink.anchor( validAnchor( id ), attribs );
775 isAnchor = true;
776 }
777 }
778 }
779 }
780
781 private boolean handleDivStart( XmlPullParser parser, SinkEventAttributeSet attribs, Sink sink )
782 {
783 boolean visited = true;
784
785 String divclass = parser.getAttributeValue( null, Attribute.CLASS.toString() );
786
787 if ( "figure".equals( divclass ) )
788 {
789 this.inFigure = true;
790 SinkEventAttributeSet atts = new SinkEventAttributeSet( attribs );
791 atts.removeAttribute( SinkEventAttributes.CLASS );
792 sink.figure( atts );
793 }
794 else
795 {
796 visited = false;
797 }
798
799 return visited;
800 }
801
802 private void handleFigureCaptionEnd( Sink sink )
803 {
804 if ( inFigure )
805 {
806 sink.figureCaption_();
807 }
808 else
809 {
810 sink.italic_();
811 }
812 }
813
814 private void handleFigureCaptionStart( Sink sink, SinkEventAttributeSet attribs )
815 {
816 if ( inFigure )
817 {
818 sink.figureCaption( attribs );
819 }
820 else
821 {
822 sink.italic();
823 }
824 }
825
826 private void handleImgStart( XmlPullParser parser, Sink sink, SinkEventAttributeSet attribs )
827 {
828 String src = parser.getAttributeValue( null, Attribute.SRC.toString() );
829
830 if ( src != null )
831 {
832 sink.figureGraphics( src, attribs );
833 }
834 }
835
836 private void handleLIStart( Sink sink, SinkEventAttributeSet attribs )
837 {
838 if ( orderedListDepth == 0 )
839 {
840 sink.listItem( attribs );
841 }
842 else
843 {
844 sink.numberedListItem( attribs );
845 }
846 }
847
848 private void handleListItemEnd( Sink sink )
849 {
850 if ( orderedListDepth == 0 )
851 {
852 sink.listItem_();
853 }
854 else
855 {
856 sink.numberedListItem_();
857 }
858 }
859
860 private void handleOLStart( XmlPullParser parser, Sink sink, SinkEventAttributeSet attribs )
861 {
862 int numbering = Sink.NUMBERING_DECIMAL;
863
864 String style = parser.getAttributeValue( null, Attribute.STYLE.toString() );
865
866 if ( style != null )
867 {
868 if ( "list-style-type: upper-alpha".equals( style ) )
869 {
870 numbering = Sink.NUMBERING_UPPER_ALPHA;
871 }
872 else if ( "list-style-type: lower-alpha".equals( style ) )
873 {
874 numbering = Sink.NUMBERING_LOWER_ALPHA;
875 }
876 else if ( "list-style-type: upper-roman".equals( style ) )
877 {
878 numbering = Sink.NUMBERING_UPPER_ROMAN;
879 }
880 else if ( "list-style-type: lower-roman".equals( style ) )
881 {
882 numbering = Sink.NUMBERING_LOWER_ROMAN;
883 }
884 else if ( "list-style-type: decimal".equals( style ) )
885 {
886 numbering = Sink.NUMBERING_DECIMAL;
887 }
888 }
889
890 sink.numberedList( numbering, attribs );
891 orderedListDepth++;
892 }
893
894 private void handlePStart( Sink sink, SinkEventAttributeSet attribs )
895 {
896 if ( !inFigure )
897 {
898 sink.paragraph( attribs );
899 }
900 }
901
902
903
904
905
906
907
908
909
910
911
912 private void handlePreStart( SinkEventAttributeSet attribs, Sink sink )
913 {
914 verbatim();
915 attribs.removeAttribute( SinkEventAttributes.DECORATION );
916 sink.verbatim( attribs );
917 }
918
919 private void handleSectionStart( Sink sink, int level, SinkEventAttributeSet attribs )
920 {
921 consecutiveSections( level, sink );
922 sink.section( level, attribs );
923 sink.sectionTitle( level, attribs );
924 }
925
926 private void handleTableStart( Sink sink, SinkEventAttributeSet attribs, XmlPullParser parser )
927 {
928 sink.table( attribs );
929 String border = parser.getAttributeValue( null, Attribute.BORDER.toString() );
930 boolean grid = true;
931
932 if ( border == null || "0".equals( border ) )
933 {
934 grid = false;
935 }
936
937 String align = parser.getAttributeValue( null, Attribute.ALIGN.toString() );
938 int[] justif = {Sink.JUSTIFY_LEFT};
939
940 if ( "center".equals( align ) )
941 {
942 justif[0] = Sink.JUSTIFY_CENTER;
943 }
944 else if ( "right".equals( align ) )
945 {
946 justif[0] = Sink.JUSTIFY_RIGHT;
947 }
948
949 sink.tableRows( justif, grid );
950 }
951
952
953
954
955
956
957
958
959
960 private void logMessage( String key, String msg )
961 {
962 final String log = "[XHTML Parser] " + msg;
963 if ( getLog().isDebugEnabled() )
964 {
965 getLog().debug( log );
966
967 return;
968 }
969
970 if ( warnMessages == null )
971 {
972 warnMessages = new HashMap<String, Set<String>>();
973 }
974
975 Set<String> set = warnMessages.get( key );
976 if ( set == null )
977 {
978 set = new TreeSet<String>();
979 }
980 set.add( log );
981 warnMessages.put( key, set );
982 }
983
984
985
986
987 private void logWarnings()
988 {
989 if ( getLog().isWarnEnabled() && this.warnMessages != null && !isSecondParsing() )
990 {
991 for ( Map.Entry<String, Set<String>> entry : this.warnMessages.entrySet() )
992 {
993 for ( String msg : entry.getValue() )
994 {
995 getLog().warn( msg );
996 }
997 }
998
999 this.warnMessages = null;
1000 }
1001 }
1002 }