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<Sink>();
056
057    private List<ByteArrayOutputStream> outputStreams = new ArrayList<ByteArrayOutputStream>();
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    /**
100     * By calling this method a sink reference is added at the current position. You can write to both the new sink
101     * reference and the original sink. After flushing all sinks will be flushed in the right order.
102     * 
103     * @return a subsink reference you can write to
104     */
105    public Sink addSinkHook()
106    {
107        Sink subSink = null;
108        try
109        {
110            ByteArrayOutputStream subOut = new ByteArrayOutputStream();
111            ByteArrayOutputStream newOut = new ByteArrayOutputStream();
112
113            outputStreams.add( subOut );
114            outputStreams.add( newOut );
115
116            if ( encoding != null )
117            {
118                subSink = sinkFactory.createSink( subOut, encoding );
119                currentSink = sinkFactory.createSink( newOut, encoding );
120            }
121            else
122            {
123                subSink = sinkFactory.createSink( subOut );
124                currentSink = sinkFactory.createSink( newOut );
125            }
126            sinks.add( subSink );
127            sinks.add( currentSink );
128        }
129        catch ( IOException e )
130        {
131            // IOException can only be caused by our own ByteArrayOutputStream
132        }
133        return subSink;
134    }
135
136    @Override
137    public void anchor( String name )
138    {
139        currentSink.anchor( name );
140    }
141
142    @Override
143    public void anchor( String name, SinkEventAttributes attributes )
144    {
145        currentSink.anchor( name, attributes );
146    }
147
148    @Override
149    public void anchor_()
150    {
151        currentSink.anchor_();
152    }
153
154    @Override
155    public void author()
156    {
157        currentSink.author();
158    }
159
160    @Override
161    public void author( SinkEventAttributes attributes )
162    {
163        currentSink.author( attributes );
164    }
165
166    @Override
167    public void author_()
168    {
169        currentSink.author_();
170    }
171
172    @Override
173    public void body()
174    {
175        currentSink.body();
176    }
177
178    @Override
179    public void body( SinkEventAttributes attributes )
180    {
181        currentSink.body( attributes );
182    }
183
184    @Override
185    public void body_()
186    {
187        currentSink.body_();
188    }
189
190    @Override
191    public void bold()
192    {
193        currentSink.bold();
194    }
195
196    @Override
197    public void bold_()
198    {
199        currentSink.bold_();
200    }
201
202    /**
203     * Close all sinks
204     */
205    public void close()
206    {
207        for ( Sink sink  : sinks )
208        {
209            // sink is responsible for closing it's stream
210            sink.close();
211        }
212        coreSink.close();
213    }
214
215    @Override
216    public void comment( String comment )
217    {
218        currentSink.comment( comment );
219    }
220
221    @Override
222    public void date()
223    {
224        currentSink.date();
225    }
226
227    @Override
228    public void date( SinkEventAttributes attributes )
229    {
230        currentSink.date( attributes );
231    }
232
233    @Override
234    public void date_()
235    {
236        currentSink.date_();
237    }
238
239    @Override
240    public void definedTerm()
241    {
242        currentSink.definedTerm();
243    }
244
245    @Override
246    public void definedTerm( SinkEventAttributes attributes )
247    {
248        currentSink.definedTerm( attributes );
249    }
250
251    @Override
252    public void definedTerm_()
253    {
254        currentSink.definedTerm_();
255    }
256
257    @Override
258    public void definition()
259    {
260        currentSink.definition();
261    }
262
263    @Override
264    public void definition( SinkEventAttributes attributes )
265    {
266        currentSink.definition( attributes );
267    }
268
269    @Override
270    public void definitionList()
271    {
272        currentSink.definitionList();
273    }
274
275    @Override
276    public void definitionList( SinkEventAttributes attributes )
277    {
278        currentSink.definitionList( attributes );
279    }
280
281    @Override
282    public void definitionListItem()
283    {
284        currentSink.definitionListItem();
285    }
286
287    @Override
288    public void definitionListItem( SinkEventAttributes attributes )
289    {
290        currentSink.definitionListItem( attributes );
291    }
292
293    @Override
294    public void definitionListItem_()
295    {
296        currentSink.definitionListItem_();
297    }
298
299    @Override
300    public void definitionList_()
301    {
302        currentSink.definitionList_();
303    }
304
305    @Override
306    public void definition_()
307    {
308        currentSink.definition_();
309    }
310
311    @Override
312    public void figure()
313    {
314        currentSink.figure();
315    }
316
317    @Override
318    public void figure( SinkEventAttributes attributes )
319    {
320        currentSink.figure( attributes );
321    }
322
323    @Override
324    public void figureCaption()
325    {
326        currentSink.figureCaption();
327    }
328
329    @Override
330    public void figureCaption( SinkEventAttributes attributes )
331    {
332        currentSink.figureCaption( attributes );
333    }
334
335    @Override
336    public void figureCaption_()
337    {
338        currentSink.figureCaption_();
339    }
340
341    @Override
342    public void figureGraphics( String name )
343    {
344        currentSink.figureGraphics( name );
345    }
346
347    @Override
348    public void figureGraphics( String src, SinkEventAttributes attributes )
349    {
350        currentSink.figureGraphics( src, attributes );
351    }
352
353    @Override
354    public void figure_()
355    {
356        currentSink.figure_();
357    }
358
359    /**
360     * Flush all sinks
361     */
362    public void flush()
363    {
364        for ( int i = 0; i < sinks.size(); i++ )
365        {
366            // first flush to get complete buffer
367            // sink is responsible for flushing it's stream
368            Sink sink = sinks.get( i );
369            sink.flush();
370
371            ByteArrayOutputStream stream = outputStreams.get( i );
372            try
373            {
374                coreOutputStream.write( stream.toByteArray() );
375            }
376            catch ( IOException e )
377            {
378                // @todo
379            }
380        }
381        coreSink.flush();
382    }
383
384    @Override
385    public void head()
386    {
387        currentSink.head();
388    }
389
390    @Override
391    public void head( SinkEventAttributes attributes )
392    {
393        currentSink.head( attributes );
394    }
395
396    @Override
397    public void head_()
398    {
399        currentSink.head_();
400    }
401
402    @Override
403    public void horizontalRule()
404    {
405        currentSink.horizontalRule();
406    }
407
408    @Override
409    public void horizontalRule( SinkEventAttributes attributes )
410    {
411        currentSink.horizontalRule( attributes );
412    }
413
414    @Override
415    public void italic()
416    {
417        currentSink.italic();
418    }
419
420    @Override
421    public void italic_()
422    {
423        currentSink.italic_();
424    }
425
426    @Override
427    public void lineBreak()
428    {
429        currentSink.lineBreak();
430    }
431
432    @Override
433    public void lineBreak( SinkEventAttributes attributes )
434    {
435        currentSink.lineBreak( attributes );
436    }
437
438    @Override
439    public void link( String name )
440    {
441        currentSink.link( name );
442    }
443
444    @Override
445    public void link( String name, SinkEventAttributes attributes )
446    {
447        currentSink.link( name, attributes );
448    }
449
450    @Override
451    public void link_()
452    {
453        currentSink.link_();
454    }
455
456    @Override
457    public void list()
458    {
459        currentSink.list();
460    }
461
462    @Override
463    public void list( SinkEventAttributes attributes )
464    {
465        currentSink.list( attributes );
466    }
467
468    @Override
469    public void listItem()
470    {
471        currentSink.listItem();
472    }
473
474    @Override
475    public void listItem( SinkEventAttributes attributes )
476    {
477        currentSink.listItem( attributes );
478    }
479
480    @Override
481    public void listItem_()
482    {
483        currentSink.listItem_();
484    }
485
486    @Override
487    public void list_()
488    {
489        currentSink.list_();
490    }
491
492    @Override
493    public void monospaced()
494    {
495        currentSink.monospaced();
496    }
497
498    @Override
499    public void monospaced_()
500    {
501        currentSink.monospaced_();
502    }
503
504    @Override
505    public void nonBreakingSpace()
506    {
507        currentSink.nonBreakingSpace();
508    }
509
510    @Override
511    public void numberedList( int numbering )
512    {
513        currentSink.numberedList( numbering );
514    }
515
516    @Override
517    public void numberedList( int numbering, SinkEventAttributes attributes )
518    {
519        currentSink.numberedList( numbering, attributes );
520    }
521
522    @Override
523    public void numberedListItem()
524    {
525        currentSink.numberedListItem();
526    }
527
528    @Override
529    public void numberedListItem( SinkEventAttributes attributes )
530    {
531        currentSink.numberedListItem( attributes );
532    }
533
534    @Override
535    public void numberedListItem_()
536    {
537        currentSink.numberedListItem_();
538    }
539
540    @Override
541    public void numberedList_()
542    {
543        currentSink.numberedList_();
544    }
545
546    @Override
547    public void pageBreak()
548    {
549        currentSink.pageBreak();
550    }
551
552    @Override
553    public void paragraph()
554    {
555        currentSink.paragraph();
556    }
557
558    @Override
559    public void paragraph( SinkEventAttributes attributes )
560    {
561        currentSink.paragraph( attributes );
562    }
563
564    @Override
565    public void paragraph_()
566    {
567        currentSink.paragraph_();
568    }
569
570    @Override
571    public void rawText( String text )
572    {
573        currentSink.rawText( text );
574    }
575
576    @Override
577    public void section( int level, SinkEventAttributes attributes )
578    {
579        currentSink.section( level, attributes );
580    }
581
582    @Override
583    public void section1()
584    {
585        currentSink.section1();
586    }
587
588    @Override
589    public void section1_()
590    {
591        currentSink.section1_();
592    }
593
594    @Override
595    public void section2()
596    {
597        currentSink.section2();
598    }
599
600    @Override
601    public void section2_()
602    {
603        currentSink.section2_();
604    }
605
606    @Override
607    public void section3()
608    {
609        currentSink.section3();
610    }
611
612    @Override
613    public void section3_()
614    {
615        currentSink.section3_();
616    }
617
618    @Override
619    public void section4()
620    {
621        currentSink.section4();
622    }
623
624    @Override
625    public void section4_()
626    {
627        currentSink.section4_();
628    }
629
630    @Override
631    public void section5()
632    {
633        currentSink.section5();
634    }
635
636    @Override
637    public void section5_()
638    {
639        currentSink.section5_();
640    }
641
642    @Override
643    public void section6()
644    {
645        currentSink.section5();
646    }
647
648    @Override
649    public void section6_()
650    {
651        currentSink.section5_();
652    }
653
654    @Override
655    public void sectionTitle()
656    {
657        currentSink.sectionTitle();
658    }
659
660    @Override
661    public void sectionTitle( int level, SinkEventAttributes attributes )
662    {
663        currentSink.sectionTitle( level, attributes );
664    }
665
666    @Override
667    public void sectionTitle1()
668    {
669        currentSink.sectionTitle1();
670    }
671
672    @Override
673    public void sectionTitle1_()
674    {
675        currentSink.sectionTitle1_();
676    }
677
678    @Override
679    public void sectionTitle2()
680    {
681        currentSink.sectionTitle2();
682    }
683
684    @Override
685    public void sectionTitle2_()
686    {
687        currentSink.sectionTitle2_();
688    }
689
690    @Override
691    public void sectionTitle3()
692    {
693        currentSink.sectionTitle3();
694    }
695
696    @Override
697    public void sectionTitle3_()
698    {
699        currentSink.sectionTitle3_();
700    }
701
702    @Override
703    public void sectionTitle4()
704    {
705        currentSink.sectionTitle4();
706    }
707
708    @Override
709    public void sectionTitle4_()
710    {
711        currentSink.sectionTitle4_();
712    }
713
714    @Override
715    public void sectionTitle5()
716    {
717        currentSink.sectionTitle5();
718    }
719
720    @Override
721    public void sectionTitle5_()
722    {
723        currentSink.sectionTitle5_();
724    }
725
726    @Override
727    public void sectionTitle6()
728    {
729        currentSink.sectionTitle5();
730    }
731
732    @Override
733    public void sectionTitle6_()
734    {
735        currentSink.sectionTitle5_();
736    }
737
738    @Override
739    public void sectionTitle_()
740    {
741        currentSink.sectionTitle_();
742    }
743
744    @Override
745    public void sectionTitle_( int level )
746    {
747        currentSink.sectionTitle_( level );
748    }
749
750    @Override
751    public void section_( int level )
752    {
753        currentSink.section_( level );
754    }
755
756    @Override
757    public void table()
758    {
759        currentSink.table();
760    }
761
762    @Override
763    public void table( SinkEventAttributes attributes )
764    {
765        currentSink.table( attributes );
766    }
767
768    @Override
769    public void tableCaption()
770    {
771        currentSink.tableCaption();
772    }
773
774    @Override
775    public void tableCaption( SinkEventAttributes attributes )
776    {
777        currentSink.tableCaption( attributes );
778    }
779
780    @Override
781    public void tableCaption_()
782    {
783        currentSink.tableCaption_();
784    }
785
786    @Override
787    public void tableCell()
788    {
789        currentSink.tableCell();
790    }
791
792    @Override
793    public void tableCell( String width )
794    {
795        currentSink.tableCell( width );
796    }
797
798    @Override
799    public void tableCell( SinkEventAttributes attributes )
800    {
801        currentSink.tableCell( attributes );
802    }
803
804    @Override
805    public void tableCell_()
806    {
807        currentSink.tableCell_();
808    }
809
810    @Override
811    public void tableHeaderCell()
812    {
813        currentSink.tableHeaderCell();
814    }
815
816    @Override
817    public void tableHeaderCell( String width )
818    {
819        currentSink.tableHeaderCell( width );
820    }
821
822    @Override
823    public void tableHeaderCell( SinkEventAttributes attributes )
824    {
825        currentSink.tableHeaderCell( attributes );
826    }
827
828    @Override
829    public void tableHeaderCell_()
830    {
831        currentSink.tableHeaderCell_();
832    }
833
834    @Override
835    public void tableRow()
836    {
837        currentSink.tableRow();
838    }
839
840    @Override
841    public void tableRow( SinkEventAttributes attributes )
842    {
843        currentSink.tableRow( attributes );
844    }
845
846    @Override
847    public void tableRow_()
848    {
849        currentSink.tableRow_();
850    }
851
852    @Override
853    public void tableRows( int[] justification, boolean grid )
854    {
855        currentSink.tableRows( justification, grid );
856    }
857
858    @Override
859    public void tableRows_()
860    {
861        currentSink.tableRows_();
862    }
863
864    @Override
865    public void table_()
866    {
867        currentSink.table_();
868    }
869
870    @Override
871    public void text( String text )
872    {
873        currentSink.text( text );
874    }
875
876    @Override
877    public void text( String text, SinkEventAttributes attributes )
878    {
879        currentSink.text( text, attributes );
880    }
881
882    @Override
883    public void title()
884    {
885        currentSink.title();
886    }
887
888    @Override
889    public void title( SinkEventAttributes attributes )
890    {
891        currentSink.title( attributes );
892    }
893
894    @Override
895    public void title_()
896    {
897        currentSink.title_();
898    }
899
900    @Override
901    public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes )
902    {
903        currentSink.unknown( name, requiredParams, attributes );
904    }
905
906    @Override
907    public void verbatim( boolean boxed )
908    {
909        currentSink.verbatim( boxed );
910    }
911
912    @Override
913    public void verbatim( SinkEventAttributes attributes )
914    {
915        currentSink.verbatim( attributes );
916    }
917
918    @Override
919    public void verbatim_()
920    {
921        currentSink.verbatim_();
922    }
923
924    @Override
925    public void enableLogging( Log log )
926    {
927        currentSink.enableLogging( log );
928    }
929}