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