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}