001package org.apache.maven.doxia.sink.impl;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.ByteArrayOutputStream;
023import java.io.File;
024import java.io.FileOutputStream;
025import java.io.IOException;
026import java.io.OutputStream;
027import java.util.ArrayList;
028import java.util.List;
029
030import org.apache.maven.doxia.logging.Log;
031import org.apache.maven.doxia.sink.Sink;
032import org.apache.maven.doxia.sink.SinkEventAttributes;
033import org.apache.maven.doxia.sink.SinkFactory;
034
035/**
036 * The RandomAccessSink provides the ability to create a {@link Sink} with hooks.
037 * A page can be prepared by first creating its structure and specifying the positions of these hooks.
038 * After specifying the structure, the page can be filled with content from one or more models.
039 * These hooks can prevent you to have to loop over the model multiple times to build the page as desired. 
040 * 
041 * @author Robert Scholte
042 * @since 1.3
043 */
044public class RandomAccessSink
045    implements Sink
046{
047    private SinkFactory sinkFactory;
048
049    private String encoding;
050
051    private OutputStream coreOutputStream;
052
053    private Sink coreSink;
054
055    private List<Sink> sinks = new ArrayList<>();
056
057    private List<ByteArrayOutputStream> outputStreams = new ArrayList<>();
058
059    private Sink currentSink;
060
061    public RandomAccessSink( SinkFactory sinkFactory, OutputStream stream )
062        throws IOException
063    {
064        this.sinkFactory = sinkFactory;
065        this.coreOutputStream = stream;
066        this.currentSink = sinkFactory.createSink( stream );
067        this.coreSink = this.currentSink;
068    }
069
070    public RandomAccessSink( SinkFactory sinkFactory, OutputStream stream, String encoding )
071        throws IOException
072    {
073        this.sinkFactory = sinkFactory;
074        this.coreOutputStream = stream;
075        this.encoding = encoding;
076        this.currentSink = sinkFactory.createSink( stream, encoding );
077        this.coreSink = this.currentSink;
078    }
079
080    public RandomAccessSink( SinkFactory sinkFactory, File outputDirectory, String outputName )
081        throws IOException
082    {
083        this.sinkFactory = sinkFactory;
084        this.coreOutputStream = new FileOutputStream( new File( outputDirectory, outputName ) );
085        this.currentSink = sinkFactory.createSink( coreOutputStream );
086        this.coreSink = this.currentSink;
087    }
088
089    public RandomAccessSink( SinkFactory sinkFactory, File outputDirectory, String outputName, String encoding )
090        throws IOException
091    {
092        this.sinkFactory = sinkFactory;
093        this.coreOutputStream = new FileOutputStream( new File( outputDirectory, outputName ) );
094        this.encoding = encoding;
095        this.currentSink = sinkFactory.createSink( coreOutputStream, encoding );
096        this.coreSink = this.currentSink;
097    }
098
099    @Override
100    public void address()
101    {
102        currentSink.address();
103    }
104
105    @Override
106    public void address( SinkEventAttributes attributes )
107    {
108        currentSink.address( attributes );
109    }
110
111    @Override
112    public void address_()
113    {
114        currentSink.address_();
115    }
116
117    /**
118     * By calling this method a sink reference is added at the current position. You can write to both the new sink
119     * reference and the original sink. After flushing all sinks will be flushed in the right order.
120     * 
121     * @return a subsink reference you can write to
122     */
123    public Sink addSinkHook()
124    {
125        Sink subSink = null;
126        try
127        {
128            ByteArrayOutputStream subOut = new ByteArrayOutputStream();
129            ByteArrayOutputStream newOut = new ByteArrayOutputStream();
130
131            outputStreams.add( subOut );
132            outputStreams.add( newOut );
133
134            if ( encoding != null )
135            {
136                subSink = sinkFactory.createSink( subOut, encoding );
137                currentSink = sinkFactory.createSink( newOut, encoding );
138            }
139            else
140            {
141                subSink = sinkFactory.createSink( subOut );
142                currentSink = sinkFactory.createSink( newOut );
143            }
144            sinks.add( subSink );
145            sinks.add( currentSink );
146        }
147        catch ( IOException e )
148        {
149            // IOException can only be caused by our own ByteArrayOutputStream
150        }
151        return subSink;
152    }
153
154    @Override
155    public void anchor( String name )
156    {
157        currentSink.anchor( name );
158    }
159
160    @Override
161    public void anchor( String name, SinkEventAttributes attributes )
162    {
163        currentSink.anchor( name, attributes );
164    }
165
166    @Override
167    public void anchor_()
168    {
169        currentSink.anchor_();
170    }
171
172    @Override
173    public void article()
174    {
175        currentSink.article();
176    }
177
178    @Override
179    public void article( SinkEventAttributes attributes )
180    {
181        currentSink.article( attributes );
182    }
183
184    @Override
185    public void article_()
186    {
187        currentSink.article_();
188    }
189
190    @Override
191    public void author()
192    {
193        currentSink.author();
194    }
195
196    @Override
197    public void author( SinkEventAttributes attributes )
198    {
199        currentSink.author( attributes );
200    }
201
202    @Override
203    public void author_()
204    {
205        currentSink.author_();
206    }
207
208    @Override
209    public void blockquote()
210    {
211        currentSink.blockquote();
212    }
213
214    @Override
215    public void blockquote( SinkEventAttributes attributes )
216    {
217        currentSink.blockquote( attributes );
218    }
219
220    @Override
221    public void blockquote_()
222    {
223        currentSink.blockquote_();
224    }
225
226    @Override
227    public void body()
228    {
229        currentSink.body();
230    }
231
232    @Override
233    public void body( SinkEventAttributes attributes )
234    {
235        currentSink.body( attributes );
236    }
237
238    @Override
239    public void body_()
240    {
241        currentSink.body_();
242    }
243
244    @Override
245    public void bold()
246    {
247        currentSink.bold();
248    }
249
250    @Override
251    public void bold_()
252    {
253        currentSink.bold_();
254    }
255
256    /**
257     * Close all sinks
258     */
259    public void close()
260    {
261        for ( Sink sink  : sinks )
262        {
263            // sink is responsible for closing it's stream
264            sink.close();
265        }
266        coreSink.close();
267    }
268
269    @Override
270    public void comment( String comment )
271    {
272        currentSink.comment( comment );
273    }
274
275    @Override
276    public void content()
277    {
278        currentSink.content();
279    }
280
281    @Override
282    public void content( SinkEventAttributes attributes )
283    {
284        currentSink.content( attributes );
285    }
286
287    @Override
288    public void content_()
289    {
290        currentSink.content_();
291    }
292
293    @Override
294    public void data( String value )
295    {
296        currentSink.data( value );
297    }
298
299    @Override
300    public void data( String value, SinkEventAttributes attributes )
301    {
302        currentSink.data( value, attributes );
303    }
304
305    @Override
306    public void data_()
307    {
308        currentSink.data_();
309    }
310
311    @Override
312    public void date()
313    {
314        currentSink.date();
315    }
316
317    @Override
318    public void date( SinkEventAttributes attributes )
319    {
320        currentSink.date( attributes );
321    }
322
323    @Override
324    public void date_()
325    {
326        currentSink.date_();
327    }
328
329    @Override
330    public void definedTerm()
331    {
332        currentSink.definedTerm();
333    }
334
335    @Override
336    public void definedTerm( SinkEventAttributes attributes )
337    {
338        currentSink.definedTerm( attributes );
339    }
340
341    @Override
342    public void definedTerm_()
343    {
344        currentSink.definedTerm_();
345    }
346
347    @Override
348    public void definition()
349    {
350        currentSink.definition();
351    }
352
353    @Override
354    public void definition( SinkEventAttributes attributes )
355    {
356        currentSink.definition( attributes );
357    }
358
359    @Override
360    public void definitionList()
361    {
362        currentSink.definitionList();
363    }
364
365    @Override
366    public void definitionList( SinkEventAttributes attributes )
367    {
368        currentSink.definitionList( attributes );
369    }
370
371    @Override
372    public void definitionListItem()
373    {
374        currentSink.definitionListItem();
375    }
376
377    @Override
378    public void definitionListItem( SinkEventAttributes attributes )
379    {
380        currentSink.definitionListItem( attributes );
381    }
382
383    @Override
384    public void definitionListItem_()
385    {
386        currentSink.definitionListItem_();
387    }
388
389    @Override
390    public void definitionList_()
391    {
392        currentSink.definitionList_();
393    }
394
395    @Override
396    public void definition_()
397    {
398        currentSink.definition_();
399    }
400
401    @Override
402    public void division()
403    {
404        currentSink.division();
405    }
406
407    @Override
408    public void division( SinkEventAttributes attributes )
409    {
410        currentSink.division( attributes );
411    }
412
413    @Override
414    public void division_()
415    {
416        currentSink.division_();
417    }
418
419    @Override
420    public void figure()
421    {
422        currentSink.figure();
423    }
424
425    @Override
426    public void figure( SinkEventAttributes attributes )
427    {
428        currentSink.figure( attributes );
429    }
430
431    @Override
432    public void figureCaption()
433    {
434        currentSink.figureCaption();
435    }
436
437    @Override
438    public void figureCaption( SinkEventAttributes attributes )
439    {
440        currentSink.figureCaption( attributes );
441    }
442
443    @Override
444    public void figureCaption_()
445    {
446        currentSink.figureCaption_();
447    }
448
449    @Override
450    public void figureGraphics( String name )
451    {
452        currentSink.figureGraphics( name );
453    }
454
455    @Override
456    public void figureGraphics( String src, SinkEventAttributes attributes )
457    {
458        currentSink.figureGraphics( src, attributes );
459    }
460
461    @Override
462    public void figure_()
463    {
464        currentSink.figure_();
465    }
466
467    /**
468     * Flush all sinks
469     */
470    public void flush()
471    {
472        for ( int i = 0; i < sinks.size(); i++ )
473        {
474            // first flush to get complete buffer
475            // sink is responsible for flushing it's stream
476            Sink sink = sinks.get( i );
477            sink.flush();
478
479            ByteArrayOutputStream stream = outputStreams.get( i );
480            try
481            {
482                coreOutputStream.write( stream.toByteArray() );
483            }
484            catch ( IOException e )
485            {
486                // @todo
487            }
488        }
489        coreSink.flush();
490    }
491
492    @Override
493    public void footer()
494    {
495        currentSink.footer();
496    }
497
498    @Override
499    public void footer( SinkEventAttributes attributes )
500    {
501        currentSink.footer( attributes );
502    }
503
504    @Override
505    public void footer_()
506    {
507        currentSink.footer_();
508    }
509
510    @Override
511    public void head()
512    {
513        currentSink.head();
514    }
515
516    @Override
517    public void head( SinkEventAttributes attributes )
518    {
519        currentSink.head( attributes );
520    }
521
522    @Override
523    public void head_()
524    {
525        currentSink.head_();
526    }
527
528    @Override
529    public void header()
530    {
531        currentSink.header();
532    }
533
534    @Override
535    public void header( SinkEventAttributes attributes )
536    {
537        currentSink.header( attributes );
538    }
539
540    @Override
541    public void header_()
542    {
543        currentSink.header_();
544    }
545
546    @Override
547    public void horizontalRule()
548    {
549        currentSink.horizontalRule();
550    }
551
552    @Override
553    public void horizontalRule( SinkEventAttributes attributes )
554    {
555        currentSink.horizontalRule( attributes );
556    }
557
558    @Override
559    public void inline()
560    {
561        currentSink.inline();
562    }
563
564    @Override
565    public void inline( SinkEventAttributes attributes )
566    {
567        currentSink.inline( attributes );
568    }
569
570    @Override
571    public void inline_()
572    {
573        currentSink.inline_();
574    }
575
576    @Override
577    public void italic()
578    {
579        currentSink.italic();
580    }
581
582    @Override
583    public void italic_()
584    {
585        currentSink.italic_();
586    }
587
588    @Override
589    public void lineBreak()
590    {
591        currentSink.lineBreak();
592    }
593
594    @Override
595    public void lineBreak( SinkEventAttributes attributes )
596    {
597        currentSink.lineBreak( attributes );
598    }
599
600    @Override
601    public void lineBreakOpportunity()
602    {
603        currentSink.lineBreakOpportunity();
604    }
605
606    @Override
607    public void lineBreakOpportunity( SinkEventAttributes attributes )
608    {
609        currentSink.lineBreakOpportunity( attributes );
610    }
611
612    @Override
613    public void link( String name )
614    {
615        currentSink.link( name );
616    }
617
618    @Override
619    public void link( String name, SinkEventAttributes attributes )
620    {
621        currentSink.link( name, attributes );
622    }
623
624    @Override
625    public void link_()
626    {
627        currentSink.link_();
628    }
629
630    @Override
631    public void list()
632    {
633        currentSink.list();
634    }
635
636    @Override
637    public void list( SinkEventAttributes attributes )
638    {
639        currentSink.list( attributes );
640    }
641
642    @Override
643    public void listItem()
644    {
645        currentSink.listItem();
646    }
647
648    @Override
649    public void listItem( SinkEventAttributes attributes )
650    {
651        currentSink.listItem( attributes );
652    }
653
654    @Override
655    public void listItem_()
656    {
657        currentSink.listItem_();
658    }
659
660    @Override
661    public void list_()
662    {
663        currentSink.list_();
664    }
665
666    @Override
667    public void monospaced()
668    {
669        currentSink.monospaced();
670    }
671
672    @Override
673    public void monospaced_()
674    {
675        currentSink.monospaced_();
676    }
677
678    @Override
679    public void navigation()
680    {
681        currentSink.navigation();
682    }
683
684    @Override
685    public void navigation( SinkEventAttributes attributes )
686    {
687        currentSink.navigation( attributes );
688    }
689
690    @Override
691    public void navigation_()
692    {
693        currentSink.navigation_();
694    }
695
696    @Override
697    public void nonBreakingSpace()
698    {
699        currentSink.nonBreakingSpace();
700    }
701
702    @Override
703    public void numberedList( int numbering )
704    {
705        currentSink.numberedList( numbering );
706    }
707
708    @Override
709    public void numberedList( int numbering, SinkEventAttributes attributes )
710    {
711        currentSink.numberedList( numbering, attributes );
712    }
713
714    @Override
715    public void numberedListItem()
716    {
717        currentSink.numberedListItem();
718    }
719
720    @Override
721    public void numberedListItem( SinkEventAttributes attributes )
722    {
723        currentSink.numberedListItem( attributes );
724    }
725
726    @Override
727    public void numberedListItem_()
728    {
729        currentSink.numberedListItem_();
730    }
731
732    @Override
733    public void numberedList_()
734    {
735        currentSink.numberedList_();
736    }
737
738    @Override
739    public void pageBreak()
740    {
741        currentSink.pageBreak();
742    }
743
744    @Override
745    public void paragraph()
746    {
747        currentSink.paragraph();
748    }
749
750    @Override
751    public void paragraph( SinkEventAttributes attributes )
752    {
753        currentSink.paragraph( attributes );
754    }
755
756    @Override
757    public void paragraph_()
758    {
759        currentSink.paragraph_();
760    }
761
762    @Override
763    public void rawText( String text )
764    {
765        currentSink.rawText( text );
766    }
767
768    @Override
769    public void section( int level, SinkEventAttributes attributes )
770    {
771        currentSink.section( level, attributes );
772    }
773
774    @Override
775    public void section1()
776    {
777        currentSink.section1();
778    }
779
780    @Override
781    public void section1_()
782    {
783        currentSink.section1_();
784    }
785
786    @Override
787    public void section2()
788    {
789        currentSink.section2();
790    }
791
792    @Override
793    public void section2_()
794    {
795        currentSink.section2_();
796    }
797
798    @Override
799    public void section3()
800    {
801        currentSink.section3();
802    }
803
804    @Override
805    public void section3_()
806    {
807        currentSink.section3_();
808    }
809
810    @Override
811    public void section4()
812    {
813        currentSink.section4();
814    }
815
816    @Override
817    public void section4_()
818    {
819        currentSink.section4_();
820    }
821
822    @Override
823    public void section5()
824    {
825        currentSink.section5();
826    }
827
828    @Override
829    public void section5_()
830    {
831        currentSink.section5_();
832    }
833
834    @Override
835    public void section6()
836    {
837        currentSink.section5();
838    }
839
840    @Override
841    public void section6_()
842    {
843        currentSink.section5_();
844    }
845
846    @Override
847    public void sectionTitle()
848    {
849        currentSink.sectionTitle();
850    }
851
852    @Override
853    public void sectionTitle( int level, SinkEventAttributes attributes )
854    {
855        currentSink.sectionTitle( level, attributes );
856    }
857
858    @Override
859    public void sectionTitle1()
860    {
861        currentSink.sectionTitle1();
862    }
863
864    @Override
865    public void sectionTitle1_()
866    {
867        currentSink.sectionTitle1_();
868    }
869
870    @Override
871    public void sectionTitle2()
872    {
873        currentSink.sectionTitle2();
874    }
875
876    @Override
877    public void sectionTitle2_()
878    {
879        currentSink.sectionTitle2_();
880    }
881
882    @Override
883    public void sectionTitle3()
884    {
885        currentSink.sectionTitle3();
886    }
887
888    @Override
889    public void sectionTitle3_()
890    {
891        currentSink.sectionTitle3_();
892    }
893
894    @Override
895    public void sectionTitle4()
896    {
897        currentSink.sectionTitle4();
898    }
899
900    @Override
901    public void sectionTitle4_()
902    {
903        currentSink.sectionTitle4_();
904    }
905
906    @Override
907    public void sectionTitle5()
908    {
909        currentSink.sectionTitle5();
910    }
911
912    @Override
913    public void sectionTitle5_()
914    {
915        currentSink.sectionTitle5_();
916    }
917
918    @Override
919    public void sectionTitle6()
920    {
921        currentSink.sectionTitle5();
922    }
923
924    @Override
925    public void sectionTitle6_()
926    {
927        currentSink.sectionTitle5_();
928    }
929
930    @Override
931    public void sectionTitle_()
932    {
933        currentSink.sectionTitle_();
934    }
935
936    @Override
937    public void sectionTitle_( int level )
938    {
939        currentSink.sectionTitle_( level );
940    }
941
942    @Override
943    public void section_( int level )
944    {
945        currentSink.section_( level );
946    }
947
948    @Override
949    public void sidebar()
950    {
951        currentSink.sidebar();
952    }
953
954    @Override
955    public void sidebar( SinkEventAttributes attributes )
956    {
957        currentSink.sidebar( attributes );
958    }
959
960    @Override
961    public void sidebar_()
962    {
963        currentSink.sidebar_();
964    }
965
966    @Override
967    public void table()
968    {
969        currentSink.table();
970    }
971
972    @Override
973    public void table( SinkEventAttributes attributes )
974    {
975        currentSink.table( attributes );
976    }
977
978    @Override
979    public void tableCaption()
980    {
981        currentSink.tableCaption();
982    }
983
984    @Override
985    public void tableCaption( SinkEventAttributes attributes )
986    {
987        currentSink.tableCaption( attributes );
988    }
989
990    @Override
991    public void tableCaption_()
992    {
993        currentSink.tableCaption_();
994    }
995
996    @Override
997    public void tableCell()
998    {
999        currentSink.tableCell();
1000    }
1001
1002    @Override
1003    public void tableCell( String width )
1004    {
1005        currentSink.tableCell( width );
1006    }
1007
1008    @Override
1009    public void tableCell( SinkEventAttributes attributes )
1010    {
1011        currentSink.tableCell( attributes );
1012    }
1013
1014    @Override
1015    public void tableCell_()
1016    {
1017        currentSink.tableCell_();
1018    }
1019
1020    @Override
1021    public void tableHeaderCell()
1022    {
1023        currentSink.tableHeaderCell();
1024    }
1025
1026    @Override
1027    public void tableHeaderCell( String width )
1028    {
1029        currentSink.tableHeaderCell( width );
1030    }
1031
1032    @Override
1033    public void tableHeaderCell( SinkEventAttributes attributes )
1034    {
1035        currentSink.tableHeaderCell( attributes );
1036    }
1037
1038    @Override
1039    public void tableHeaderCell_()
1040    {
1041        currentSink.tableHeaderCell_();
1042    }
1043
1044    @Override
1045    public void tableRow()
1046    {
1047        currentSink.tableRow();
1048    }
1049
1050    @Override
1051    public void tableRow( SinkEventAttributes attributes )
1052    {
1053        currentSink.tableRow( attributes );
1054    }
1055
1056    @Override
1057    public void tableRow_()
1058    {
1059        currentSink.tableRow_();
1060    }
1061
1062    @Override
1063    public void tableRows( int[] justification, boolean grid )
1064    {
1065        currentSink.tableRows( justification, grid );
1066    }
1067
1068    @Override
1069    public void tableRows_()
1070    {
1071        currentSink.tableRows_();
1072    }
1073
1074    @Override
1075    public void table_()
1076    {
1077        currentSink.table_();
1078    }
1079
1080    @Override
1081    public void text( String text )
1082    {
1083        currentSink.text( text );
1084    }
1085
1086    @Override
1087    public void text( String text, SinkEventAttributes attributes )
1088    {
1089        currentSink.text( text, attributes );
1090    }
1091
1092    @Override
1093    public void time( String datetime )
1094    {
1095        currentSink.time( datetime );
1096    }
1097
1098    @Override
1099    public void time( String datetime, SinkEventAttributes attributes )
1100    {
1101        currentSink.time( datetime, attributes );
1102    }
1103
1104    @Override
1105    public void time_()
1106    {
1107        currentSink.time_();
1108    }
1109
1110    @Override
1111    public void title()
1112    {
1113        currentSink.title();
1114    }
1115
1116    @Override
1117    public void title( SinkEventAttributes attributes )
1118    {
1119        currentSink.title( attributes );
1120    }
1121
1122    @Override
1123    public void title_()
1124    {
1125        currentSink.title_();
1126    }
1127
1128    @Override
1129    public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes )
1130    {
1131        currentSink.unknown( name, requiredParams, attributes );
1132    }
1133
1134    @Override
1135    public void verbatim( boolean boxed )
1136    {
1137        currentSink.verbatim( boxed );
1138    }
1139
1140    @Override
1141    public void verbatim( SinkEventAttributes attributes )
1142    {
1143        currentSink.verbatim( attributes );
1144    }
1145
1146    @Override
1147    public void verbatim_()
1148    {
1149        currentSink.verbatim_();
1150    }
1151
1152    @Override
1153    public void enableLogging( Log log )
1154    {
1155        currentSink.enableLogging( log );
1156    }
1157}